Go Fish
Write a program to let the user play Go Fish against a computer opponent. Use the following rules:
- Each player is dealt nine cards to start with.
- On their turn, a player asks their opponent for a given rank (such as threes or kings). A player must already have at least one card of a given rank to ask for more.
- If the opponent has any cards of the named rank, they must hand over all such cards, and the requester can ask again.
- If the opponent has no cards of the named rank, the requester draws a card and ends their turn.
- A book is a collection of every card of a given rank. Whenever a player completes a book, they may remove it from their hand.
- If at any time a player's hand is empty, they may immediately draw a new card, so long as any new cards remain in the deck.
- The game ends when every book is complete. The player with the most books wins.

You are encouraged to solve this task according to the task description, using any language you may know.
The game's AI need not be terribly smart, but it should use at least some strategy. That is, it shouldn't choose legal moves entirely at random.
You may want to use code from Playing Cards.
Related tasks:
Aime
See Go Fish/Aime
AutoHotkey
C
See Go Fish/C
C++
See Go Fish/C++
D
See Go Fish/D
Erlang
See Go Fish/Erlang
FreeBASIC
' Go Fish ~ ¡Pesca!
Const cartas = "A234567890JQK"
Declare Sub Reparto_Cartas
Declare Sub Pescar_Carta_Jug
Declare Sub Pescar_Carta_CPU
Declare Sub Comprobar_Libro_Jug
Declare Sub Comprobar_Libro_CPU
Declare Sub Comprobar_Fin_Partida
Declare Sub Intro
Dim Shared As Integer play(13), compu(13), deck(13), guess(13), poss(13), asked(13)
Dim Shared As String nombre, Snombre, CartaPedida
Dim Shared puntos(2) As Byte = {0,0}
Dim Shared As Integer remca = 4*Len(cartas)
Dim Shared As Integer i, k, j, cn
For i = 1 To 13
deck(i) = 4
Next i
For i = 1 To 9
Reparto_Cartas
deck(k) -= 1
compu(k) += 1
Reparto_Cartas
deck(k) -= 1
play(k) += 1
Next i
Dim As Integer v, po
Sub Reparto_Cartas
remca -= 1
Dim As Integer sc = remca * Rnd + 1
For k = 1 To 13
sc -= deck(k)
If sc <= 0 Then Return
Next k
End Sub
Sub Pescar_Carta_Jug
Reparto_Cartas
Print " " &Mid(cartas,k,1) &"."
deck(k) -= 1
play(k) += 1
End Sub
Sub Pescar_Carta_CPU
Reparto_Cartas
Print "a carta."
deck(k) -= 1
compu(k) += 1
End Sub
Sub Comprobar_Libro_Jug
For i = 1 To 13
If play(i) <> 4 Then
Else
Color 11: Print Snombre &" completa el libro de " &Mid(cartas,i,1) &"'s.": Color 7
play(i) = 0
puntos(0) += 1
End If
Next i
End Sub
Sub Comprobar_Libro_CPU
For i = 1 To 13
If compu(i) <> 4 Then
Else
Color 11: Print Snombre &" completa el libro de " &Mid(cartas,i,1) &"'s.": Color 7
compu(i) = 0
puntos(1) += 1
End If
Next i
End Sub
Sub Comprobar_Fin_Partida
Dim As Integer np = 0, nc = 0
For i = 1 To 13
np += play(i)
nc += compu(i)
Next i
If remca = 0 Or np = 0 Or nc = 0 Then
Color 15: Print
Print "*** FIN de la partida! ***"
Print
If puntos(0) < puntos(1) Then
Print "La CPU ha ganado."
Elseif puntos(0) > puntos(1) Then
Print nombre &" ha ganado."
Else
Print "Es un empate!"
End If
Sleep: End
End If
End Sub
Sub Intro
Color 15
Print " __ _ _ "
Print " __ _ ___ / _(_)___| |__ "
Print " / ` |/ _ \ | |_| / __| '_ \ "
Print "| (_) | (_) | | _| \__ \ | | | "
Print " \__, |\___/ |_| |_|___/_| |_| "
Print " |___/ "
Print " "
Color 14: Locate 10, 2: Input "Como te llamas: ", nombre
End Sub
'--- Programa Principal ---
Cls
Randomize Timer
Intro
Do
Dim As boolean MuestraMano = false
While MuestraMano = false
Color 15: Print Chr(10) &"Puntos >> " &nombre &": "; puntos(0); " CPU: "; puntos(1)
Color 13: Print Chr(10) &space(10) &remca &" cartas restantes"
Color 14: Print Chr(10) &"Tu mano: ";
For i = 1 To 13
If Not play(i) Then
For j = 1 To play(i)
Print Mid(cartas,i,1); " ";
Next j
End If
Next i
Print
Dim As boolean PideCarta = false
While PideCarta = false
Comprobar_Fin_Partida
Snombre = nombre
Color 7: Print
Input "¨Que carta pides... "; CartaPedida
Print
If CartaPedida <> "" Then cn = Instr(cartas, Ucase(CartaPedida)): PideCarta = true
If cn = 0 Then
Print "Lo siento, no es una opción valida.": PideCarta = false
Elseif play(cn) = 0 Then Color 12: Print "No tienes esa carta!": Color 7: PideCarta = false
End If
Wend
guess(cn) = 1
If compu(cn) = 0 Then
Print Snombre &", ";
Color 15: Print "ve a pescar!"
Color 7: Print Snombre &" pesca un";: Pescar_Carta_Jug
Comprobar_Libro_Jug
MuestraMano = true
Else
v = compu(cn)
compu(cn) = 0
play(cn) += v
Print Snombre &" consigue " &v &" carta(s) mas."
Comprobar_Libro_Jug
MuestraMano = false
End If
Wend
Snombre = "CPU"
For i = 1 To 13
asked(i) = 0
Next i
Dim As boolean Turno_CPU_2 = false
While Turno_CPU_2 = false
Comprobar_Fin_Partida
po = 0
For i = 1 To 13
If (compu(i) > 0) And (guess(i) > 0) Then poss(i) = 1: po += 1
Next i
If po = 0 Then
Do
k = (Rnd*12)+1
Loop While compu(k) = 0 Or asked(k)
Else
Do
k = (Rnd*12)+1
Loop While poss(k) = 0
guess(k) = 0
asked(k) = 1
End If
Print: Print Snombre &" quiere tus " &Mid(cartas,k,1) &"'s."
asked(k) = 1
If play(k) = 0 Then
Print Snombre &", ";
Color 15: Print "ve a pescar!"
Color 7:Print Snombre &" pesca un";: Pescar_Carta_CPU
Comprobar_Libro_CPU
Turno_CPU_2 = true
Else
v = play(k)
play(k) = 0
compu(k) += v
Print Snombre &" consigue " &v &" carta(s) mas."
Comprobar_Libro_CPU
Turno_CPU_2 = false
End If
Wend
Loop
End
FutureBasic
May 5, 2024
May 22 Minor update replaces || with or in the instructions.
/*
Go Fish
-- Rich Love --
FutureBasic app For Macintosh
Get the latest FutureBasic here
http://www.brilorsoftware.com/fb/pages/home.html
*/
_window = 1
begin enum 1
_scrollView
_textView
end enum
override _forLoopsAlwaysExecuteAtLeastOnce = _true
begin globals
str255 cards
cards = "A234567890JQK"
short play(13), Computer(13), deck(13), guess(13), poss(13), asked(13)
str255 YourName, Someone
//bool gNeedToClearScreen
short Points(2) : Points(0) = 0 : Points(1) = 0
short i, k, j, CardNumber
short RemainingCards
end globals
local fn CheckForFaceCard(TheCard as short) as str255
str255 WantsCard
WantsCard = str$(TheCard)
if TheCard = 0 then WantsCard = "10"
if TheCard = 11 then WantsCard = "jack"
if TheCard = 12 then WantsCard = "Queen"
if TheCard = 13 then WantsCard = "King"
if TheCard = 1 then WantsCard = "Ace"
end fn = WantsCard
void local fn PrintViewScrollToBottom( printView as ViewRef )
BeginCCode
NSScrollView *scrollView = [printView enclosingScrollView];
NSClipView *clipView = [scrollView contentView];
[clipView scrollToPoint:NSMakePoint(0,printView.frame.size.height-scrollView.contentSize.height + 20)];
[scrollView reflectScrolledClipView:clipView];
EndC
end fn
void local fn DealCards
RemainingCards -= 1
short sc
sc = rnd(RemainingCards) + 1 // 5/2/24 Rich added + 1
For k = 1 To 13
sc -= deck(k)
If sc <= 0 Then exit fn
Next k
End fn
void local fn youGoFishing
fn DealCards
str255 WantsCard
WantsCard = fn CheckForFaceCard(k)
if WantsCard = "0" then WantsCard = "10"
Print " " + WantsCard + "."
deck(k) -= 1
play(k) += 1
End fn
void local fn cpuGoFishing
fn DealCards
Print " a card from the deck."
if k > 13 then k = 13
deck(k) -= 1
Computer(k) += 1
End fn
void local fn CheckForCompletedBook
For i = 1 To 13
If play(i) <> 4
Else
text ,,fn colorcyan
str255 WantsCard
WantsCard = Mid$(cards,i,1)
if WantsCard = "j" || WantsCard = "J" then WantsCard = "Jack"
if WantsCard = "q" || WantsCard = "Q" then WantsCard = "Queen"
if WantsCard = "k" || WantsCard = "K" then WantsCard = "King"
if WantsCard = "a" || WantsCard = "A" then WantsCard = "Ace"
if WantsCard = "0" then WantsCard = "10"
Print YourName + " completed the book of " + WantsCard + "'s."
text ,,fn colorWhite
play(i) = 0
Points(0) += 1
fn PrintViewScrollToBottom( fn WindowPrintView(1))
End If
Next i
End fn
local fn CheckCPUForCompletedBook
For i = 1 To 13
If Computer(i) <> 4
Else
text ,,fn colorCyan
str255 WantsCard
WantsCard = Mid$(cards,i,1)
if WantsCard = "j" || WantsCard = "J" then WantsCard = "Jack"
if WantsCard = "q" || WantsCard = "Q" then WantsCard = "Queen"
if WantsCard = "k" || WantsCard = "K" then WantsCard = "King"
if WantsCard = "a" || WantsCard = "A" then WantsCard = "Ace"
if WantsCard = "0" then WantsCard = "10"
Print "CPU completed the book of " + WantsCard + "'s."
text ,,fn colorWhite
Computer(i) = 0
Points(1) += 1
fn PrintViewScrollToBottom( fn WindowPrintView(1))
End If
Next i
End fn
local fn InitCards
cards = "A234567890JQK"
RemainingCards = 4 * len$(cards) // the length of cards is 13. There are 4 suits of cards. so RemainingCards is 52
i = 0:k = 0:j = 0:CardNumber = 0
For i = 0 to 1
Points(i) = 0
next i
For i = 1 TO 13 // Reset each element to 0
play(i) = 0
Computer(i) = 0
deck(i) = 0
guess(i) = 0
poss(i) = 0
asked(i) = 0
NEXT i
For i = 1 To 13
deck(i) = 4
Next i
For i = 1 To 9
fn DealCards
deck(k) -= 1
Computer(k) += 1
fn DealCards
deck(k) -= 1
play(k) += 1
Next i
fn CheckForCompletedBook // Rich added 5/1/24
fn CheckCPUForCompletedBook // Rich added 5/5/24
end fn
local fn QuitOrPlayAlert(GameResult as CFStringRef)
alert -2,,GameResult,@"Game Over",@"Quit;Play Again"
AlertButtonSetKeyEquivalent( 2, 2, @"\e" )
short result
result = alert 2
if ( result != NSAlertSecondButtonReturn ) then end
end fn
local fn QuitOrResumeAlert(GameResult as CFStringRef)
alert -3,,GameResult,@"Quit the game?",@"Quit;Resume game"
AlertButtonSetKeyEquivalent( 3, 2, @"\e" )
short result
result = alert 3
if ( result != NSAlertSecondButtonReturn ) then end
end fn
local fn CheckForEndGame as boolean
bool PlayAgain = _False
short np = 0, nc = 0
For i = 1 To 13
np += play(i)
nc += Computer(i)
Next i
If RemainingCards = 0 || np = 0 || nc = 0
text ,,fn colorRed
Print "*** Game Over! ***"
Print
If Points(0) < Points(1)
Print "The CPU has won."
print:print
fn QuitOrPlayAlert(@"the CPU won!")
PlayAgain = _True
Else if Points(0) > Points(1)
Print YourName + " has won."
print:print
fn QuitOrPlayAlert(@"You Won!")
PlayAgain = _True
Else
Print "It's a tie!"
fn QuitOrPlayAlert(@"It's a tie!.")
PlayAgain = _True
End If
fn PrintViewScrollToBottom( fn WindowPrintView(1) )
End If
PlayAgain = _True
End If
End fn = PlayAgain
void local fn Intro
text ,,fn colorGreen
Print " __ _ _ "
Print " __ _ ___ / _(_)___| |__ "
Print " / ` |/ _ \ | |_| / __| //_ \ "
Print "| (_) | (_) | | _| \__ \ | | | "
Print " \__, |\___/ |_| |_|___/_| |_| "
Print " |___/ "
Print ""
text ,,fn colorCyan
print %(301,90),"( x to exit the game )"
text ,,fn colorWhite
print " Go Fish Rules:"
print
print " You are playing against the CPU."
print " You are dealt nine cards to start with."
print " The remaining cards are placed face down in the center of the table"
print " to form the draw pile (the fish pond)."
print " On your turn, you ask the CPU For a card."
print " You must already have at least one card of a given rank to ask For more."
print " (A rank is one or more of any card.)"
print " If the CPU has any cards of the named rank, it must hand over all such cards,"
print " and you can then ask again."
print " If the CPU has no cards of the named rank, a card will be drawn from the pile,"
print " and placed in your hand, which then ends your turn."
print " A book is a collection of four cards in a given rank."
print " Whenever you complete a book, it will be removed from your hand."
print " If at any time, your hand is empty, a new card will be drawn from the pile."
print " The game ends when every book is complete,"
print " or there are no more cards left in the pile."
print " The player with the most books wins."
CFStringRef UserInput
"InputYourName"
UserInput = input % (300, 70), @"What's your name?: "
if ( UserInput == NULL ) then "InputYourName" // Rich added this 5/1/24
fn CFStringGetPascalString (UserInput, @YourName, 256, _kCFStringEncodingMacRoman)
cls
if YourName = "X" || YourName = "x" || YourName = chr$(127) then fn QuitOrResumeAlert(@"EXIT")
End fn
local fn WhatCardInputHeight as short
CGRect mainScreenFrame = fn ScreenMainFrame
float InputHeight = int(mainScreenFrame.size.height - 120)
end fn = InputHeight
local fn BuildWindow
// ---> Get the size of the Main Screen. <---
CGRect mainScreenFrame = fn ScreenMainFrame
float msh = mainScreenFrame.size.height
CGRect r = fn CGRectMake( 0, 0, 600, int(msh) - 110)
window 1, @"Go Fish", r
windowcenter(1)
WindowSetBackgroundColor(1,fn ColorBlack)
end fn
//--- Start ---
fn BuildWindow
fn Intro
fn InitCards
str255 AddTheS
bool RequestCard = _false
short v = 0
short po = 0
boolean ShowHand = _false
str255 WantsCard
"Main"
ShowHand = _false
str255 RequestedCard
While ShowHand = _false
text ,,fn colorGreen
Print Chr$(10) + "Points >> ";
text ,,fn colorYellow
print YourName + ": ";
text ,,fn colorGreen
print Points(0);
text ,,fn colorOrange
print " CPU: ";
text ,,fn colorGreen
print Points(1)
text ,,fn colorWhite
Print Chr$(10) + " " + str$(RemainingCards) + " remaining cards"
text ,,fn colorWhite
/*
// Uncomment this to see the CPUs cards For testing
Print Chr$(10) + "CPU Cards: ";
For i = 1 To 13
if Computer(i) <> 0
For j = 1 To Computer(i)
if Mid$(cards,i,1) = "0"
Print @"10"; " ";
else
Print Mid$(cards,i,1); " ";
end if
Next j
End If
Next i
Print
fn PrintViewScrollToBottom( fn WindowPrintView(1))
*/
Print Chr$(10) + "Your Cards: ";
For i = 1 To 13
if play(i) <> 0
For j = 1 To play(i)
if Mid$(cards,i,1) = "0"
Print @"10"; " ";
else
Print Mid$(cards,i,1); " ";
end if
Next j
End If
Next i
Print
fn PrintViewScrollToBottom( fn WindowPrintView(1))
RequestCard = _false
While RequestCard = _false
if fn CheckForEndGame = _True then cls:fn InitCards:goto "Loop"
Someone = YourName
CFStringRef UserInput = 0
"InputCard"
UserInput = input % (20, fn WhatCardInputHeight),@"What card do you want? "
if ( UserInput == NULL ) then "InputCard" // Rich added this 5/1/24
fn CFStringGetPascalString (UserInput, @RequestedCard, 256, _kCFStringEncodingMacRoman)
if RequestedCard = "10" then RequestedCard = "0"// card zero is a 10
text ,,fn ColorYellow
Print
WantsCard = RequestedCard
if WantsCard = "j" || WantsCard = "J" then WantsCard = "Jack"
if WantsCard = "q" || WantsCard = "Q" then WantsCard = "Queen"
if WantsCard = "k" || WantsCard = "K" then WantsCard = "King"
if WantsCard = "a" || WantsCard = "A" then WantsCard = "Ace"
if WantsCard = "0" then WantsCard = "10"
print "-------------------------------------"
print
str255 AorAn
AorAn = "a"
if WantsCard = "Ace" then AorAn = "an"
print YourName + " asked For " + AorAn + " " + WantsCard
print
text ,,fn ColorWhite
fn PrintViewScrollToBottom( fn WindowPrintView(1))
if RequestedCard = "X" || RequestedCard = "x" then fn QuitOrResumeAlert(@"EXIT")
If RequestedCard <> "" Then CardNumber = Instr$(1,cards, Ucase$(RequestedCard)): RequestCard = _true
If CardNumber = 0
text,,fn ColorRed
Print "Sorry, that is not a valid card.": RequestCard = _false
print
fn PrintViewScrollToBottom( fn WindowPrintView(1))
Else if play(CardNumber) = 0 Then text ,,fn colorRed: Print "You don//t have that card!": text ,,fn colorRed: RequestCard = _false
fn PrintViewScrollToBottom( fn WindowPrintView(1))
text,,fn ColorWhite
End If
Wend
guess(CardNumber) = 1
If Computer(CardNumber) = 0
Print Someone + ",";
text ,,fn colorRed
Print " Go fish!"
text ,,fn colorWhite
Print Someone + " got a";: fn youGoFishing
print
fn CheckForCompletedBook
ShowHand = _true
Else
v = Computer(CardNumber)
Computer(CardNumber) = 0
play(CardNumber) += v
if v > 1 then AddTheS = "s" else AddTheS = ""
Print Someone + " got" + str$(v) + " card" + AddTheS
fn CheckForCompletedBook
fn PrintViewScrollToBottom( fn WindowPrintView(1))
ShowHand = _false
End If
Wend
Someone = "CPU"
For i = 1 To 13
asked(i) = 0
Next i
bool CPUsTurn = _false
While CPUsTurn = _false
if fn CheckForEndGame = _True then cls:fn InitCards:goto "Loop"
po = 0
For i = 1 To 13
If (Computer(i) > 0) && (guess(i) > 0) Then poss(i) = 1: po += 1
Next i
short whilecounter
WhileCounter = 0
If po = 0
// this k is the go fish card.
k = rnd(12) +1
while Computer(k) = 0 || asked(k)
whilecounter ++
k = rnd(12) +1
if WhileCounter > 100 then k = 0: exit while //5/5/24 Rich added this to prevent hangs
wend
Else
k = rnd(12) + 1
while poss(k) = 0
k = rnd(12) + 1
if WhileCounter > 100 then k = 0: exit while //5/5/24 Rich added this to prevent hangs
wend
guess(k) = 0
asked(k) = 1
end if
if k = 0 then "Loop" //5/5/24 Rich added this to prevent hangs
WantsCard = fn CheckForFaceCard(k)
if WantsCard = "j" || WantsCard = "J" then WantsCard = "Jack"
if WantsCard = "q" || WantsCard = "Q" then WantsCard = "Queen"
if WantsCard = "k" || WantsCard = "K" then WantsCard = "King"
if WantsCard = "a" || WantsCard = "A" then WantsCard = "Ace"
if WantsCard = "0" then WantsCard = "10"
text ,,fn ColorOrange
print "-------------------------------------"
Print:Print Someone + " wants your " + wantsCard + "'s."
print
text ,,fn ColorWhite
asked(k) = 1
If play(k) = 0
Print Someone + ", ";
text ,,fn colorRed: Print "go fish!"
text ,,fn colorWhite:Print Someone + " got";: fn cpuGoFishing
fn CheckCPUForCompletedBook
CPUsTurn = _true
Else
v = play(k)
play(k) = 0
Computer(k) += v
if v > 1 then AddTheS = "s" else AddTheS = ""
Print Someone + " got" + str$(v) + " card" + AddTheS
fn CheckCPUForCompletedBook
CPUsTurn = _false
End If
Wend
"Loop"
goto "Main"
handleevents
Go
See Go Fish/Go
Haskell
See Go Fish/Haskell
Icon and Unicon
See Go Fish/Unicon
J
See Go Fish/J
Java
See Go Fish/Java
Julia
see Go Fish/Julia
Kotlin
See Go Fish/Kotlin
Lua
See Go Fish/Lua
Locomotive Basic
Mathematica / Wolfram Language
Nim
See Go Fish/Nim
OCaml
See Go Fish/OCaml
Perl
#!/usr/bin/perl
use strict; # https://rosettacode.org/wiki/Go_Fish
use warnings;
use List::Util qw( first shuffle );
my $pat = qr/[atjqk2-9]/; # ranks
my $deck = join '', shuffle map { my $rank = $_; map "$rank$_", qw( S H C D ) }
qw( a t j q k ), 2 .. 9;
my $mebooks = my $youbooks = 0;
my $me = substr $deck, 0, 2 * 9, '';
my $mepicks = join '', $me =~ /$pat/g;
arrange($me);
$mebooks++ while $me =~ s/($pat).\1.\1.\1.//;
my $you = substr $deck, 0, 2 * 9, '';
my $youpicks = join '', $you =~ /$pat/g;
arrange($you);
$youbooks++ while $you =~ s/($pat).\1.\1.\1.//;
while( $mebooks + $youbooks < 13 )
{
play( \$you, \$youbooks, \$youpicks, \$me, \$mebooks, 1 );
$mebooks + $youbooks == 13 and last;
play( \$me, \$mebooks, \$mepicks, \$you, \$youbooks, 0 );
}
print "me $mebooks you $youbooks\n";
sub arrange { $_[0] = join '', sort $_[0] =~ /../g }
sub human
{
my $have = shift =~ s/($pat).\K(?!\1)/ /gr;
local $| = 1;
my $pick;
do
{
print "You have $have, enter request: ";
($pick) = lc(<STDIN>) =~ /$pat/g;
} until $pick and $have =~ /$pick/;
return $pick;
}
sub play
{
my ($me, $mb, $lastpicks, $you, $yb, $human) = @_;
my $more = 1;
while( arrange( $$me ), $more and $$mb + $$yb < 13 )
{
# use Data::Dump 'dd'; dd \@_, "deck $deck";
if( $$me =~ s/($pat).\1.\1.\1.// )
{
print "book of $&\n";
$$mb++;
}
elsif( $$me )
{
my $pick = $human ? do { human($$me) } : do
{
my %picks;
$picks{$_}++ for my @picks = $$me =~ /$pat/g;
my $pick = first { $picks{$_} } split(//, $$lastpicks), shuffle @picks;
print "pick $pick\n";
$$lastpicks =~ s/$pick//g;
$$lastpicks .= $pick;
$pick;
};
if( $$you =~ s/(?:$pick.)+// )
{
$$me .= $&;
}
else
{
print "GO FISH !!\n";
$$me .= substr $deck, 0, 2, '';
$more = 0;
}
}
elsif( $deck )
{
$$me .= substr $deck, 0, 2, '';
}
else
{
$more = 0;
}
}
arrange( $$me );
}
Phix
See Go Fish/Phix
PicoLisp
See Go Fish/PicoLisp
PowerShell
PureBasic
Python
See Go Fish/Python
Raku
(formerly Perl 6) See Go Fish/Raku
Red
Red [
Title: "Go Fish"
Author: "gltewalt"
]
chand: [] ;-- c and p = computer and player
cguesses: []
phand: []
cbooks: 0
pbooks: 0
gf: {
***************
* GO FISH *
***************
}
pip: ["a" "2" "3" "4" "5" "6" "7" "8" "9" "10" "j" "q" "k"] ;-- suits are not relevant
pile: [] ;-- where discarded cards go
;---------------------
; Helper functions -
;---------------------
clear-screen: does [
"clears the console"
call/console either system/platform = 'Linux ["clear"]["cls"]
]
clear-and-show: func [duration str][
{
Poor persons animation.
Blips message to screen after a pause of duration length.
}
clear-screen
print str
wait duration
clear-screen
]
deal-cards: func [num hand][
loop num [
append hand rejoin [trim/all form take deck]
]
]
find-in: func [blk str][
"Finds a string value in a block. Series in series."
foreach i blk [if find i str [return i]]
]
go-fish: func [num hand][
either not empty? deck [
deal-cards num hand
][
append hand rejoin [trim/all form take pile] ;-- take from pile if deck is empty
]
]
guess-from: func [hand guessed][
{
Randomly picks from hand minus guessed.
Simulates a person asking for different cards on
their next turn if their previous guess resulted
in a Go Fish.
}
random/seed now/time
either any [empty? guessed empty? exclude hand guessed][
random/only hand
][
random/only exclude hand guessed
]
]
make-deck: function [] [
"make-deck and shuffle from https://rosettacode.org/wiki/Playing_cards#Red"
new-deck: make block! 52
foreach p pip [loop 4 [append/only new-deck p]]
return new-deck
]
show-cards: does [
clear-and-show 0 ""
print [newline "Player cards:" newline sort phand newline]
print ["Computer books:" cbooks]
print ["Player books:" pbooks newline]
]
shuffle: function [deck [block!]] [deck: random deck]
;------------- end of helper functions -----------------
check-for-books: func [
{
Checks for a book in a players hand.
Increments the players book score, and
discards the book from the players hand
}
hand "from or to hand"
kind "rank of cards"
/local
c "collected"
][
c: collect [
forall hand [keep find hand/1 kind]
]
remove-each i c [none = i]
if 4 = length? c [
either hand = phand [pbooks: pbooks + 1][cbooks: cbooks + 1]
remove-each i hand [if find/only c i [i]] ;-- remove book from hand
forall c [append pile c/1] ;-- append discarded book to the pile
]
]
transfer-cards: func [
"Transfers cards from player to player"
fhand "from hand"
thand "to hand"
kind "rank of cards"
/local
c "collected"
][
c: collect [forall fhand [keep find fhand/1 kind]]
remove-each i c [none = i] ;-- remove none values from collected
forall c [append thand c/1] ;-- append remaining values to "to hand"
remove-each i fhand [if find/only c i [i]] ;-- remove those values from "from hand"
]
computer-turn: func [
fhand "from hand"
thand "to hand"
kind "rank of cards"
/local
a
][
a: ask rejoin ["Do you have any " kind " s? "]
if a = "x" [halt]
either any [a = "y" a = "yes"][
check-for-books thand kind
transfer-cards fhand thand kind
show-cards
computer-turn fhand thand guess-from thand cguesses
][
clear-and-show 0.4 gf
go-fish 1 thand
append cguesses kind
]
]
player-turn: func [
fhand "from hand"
thand "to hand"
kind "rank of cards"
/local
p
][
if empty? fhand [go-fish 3 fhand]
if none? find-in thand kind [ ;-- player has to hold rank asked for
clear-and-show 1.0
"You have to have that rank in your hand to ask for it.^/Computers turn..."
exit
]
either find-in fhand kind [
check-for-books thand kind
transfer-cards fhand thand kind
show-cards
if find-in thand kind [
p: ask "Your guess: "
either p = "x" [halt][player-turn fhand thand p]
check-for-books thand p
]
][
clear-and-show 0.4 gf
go-fish 1 thand
]
]
game-round: has [c p][
print {
-------------------
- COMPUTER TURN -
-------------------
}
if empty? chand [ ; computer has no more cards? fish 3 cards.
go-fish 3 chand
show-cards
]
computer-turn phand chand c: guess-from chand cguesses
check-for-books chand c
show-cards
print {
-------------------
- PLAYER TURN -
-------------------
}
if empty? phand [ ;-- player has no more cards? fish 3 cards.
go-fish 3 phand
show-cards
]
p: ask "Your guess: "
either p = "x" [halt][player-turn chand phand find-in phand p]
check-for-books phand p
show-cards
]
main: does [
deck: shuffle make-deck
deal-cards 9 chand
deal-cards 9 phand
show-cards
while [cbooks + pbooks < 13][
game-round
]
clear-and-show 0 ""
print "GAME OVER"
print [newline "Computer books:" cbooks newline "Player books:" pbooks]
]
main
Rust
See Go Fish/Rust
Ruby
See Go Fish/Ruby
Tcl
See Go Fish/Tcl
V (Vlang)
Wren
See Go Fish/Wren