Go Fish: Difference between revisions
(→{{header|Haskell}}: Cleanup.) |
|||
(57 intermediate revisions by 35 users not shown) | |||
Line 3: | Line 3: | ||
* Each player is dealt nine cards to start with. |
* Each player is dealt nine cards to start with. |
||
* On their turn, a player asks their opponent for a given rank ( |
* 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 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. |
** 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. |
* 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. |
* 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 game ends when every book is complete. The player with the most books wins. |
||
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. |
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. |
||
Line 14: | Line 14: | ||
You may want to use code from [[Playing Cards]]. |
You may want to use code from [[Playing Cards]]. |
||
Related tasks: |
|||
=={{header|Haskell}}== |
|||
* [[Playing cards]] |
|||
* [[Card shuffles]] |
|||
* [[Deal cards_for_FreeCell]] |
|||
* [[War Card_Game]] |
|||
* [[Poker hand_analyser]] |
|||
If possible, the AI will randomly select a rank known to be in the human's hand (a card in the AI's hand that the human has asked for before and the AI hasn't asked for before). If there are no known ranks, a rank is randomly selected from the AI's hand. |
|||
=={{header|Aime}}== |
|||
<lang haskell> |
|||
See [[Go Fish/Aime]] |
|||
import Char |
|||
import IO |
|||
import Data.Map (Map) |
|||
import qualified Data.Map as M |
|||
import Data.Set (Set) |
|||
import qualified Data.Set as S |
|||
import Data.List |
|||
import Monad |
|||
import Random |
|||
=={{header|AutoHotkey}}== |
|||
data Player = Player String (GameState -> IO Rank) |
|||
See [[Go Fish/AutoHotkey]] |
|||
=={{header|C}}== |
|||
type PlayerState = (Hand, Set Rank, Set Rank) |
|||
See [[Go Fish/C]] |
|||
=={{header|C++}}== |
|||
data GameState = GS [(Suit, Rank)] PlayerState PlayerState |
|||
See [[Go Fish/C++]] |
|||
=={{header|D}}== |
|||
type Hand = Map Rank (Set Suit) |
|||
See [[Go Fish/D]] |
|||
=={{header|Erlang}}== |
|||
data Suit = Diamond | Club | Heart | Spade |
|||
See [[Go Fish/Erlang]] |
|||
deriving (Bounded, Enum, Eq, Ord, Show) |
|||
=={{header|FreeBASIC}}== |
|||
data Rank = Two | Three | Four | Five | Six | Seven | Eight | Nine | Ten | |
|||
<syntaxhighlight lang="freebasic"> |
|||
Jack | Queen | King | Ace |
|||
' Go Fish ~ ¡Pesca! |
|||
deriving (Bounded, Enum, Eq, Ord, Show) |
|||
Const cartas = "A234567890JQK" |
|||
main = |
|||
hSetBuffering stdout NoBuffering >> |
|||
putStrLn "GO FISH\n\nDealing Cards" >> |
|||
initialGameState >>= |
|||
play (cycle [player, computer]) |
|||
Declare Sub Reparto_Cartas |
|||
play ((Player name next):ps) state = |
|||
Declare Sub Pescar_Carta_Jug |
|||
putStrLn ('\n' : name ++ "'S TURN") >> |
|||
Declare Sub Pescar_Carta_CPU |
|||
runPlayer next state >>= \nextState -> |
|||
Declare Sub Comprobar_Libro_Jug |
|||
(if isDone nextState |
|||
Declare Sub Comprobar_Libro_CPU |
|||
then let (winnerName, ws, ls) = scoreGame name (head ps) nextState |
|||
Declare Sub Comprobar_Fin_Partida |
|||
in putStrLn (winnerName ++ " WINS " ++ show ws ++ " TO " ++ show ls) |
|||
Declare Sub Intro |
|||
else play ps $ swapPlayers nextState |
|||
) |
|||
Dim Shared As Integer play(13), compu(13), deck(13), guess(13), poss(13), asked(13) |
|||
scoreGame name (Player opp _) (GS _ (_,books,_) (_,oppBooks,_)) = |
|||
Dim Shared As String nombre, Snombre, CartaPedida |
|||
if score > oppScore then (name,score,oppScore) else (opp,oppScore,score) |
|||
Dim Shared puntos(2) As Byte = {0,0} |
|||
where (score, oppScore) = (S.size books, S.size oppBooks) |
|||
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 |
|||
player = Player "PLAYER" playerBrain |
|||
remca -= 1 |
|||
playerBrain (GS _ (hand,_,_) _) = |
|||
Dim As Integer sc = remca * Rnd + 1 |
|||
putStr "Your cards: " >> |
|||
For k = 1 To 13 |
|||
putStrLn (intercalate " " . map showCard $ handToCards hand) >> |
|||
sc -= deck(k) |
|||
untilSuccess (liftM readRank rankPrompt) (putStrLn "Bad rank") |
|||
If sc <= 0 Then Return |
|||
where rankPrompt = putStr "Ask opponent for what rank? " >> getLine |
|||
Next k |
|||
End Sub |
|||
Sub Pescar_Carta_Jug |
|||
computer = Player "COMPUTER" computerBrain |
|||
Reparto_Cartas |
|||
computerBrain (GS _ (hand,_,history) (_, _, oppHistory)) = |
|||
Print " " &Mid(cartas,k,1) &"." |
|||
liftM selectRank newStdGen >>= \rank -> |
|||
deck(k) -= 1 |
|||
putStrLn ("Do you have any " ++ show rank ++ "s?") >> |
|||
play(k) += 1 |
|||
End Sub |
|||
where knowns = S.difference (S.intersection guesses oppHistory) history |
|||
guesses = M.keysSet hand |
|||
ranks = S.toList $ if S.null knowns then guesses else knowns |
|||
selectRank = (ranks !!) . fst . randomR (0, length ranks - 1) |
|||
Sub Pescar_Carta_CPU |
|||
runPlayer askRank state@(GS deck (hand, b, hi) o) = |
|||
Reparto_Cartas |
|||
Print "a carta." |
|||
deck(k) -= 1 |
|||
then return $! state |
|||
compu(k) += 1 |
|||
else putStrLn "Empty hand, forced draw" >> |
|||
End Sub |
|||
let (newHand, newDeck) = draw hand deck |
|||
in normalizeBooks $ GS newDeck (newHand, b, hi) o |
|||
else getValidRank askRank state >>= \rank -> |
|||
exchangeCards state rank >>= \(newState, done) -> |
|||
normalizeBooks newState >>= |
|||
(if done then return else runPlayer askRank) |
|||
Sub Comprobar_Libro_Jug |
|||
exchangeCards (GS deck (hand, b, hist) (opponentHand, ob, ohi)) rank = |
|||
For i = 1 To 13 |
|||
putStrLn m >> return (GS nd (nh, b, nhi) (noh, ob, ohi), done) |
|||
If play(i) <> 4 Then |
|||
where (m, nh, noh, nd, done) = worker $ M.lookup rank opponentHand |
|||
Else |
|||
Color 11: Print Snombre &" completa el libro de " &Mid(cartas,i,1) &"'s.": Color 7 |
|||
worker Nothing = ("Go fish", newHand, opponentHand, newDeck, True) |
|||
play(i) = 0 |
|||
puntos(0) += 1 |
|||
worker (Just suits) = (message, newHand, newOppHand, deck, False) |
|||
End If |
|||
where message = show (S.size suits) ++ " " ++ show rank ++ "(s)" |
|||
Next i |
|||
newHand = M.adjust (S.union suits) rank hand |
|||
End Sub |
|||
newOppHand = M.delete rank opponentHand |
|||
Sub Comprobar_Libro_CPU |
|||
getValidRank askRank state@(GS _ (hand,_,_) _) = untilSuccess |
|||
For i = 1 To 13 |
|||
(liftM (check hand) $ askRank state) $ putStrLn "Rank not in hand" |
|||
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 |
|||
normalizeBooks (GS d (hand, books, hi) o) = |
|||
Dim As Integer np = 0, nc = 0 |
|||
mapM_ printRank (M.keys newBookRanks) >> |
|||
For i = 1 To 13 |
|||
(return $! GS d (newHand, newBooks, hi) o) |
|||
np += play(i) |
|||
where (newBookRanks, newHand) = M.partition ((==4) . S.size) hand |
|||
nc += compu(i) |
|||
newBooks = S.union books $ M.keysSet newBookRanks |
|||
Next i |
|||
printRank r = putStrLn ("Rank " ++ show r ++ " was booked") |
|||
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 |
|||
swapPlayers (GS d p1 p2) = GS d p2 p1 |
|||
Color 15 |
|||
Print " __ _ _ " |
|||
Print " __ _ ___ / _(_)___| |__ " |
|||
Print " / ` |/ _ \ | |_| / __| '_ \ " |
|||
Print "| (_) | (_) | | _| \__ \ | | | " |
|||
Print " \__, |\___/ |_| |_|___/_| |_| " |
|||
Print " |___/ " |
|||
Print " " |
|||
Color 14: Locate 10, 2: Input "Como te llamas: ", nombre |
|||
End Sub |
|||
'--- Programa Principal --- |
|||
isDone (GS deck (hand,_,_) (oppHand,_,_)) = |
|||
Cls |
|||
and [M.null hand, M.null oppHand, null deck] |
|||
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" |
|||
initialGameState = liftM worker newStdGen |
|||
For i = 1 To 13 |
|||
asked(i) = 0 |
|||
(GS deck (hand1, S.empty, S.empty) (hand2, S.empty, S.empty)) |
|||
Next i |
|||
where (startDeck, _) = shuffle initialDeck gen |
|||
Dim As boolean Turno_CPU_2 = false |
|||
(hand1, deckMinusPlayerHand) = drawN 9 M.empty startDeck |
|||
While Turno_CPU_2 = false |
|||
(hand2, deck) = drawN 9 M.empty deckMinusPlayerHand |
|||
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." |
|||
untilSuccess action onFailure = worker |
|||
asked(k) = 1 |
|||
where worker = action >>= \result -> case result of |
|||
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 |
|||
</syntaxhighlight> |
|||
=={{header|FutureBasic}}== |
|||
readRank [x] | isDigit x && x > '1' = Just $ toEnum (fromEnum x - 50) |
|||
Translated from FreeBasic |
|||
readRank x@[_,_] | x == "10" = Just Ten |
|||
May 5, 2024 Rich Love |
|||
readRank [x] = case toLower x of |
|||
Fixed intermittent hang |
|||
'j' -> Just Jack |
|||
Also, now using && and || to be compatible with later versions of FutureBasic. |
|||
'q' -> Just Queen |
|||
( replaces AND and OR ) |
|||
'k' -> Just King |
|||
<syntaxhighlight lang="futurebasic"> |
|||
'a' -> Just Ace |
|||
_ -> Nothing |
|||
readRank _ = Nothing |
|||
/* |
|||
showCard (suit, rank) = r ++ front suit |
|||
where r = if rank > Ten then front rank else show (fromEnum rank + 2) |
|||
front v = [head $ show v] |
|||
Go Fish |
|||
initialDeck = liftM2 (,) [Diamond .. Spade] [Two .. Ace] |
|||
-- Rich Love -- |
|||
FutureBasic app For Macintosh |
|||
shuffle deck gen = worker gen (length deck) [] deck |
|||
Get the latest FutureBasic here |
|||
where worker g l xs [] = (xs, g) |
|||
http://www.brilorsoftware.com/fb/pages/home.html |
|||
worker g l xs ys = worker newGen (l-1) (card : xs) (delete card ys) |
|||
where (index, newGen) = randomR (0,l-1) g |
|||
card = ys !! index |
|||
*/ |
|||
draw hand ((s,r):deck) = (M.insertWith S.union r (S.singleton s) hand, deck) |
|||
drawN n hand deck = iterate (uncurry draw) (hand, deck) !! (n-1) |
|||
_window = 1 |
|||
handToCards = concatMap (\(r,ss) -> map (flip (,) r) $ S.toList ss) . M.assocs |
|||
begin enum 1 |
|||
</lang> |
|||
_scrollView |
|||
_textView |
|||
end enum |
|||
override _forLoopsAlwaysExecuteAtLeastOnce = _true |
|||
=={{header|OCaml}}== |
|||
begin globals |
|||
<lang ocaml>type pip = Two | Three | Four | Five | Six | Seven | Eight | Nine | Ten | |
|||
Jack | Queen | King | Ace |
|||
let pips = [Two; Three; Four; Five; Six; Seven; Eight; Nine; Ten; |
|||
Jack; Queen; King; Ace] |
|||
type suit = Diamonds | Spades | Hearts | Clubs |
|||
let suits = [Diamonds; Spades; Hearts; Clubs] |
|||
type card = pip * suit |
|||
str255 cards |
|||
let string_of_pip = function |
|||
cards = "A234567890JQK" |
|||
| Two -> "Two" |
|||
short play(13), Computer(13), deck(13), guess(13), poss(13), asked(13) |
|||
| Three -> "Three" |
|||
str255 YourName, Someone |
|||
| Four -> "Four" |
|||
//bool gNeedToClearScreen |
|||
| Five -> "Five" |
|||
short Points(2) : Points(0) = 0 : Points(1) = 0 |
|||
| Six -> "Six" |
|||
short i, k, j, CardNumber |
|||
| Seven -> "Seven" |
|||
short RemainingCards |
|||
| Eight -> "Eight" |
|||
| Nine -> "Nine" |
|||
| Ten -> "Ten" |
|||
| Jack -> "Jack" |
|||
| Queen -> "Queen" |
|||
| King -> "King" |
|||
| Ace -> "Ace" |
|||
let string_of_suit = function |
|||
| Diamonds -> "Diamonds" |
|||
| Spades -> "Spades" |
|||
| Hearts -> "Hearts" |
|||
| Clubs -> "Clubs" |
|||
end globals |
|||
let string_of_card (pip, suit) = |
|||
(Printf.sprintf "(%s-%s)" (string_of_pip pip) (string_of_suit suit)) |
|||
let pip_of_card (pip, _) = (pip) |
|||
local fn CheckForFaceCard(TheCard as short) as str255 |
|||
let deck = List.concat (List.map (fun pip -> List.map (fun suit -> (pip, suit)) suits) pips) |
|||
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 ) |
|||
type rank_state = |
|||
BeginCCode |
|||
| Unknown (* Don't know if the opponent has any cards in that rank. *) |
|||
NSScrollView *scrollView = [printView enclosingScrollView]; |
|||
| No_cards (* Opponent has no cards there; I took them away, or I asked yet. *) |
|||
NSClipView *clipView = [scrollView contentView]; |
|||
| Has_cards (* Opponent has cards there; they tried to get them off me and haven't booked them yet. *) |
|||
[clipView scrollToPoint:NSMakePoint(0,printView.frame.size.height-scrollView.contentSize.height + 20)]; |
|||
| Booked (* Someone has booked the rank. *) |
|||
[scrollView reflectScrolledClipView:clipView]; |
|||
EndC |
|||
end fn |
|||
let state_score = function |
|||
| Booked -> 0 |
|||
| No_cards -> 1 |
|||
| Unknown -> 2 |
|||
| Has_cards -> 3 |
|||
void local fn DealCards |
|||
let string_of_state = function |
|||
| Booked -> "Booked" |
|||
RemainingCards -= 1 |
|||
| No_cards -> "No_cards" |
|||
short sc |
|||
| Unknown -> "Unknown" |
|||
sc = rnd(RemainingCards) + 1 // 5/2/24 Rich added + 1 |
|||
| Has_cards -> "Has_cards" |
|||
For k = 1 To 13 |
|||
sc -= deck(k) |
|||
If sc <= 0 Then exit fn |
|||
Next k |
|||
End fn |
|||
void local fn youGoFishing |
|||
let replace ((rank,_) as state) opp = |
|||
let rec aux acc = function |
|||
fn DealCards |
|||
| (_rank,_)::tl when _rank = rank -> List.rev_append acc (state::tl) |
|||
| hd::tl -> aux (hd::acc) tl |
|||
str255 WantsCard |
|||
| [] -> assert(false) |
|||
WantsCard = fn CheckForFaceCard(k) |
|||
in |
|||
aux [] opp ;; |
|||
if WantsCard = "0" then WantsCard = "10" |
|||
Print " " + WantsCard + "." |
|||
deck(k) -= 1 |
|||
play(k) += 1 |
|||
End fn |
|||
void local fn cpuGoFishing |
|||
class virtual abstract_player = |
|||
object (s) |
|||
fn DealCards |
|||
val mutable virtual cards : card list |
|||
Print " a card from the deck." |
|||
val mutable virtual books : pip list |
|||
if k > 13 then k = 13 |
|||
deck(k) -= 1 |
|||
method virtual give_rank : pip -> card list |
|||
Computer(k) += 1 |
|||
method virtual notify_booked : pip -> unit |
|||
method virtual request_failed : pip -> unit |
|||
End fn |
|||
method private cards_given rank = |
|||
let matched, rest = List.partition (fun (pip,_) -> pip = rank) cards in |
|||
if List.length matched = 4 then begin |
|||
cards <- rest; |
|||
books <- rank :: books; |
|||
s#notify_booked rank; |
|||
(Some rank) |
|||
end |
|||
else (None) |
|||
void local fn CheckForCompletedBook |
|||
method give_card (card : card) = |
|||
let rank = pip_of_card card in |
|||
For i = 1 To 13 |
|||
cards <- card :: cards; |
|||
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 |
|||
method give_cards (_cards : card list) = |
|||
let rank = |
|||
For i = 1 To 13 |
|||
| [] -> invalid_arg "empty list" |
|||
If Computer(i) <> 4 |
|||
Else |
|||
List.fold_left |
|||
text ,,fn colorCyan |
|||
(fun rank1 (rank2,_) -> |
|||
str255 WantsCard |
|||
if rank1 <> rank2 |
|||
WantsCard = Mid$(cards,i,1) |
|||
then invalid_arg "!= ranks" |
|||
if WantsCard = "j" || WantsCard = "J" then WantsCard = "Jack" |
|||
if WantsCard = "q" || WantsCard = "Q" then WantsCard = "Queen" |
|||
in |
|||
if WantsCard = "k" || WantsCard = "K" then WantsCard = "King" |
|||
cards <- _cards @ cards; |
|||
if WantsCard = "a" || WantsCard = "A" then WantsCard = "Ace" |
|||
s#cards_given rank |
|||
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 |
|||
method give_rank rank = |
|||
let give, _cards = List.partition (fun (pip, _) -> pip = rank) cards in |
|||
cards <- _cards; |
|||
(give) |
|||
local fn InitCards |
|||
method books_length = |
|||
(List.length books) |
|||
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 |
|||
method empty_hand = |
|||
cards = [] |
|||
local fn QuitOrPlayAlert(GameResult as CFStringRef) |
|||
method private dump_cards() = |
|||
print_endline(String.concat ", " (List.map string_of_card cards)); |
|||
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) |
|||
end |
|||
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 |
|||
class human_player = |
|||
object (s) inherit abstract_player |
|||
void local fn Intro |
|||
val mutable cards = [] |
|||
val mutable books = [] |
|||
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 || 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 " || 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 |
|||
method ask_rank() = |
|||
let ranks = |
|||
List.fold_left (fun acc card -> |
|||
let rank = pip_of_card card in |
|||
if List.mem rank acc |
|||
then (acc) |
|||
else (rank::acc) |
|||
) |
|||
[] cards |
|||
in |
|||
s#dump_cards(); |
|||
Printf.printf "Ranks: %s\n%!" (String.concat ", " (List.map string_of_pip ranks)); |
|||
let n = List.length ranks in |
|||
Printf.printf "choose from 1 to %d\n%!" n; |
|||
let get_int() = |
|||
try int_of_string(read_line()) |
|||
with Failure "int_of_string" -> raise Exit |
|||
in |
|||
let rec aux() = |
|||
let d = get_int() in |
|||
if d <= 0 || d > n then aux() else (pred d) |
|||
in |
|||
let d = aux() in |
|||
(List.nth ranks d) |
|||
local fn WhatCardInputHeight as short |
|||
method notify_booked rank = |
|||
Printf.printf "Rank [%s] is now booked\n%!" (string_of_pip rank); |
|||
CGRect mainScreenFrame = fn ScreenMainFrame |
|||
float InputHeight = int(mainScreenFrame.size.height - 120) |
|||
end fn = InputHeight |
|||
method request_failed rank = () |
|||
end |
|||
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 |
|||
class ai_player = |
|||
object (s) inherit abstract_player as parent |
|||
fn Intro |
|||
val mutable cards = [] |
|||
val mutable books = [] |
|||
val mutable opponent = List.map (fun rank -> (rank, Unknown)) pips |
|||
fn InitCards |
|||
method private dump_state() = |
|||
let f (pip, state) = |
|||
Printf.sprintf "{%s:%s}" (string_of_pip pip) (string_of_state state) |
|||
in |
|||
print_endline(String.concat ", " (List.map f opponent)); |
|||
str255 AddTheS |
|||
method ask_rank() = |
|||
bool RequestCard = _false |
|||
let ranks = |
|||
short v = 0 |
|||
List.fold_left (fun acc card -> |
|||
short po = 0 |
|||
let rank = pip_of_card card in |
|||
boolean ShowHand = _false |
|||
try |
|||
str255 WantsCard |
|||
let _,n = List.find (fun (_rank,_) -> _rank = rank) acc in |
|||
(replace (rank, n+1) acc) |
|||
with Not_found -> |
|||
((rank,1)::acc) |
|||
) |
|||
[] cards |
|||
in |
|||
let f (rank,_) = |
|||
(state_score(List.assoc rank opponent)) |
|||
in |
|||
let ranks = List.sort (fun a b -> (f b) - (f a)) ranks in |
|||
(* DEBUG |
|||
Printf.printf "Ranks: %s\n%!" (String.concat ", " (List.map string_of_pip ranks)); |
|||
s#dump_state(); |
|||
s#dump_cards(); |
|||
*) |
|||
opponent <- List.sort (fun _ _ -> Random.int 9 - Random.int 9) opponent; |
|||
if ranks <> [] |
|||
then fst(List.hd ranks) |
|||
else Jack |
|||
"Main" |
|||
method give_cards (_cards : card list) = |
|||
let rank = pip_of_card(List.hd _cards) in |
|||
opponent <- replace (rank, No_cards) opponent; |
|||
(parent#give_cards _cards) |
|||
ShowHand = _false |
|||
method give_rank rank = |
|||
opponent <- replace (rank, Has_cards) opponent; |
|||
(parent#give_rank rank) |
|||
str255 RequestedCard |
|||
method notify_booked rank = |
|||
opponent <- replace (rank, Booked) opponent |
|||
While ShowHand = _false |
|||
method request_failed rank = |
|||
text ,,fn colorGreen |
|||
opponent <- replace (rank, No_cards) opponent |
|||
Print Chr$(10) + "Points >> "; |
|||
end |
|||
text ,,fn colorYellow |
|||
print YourName + ": "; |
|||
text ,,fn colorGreen |
|||
print Points(0); |
|||
class random_player = |
|||
text ,,fn colorOrange |
|||
object (s) inherit ai_player |
|||
print " CPU: "; |
|||
text ,,fn colorGreen |
|||
method ask_rank() = |
|||
print Points(1) |
|||
let ranks = |
|||
text ,,fn colorWhite |
|||
List.fold_left (fun acc card -> |
|||
Print Chr$(10) + " " + str$(RemainingCards) + " remaining cards" |
|||
let rank = pip_of_card card in |
|||
text ,,fn colorWhite |
|||
if List.mem rank acc |
|||
then (acc) |
|||
else (rank::acc) |
|||
/* |
|||
// Uncomment this to see the CPUs cards For testing |
|||
Print Chr$(10) + "CPU Cards: "; |
|||
in |
|||
For i = 1 To 13 |
|||
if Computer(i) <> 0 |
|||
let d = Random.int n in |
|||
For j = 1 To Computer(i) |
|||
(List.nth ranks d) |
|||
if Mid$(cards,i,1) = "0" |
|||
Print @"10"; " "; |
|||
end |
|||
else |
|||
Print Mid$(cards,i,1); " "; |
|||
end if |
|||
Next j |
|||
exception Empty_deck |
|||
End If |
|||
let card_to_player deck player op = |
|||
Next i |
|||
match deck with |
|||
Print |
|||
| card::deck -> |
|||
fn PrintViewScrollToBottom( fn WindowPrintView(1)) |
|||
begin match player#give_card card with |
|||
*/ |
|||
| None -> () |
|||
| Some rank -> op#notify_booked rank |
|||
end; |
|||
Print Chr$(10) + "Your Cards: "; |
|||
(deck) |
|||
For i = 1 To 13 |
|||
if play(i) <> 0 |
|||
For j = 1 To play(i) |
|||
let n_cards_to_player n deck player op = |
|||
if Mid$(cards,i,1) = "0" |
|||
let rec aux i deck = |
|||
Print @"10"; " "; |
|||
else |
|||
let deck = card_to_player deck player op in |
|||
Print Mid$(cards,i,1); " "; |
|||
end if |
|||
in |
|||
Next j |
|||
End If |
|||
Next i |
|||
Print |
|||
let () = |
|||
fn PrintViewScrollToBottom( fn WindowPrintView(1)) |
|||
Random.self_init(); |
|||
let deck = List.sort (fun _ _ -> Random.int 9 - Random.int 9) deck in |
|||
RequestCard = _false |
|||
let player_a = new human_player |
|||
and player_b = new ai_player in |
|||
While RequestCard = _false |
|||
let deck = n_cards_to_player 9 deck player_a player_b in |
|||
if fn CheckForEndGame = _True then cls:fn InitCards:goto "Loop" |
|||
let deck = n_cards_to_player 9 deck player_b player_a in |
|||
let deck = ref deck in |
|||
Someone = YourName |
|||
let empty_hand player1 player2 = |
|||
if player1#empty_hand |
|||
then deck := card_to_player !deck player1 player2 |
|||
in |
|||
let rec make_turn id1 id2 player1 player2 = |
|||
print_newline(); |
|||
(try |
|||
empty_hand player1 player2; |
|||
empty_hand player2 player1; |
|||
with Empty_deck -> ()); |
|||
if player1#books_length + player2#books_length <> 13 |
|||
then begin |
|||
let rank = player1#ask_rank() in |
|||
Printf.printf "player %s asked for %ss\n%!" id1 (string_of_pip rank); |
|||
let cards = player2#give_rank rank in |
|||
match cards with |
|||
| [] -> |
|||
Printf.printf "player %s has no %ss\n%!" id2 (string_of_pip rank); |
|||
player1#request_failed rank; |
|||
(try |
|||
deck := card_to_player !deck player1 player2; |
|||
make_turn id2 id1 player2 player1 |
|||
with Empty_deck -> ()) |
|||
| cards -> |
|||
let given = String.concat ", " (List.map string_of_card cards) in |
|||
Printf.printf "player %s gives %s\n%!" id2 given; |
|||
begin match player1#give_cards cards with |
|||
| None -> () |
|||
| Some rank -> |
|||
Printf.printf "player %s booked [%s]\n%!" id1 (string_of_pip rank); |
|||
player2#notify_booked rank; |
|||
end; |
|||
make_turn id1 id2 player1 player2 |
|||
end |
|||
in |
|||
(try |
|||
if Random.bool() |
|||
then make_turn "a" "b" player_a player_b |
|||
else make_turn "b" "a" player_b player_a; |
|||
with Exit -> ()); |
|||
Printf.printf "player a has %d books\n" (player_a#books_length); |
|||
Printf.printf "player b has %d books\n" (player_b#books_length); |
|||
;;</lang> |
|||
=={{header|Perl 6}}== |
|||
{{works with|Rakudo|#23 "Lisbon"}} |
|||
<lang perl6>constant BOOKSIZE = 4; |
|||
constant HANDSIZE = 9; |
|||
constant Str @pips = <two three four five six seven eight nine ten jack queen king ace>; |
|||
# The elements of @pips are only names. Pips are represented internally |
|||
# as indices of this array. |
|||
constant Str @piparticles = <a a a a a a an a a a a a an>; |
|||
constant Str @ppips = <deuces threes fours fives sixes sevens eights nines tens jacks queens kings aces>; |
|||
constant Str @shortpips = <2 3 4 5 6 7 8 9 T J Q K A>; |
|||
constant $foe_nominative_pronoun = pick 1, <he she it e xe>; |
|||
sub count ($x, *@a) { |
|||
my $n = 0; |
|||
$_ eqv $x and ++$n for @a; |
|||
return $n; |
|||
} |
|||
sub find ($x, *@a) { |
|||
for @a.kv -> $k, $v { |
|||
$v eqv $x and return $k; |
|||
} |
|||
fail 'Not found'; |
|||
} |
|||
sub maxes (&f, *@a) { |
|||
my $x = [max] map &f, @a; |
|||
return grep { f($^e) eqv $x }, @a; |
|||
} |
|||
sub ncard ($n, $pip) { |
|||
$n > 1 ?? "$n {@ppips[$pip]}" !! "{@piparticles[$pip]} {@pips[$pip]}" |
|||
} |
|||
sub readpip (@user_hand) { |
|||
my @choices = grep { @user_hand[$^p] }, ^@pips; |
|||
if (@choices == 1) { |
|||
say "You're obliged to ask for { @ppips[@choices[0]] }."; |
|||
return @choices[0]; |
|||
} |
|||
loop { |
|||
print 'For what do you ask? (', join(', ', @shortpips[@choices]), '): '; |
|||
my $in = substr uc($*IN.get or next), 0, 1; |
|||
my $pip = find $in, @shortpips; |
|||
if defined $pip { |
|||
@user_hand[$pip] and return $pip; |
|||
say "You don't have any { @ppips[$pip] }."; |
|||
} |
|||
else { |
|||
say 'No such rank.'; |
|||
} |
|||
} |
|||
} |
|||
enum Maybe <No Yes Dunno>; |
|||
class Knowledge { |
|||
# The computer player has an instance of this class for each pip. |
|||
# Each instance tracks whether the computer thinks the user has at |
|||
# least one card of the corresponding pip. |
|||
has Maybe $.maybe = Dunno; |
|||
# Yes if the user definitely has this pip, No if they didn't |
|||
# have it the last time we checked, Dunno if we haven't yet |
|||
# checked. |
|||
has Int $.n = 0; |
|||
# If $.maybe is No, $.n counts how many cards the user |
|||
# has drawn since we last checked. |
|||
method set (Maybe $!maybe) { $!n = 0 } |
|||
method incr { $.maybe == No and ++$!n } |
|||
} |
|||
class Player { |
|||
has Int @.h; |
|||
# @h[$n] is number of cards of pip $n in this player's hand. |
|||
has $.deck; |
|||
# A reference to whatever deck the player's playing with. |
|||
has Int $.books = 0; |
|||
has Bool $.cpu; |
|||
has Knowledge @.know; |
|||
method new ($cpu, @deck is rw) { |
|||
my Int @h = 0 xx @pips; |
|||
++@h[$_] for @deck[^HANDSIZE]; |
|||
@deck = @deck[HANDSIZE ..^ @deck]; |
|||
Player.bless(*, |
|||
h => @h, cpu => $cpu, |
|||
deck => \@deck, |
|||
know => ($cpu ?? map { Knowledge.new() }, @pips !! ()) |
|||
); |
|||
} |
|||
method showhand { |
|||
say |
|||
($.cpu ?? 'The dealer has ' !! 'You have '), |
|||
join(' ', |
|||
map { join ' ', @shortpips[.key] xx .value }, |
|||
grep { .value }, |
|||
pairs @.h), |
|||
'.'; |
|||
} |
|||
method draw () { |
|||
my $new = shift $.deck; |
|||
$.cpu or print "You got { ncard 1, $new }. "; |
|||
say "({ $.deck.elems or 'No' } card{ $.deck.elems == 1 ?? '' !! 's' } left.)"; |
|||
self.getcards(1, $new); |
|||
} |
|||
method getcards (Int $quantity, Int $pip) { |
|||
@!h[$pip] += $quantity; |
|||
@.h[$pip] == BOOKSIZE or return; |
|||
++$!books; |
|||
say |
|||
($.cpu |
|||
?? "The dealer puts down a book of { @ppips[$pip] }" |
|||
!! "That's a book"), |
|||
" (for a total of $.books book{ $.books == 1 ?? '' !! 's' })."; |
|||
self.losecards($pip); |
|||
} |
|||
method losecards (Int $pip) { |
|||
@.h[$pip] = 0; |
|||
while none @.h and $.deck.elems { |
|||
say do $.cpu |
|||
?? "The dealer's hand is empty, so $foe_nominative_pronoun draws a new card." |
|||
!! "Your hand's empty, so you draw a new card."; |
|||
self.draw; |
|||
} |
|||
} |
|||
method learn (Int $pip, Maybe $m) { @.know[$pip].set($m) } |
|||
method notice_draw () { .incr for @.know } |
|||
method choose_request () returns Int { |
|||
#self.showhand; |
|||
#say 'Know: ', join ', ', map |
|||
# { .maybe ~~ Yes ?? 'Yes' !! .maybe ~~ Dunno ?? 'Dunno' !! .n }, |
|||
# @.know; |
|||
my @ps = map { .key }, grep { .value }, pairs @.h; |
|||
return pick 1, maxes { @.h[$^p] }, do |
|||
# Most of all we should ask for cards we know the |
|||
# user has. |
|||
grep { @.know[$^p].maybe ~~ Yes }, @ps or |
|||
# Then try asking for one we haven't requested |
|||
# before. |
|||
grep { @.know[$^p].maybe ~~ Dunno }, @ps or |
|||
# Then try asking for one we least recently |
|||
# asked about. |
|||
maxes { @.know[$^p].n }, @ps; |
|||
} |
|||
} |
|||
sub play () { |
|||
my Int @deck; |
|||
# Shuffle the deck until the first two hands contain no books. |
|||
# (If BOOKSIZE is greater than 2 and HANDSIZE is reasonably |
|||
# small, this'll probably take only one shuffle.) |
|||
repeat { @deck = pick *, ^@pips xx BOOKSIZE } |
|||
until none(map { count $^x, @deck[^HANDSIZE] }, ^@pips) >= BOOKSIZE and |
|||
none(map { count $^x, @deck[HANDSIZE ..^ 2*HANDSIZE] }, ^@pips) >= BOOKSIZE; |
|||
my Player $user .= new(False, @deck); |
|||
my Player $foe .= new(True, @deck); |
|||
CFStringRef UserInput = 0 |
|||
while any |$user.h or any |$foe.h { |
|||
"InputCard" |
|||
UserInput = input % (20, fn WhatCardInputHeight),@"What card do you want? " |
|||
# The user goes first. |
|||
if ( UserInput == NULL ) then "InputCard" // Rich added this 5/1/24 |
|||
while any |$user.h { |
|||
fn CFStringGetPascalString (UserInput, @RequestedCard, 256, _kCFStringEncodingMacRoman) |
|||
say ''; |
|||
if RequestedCard = "10" then RequestedCard = "0"// card zero is a 10 |
|||
$user.showhand; |
|||
text ,,fn ColorYellow |
|||
my $request = readpip $user.h; |
|||
Print |
|||
$foe.learn($request, Yes); |
|||
if $foe.h[$request] -> $quantity is copy { |
|||
WantsCard = RequestedCard |
|||
say 'The dealer reluctantly hands over ', |
|||
ncard($quantity, $request), |
|||
if WantsCard = "j" || WantsCard = "J" then WantsCard = "Jack" |
|||
if WantsCard = "q" || WantsCard = "Q" then WantsCard = "Queen" |
|||
$foe.losecards($request); |
|||
if WantsCard = "k" || WantsCard = "K" then WantsCard = "King" |
|||
$user.getcards($quantity, $request); |
|||
if WantsCard = "a" || WantsCard = "A" then WantsCard = "Ace" |
|||
} |
|||
if WantsCard = "0" then WantsCard = "10" |
|||
say '"Go fish!"'; |
|||
print "-------------------------------------" |
|||
$user.draw; |
|||
print |
|||
$foe.notice_draw; |
|||
str255 AorAn |
|||
last; |
|||
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 |
|||
while any |$foe.h { |
|||
my $request = $foe.choose_request; |
|||
say "\n\"Got any ", @ppips[$request], '?"'; |
|||
$foe.learn($request, No); |
|||
if $user.h[$request] -> $quantity is copy { |
|||
say '"Thanks!"'; |
|||
$foe.getcards($quantity, $request); |
|||
$user.losecards($request); |
|||
} |
|||
else { |
|||
say 'The dealer goes fishing.'; |
|||
$foe.draw; |
|||
last; |
|||
} |
|||
} |
|||
} |
|||
Someone = "CPU" |
|||
say "\nGame over!"; |
|||
For i = 1 To 13 |
|||
say 'Your books: ', $user.books; |
|||
asked(i) = 0 |
|||
say "The dealer's books: ", $foe.books; |
|||
Next i |
|||
say do |
|||
$user.books > $foe.books |
|||
?? 'A winner is you!' |
|||
!! $user.books < $foe.books |
|||
?? 'Alas, you have lost.' |
|||
# A draw is possible if @pips !% 2. |
|||
!! "It's a draw."; |
|||
bool CPUsTurn = _false |
|||
} |
|||
sub MAIN () { play }</lang> |
|||
=={{header|Python}}== |
|||
{{works with|Python|2.5}} |
|||
<lang Python>import random |
|||
import sys |
|||
from collections import defaultdict |
|||
class HumanPlayer(object): |
|||
def __init__(self,deck): |
|||
self.hand = defaultdict(int) |
|||
self.book = [] |
|||
self.deck = deck #making a copy of deck, all changes within |
|||
#this class should affect the global deck |
|||
self.score = 0 |
|||
self.name = raw_input('Name yourself: ') |
|||
def Draw(self): #assuming that deck is a global |
|||
cardDrawn = self.deck.pop() #removes the last card from deck |
|||
self.hand[cardDrawn] += 1 #adds card to hand |
|||
print '%s drew %s.' % (self.name,cardDrawn) |
|||
self.checkForBooks() |
|||
def checkForBooks(self): |
|||
# Removes all items of which are 4. |
|||
for key,val in self.hand.items(): #can't use iteritems() because we are modifying hand in loop |
|||
if val == 4: #completed a book |
|||
self.book.append(key) |
|||
print '%s completed the book of %s\'s.' % (self.name,key) |
|||
self.score += 1 |
|||
del self.hand[key] |
|||
self.emptyCheck() |
|||
def emptyCheck(self): |
|||
if len(self.deck)!=0 and len(self.hand)==0: #checks if deck/hand is empty |
|||
self.Draw() |
|||
def displayHand(self): #Displays current hand, cards separated by spaces |
|||
return ' '.join(key for key,val in self.hand.iteritems() |
|||
for i in range(val)) #meh, make it prettier |
|||
While CPUsTurn = _false |
|||
def makeTurn(self): |
|||
if fn CheckForEndGame = _True then cls:fn InitCards:goto "Loop" |
|||
print '%s\'s hand: %s' % (self.name,self.displayHand()) |
|||
chooseCard = raw_input('What card do you ask for? ').strip() |
|||
po = 0 |
|||
if chooseCard == 'quit': |
|||
For i = 1 To 13 |
|||
If (Computer(i) > 0) && (guess(i) > 0) Then poss(i) = 1: po += 1 |
|||
if chooseCard not in self.hand: |
|||
Next i |
|||
print 'You don\'t have that card. Try again! (or enter quit to exit)' |
|||
chooseCard = self.makeTurn() |
|||
short whilecounter |
|||
return chooseCard |
|||
WhileCounter = 0 |
|||
If po = 0 |
|||
// this k is the go fish card. |
|||
k = rnd(12) +1 |
|||
while Computer(k) = 0 || asked(k) |
|||
if card in self.hand: # if card in hand, returns count and removes the card from hand |
|||
whilecounter ++ |
|||
val = self.hand.pop(card) |
|||
k = rnd(12) +1 |
|||
if WhileCounter > 100 then k = 0: exit while //5/5/24 Rich added this to prevent hangs |
|||
return val |
|||
wend |
|||
return False |
|||
def gotCard(self,card,amount): |
|||
self.hand[card] += amount |
|||
self.checkForBooks() |
|||
class Computer(HumanPlayer): |
|||
def __init__(self,deck): |
|||
self.name = 'Computer' |
|||
self.hand = defaultdict(int) |
|||
self.book = [] |
|||
self.deck = deck |
|||
self.opponentHas = set() |
|||
self.score = 0 |
|||
def Draw(self): #assuming that deck is a global |
|||
cardDrawn = self.deck.pop() #removes the last card from deck |
|||
self.hand[cardDrawn] += 1 #adds card to hand |
|||
print '%s drew a card.' % (self.name) |
|||
self.checkForBooks() |
|||
##AI: guesses cards that knows you have, then tries cards he has at random. |
|||
##Improvements: remember if the card was rejected before, guess probabilities |
|||
def makeTurn(self): |
|||
# print self.displayHand(),self.opponentHas |
|||
candidates = list(self.opponentHas & set(self.hand.keys())) #checks for cards in hand that computer knows you have |
|||
if not candidates: |
|||
candidates = self.hand.keys() #if no intersection between those two, random guess |
|||
move = random.choice(candidates) |
|||
print '%s fishes for %s.' % (self.name,move) |
|||
return move |
|||
Else |
|||
def fishFor(self,card): #Same as for humans players, but adds the card fished for to opponentHas list. |
|||
self.opponentHas.add(card) |
|||
if card in self.hand: # if card in hand, returns count and removes the card from hand |
|||
val = self.hand.pop(card) |
|||
self.emptyCheck() |
|||
return val |
|||
else: |
|||
return False |
|||
k = rnd(12) + 1 |
|||
def gotCard(self,card,amount): |
|||
while poss(k) = 0 |
|||
self.hand[card] += amount |
|||
k = rnd(12) + 1 |
|||
if WhileCounter > 100 then k = 0: exit while //5/5/24 Rich added this to prevent hangs |
|||
self.checkForBooks() |
|||
wend |
|||
class PlayGoFish(object): |
|||
guess(k) = 0 |
|||
asked(k) = 1 |
|||
self.deck = ('2 3 4 5 6 7 8 9 10 J Q K A '*4).split(' ') |
|||
self.deck.remove('') |
|||
end if |
|||
self.player = [HumanPlayer(self.deck),Computer(self.deck)] #makes counting turns easier |
|||
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" |
|||
def endOfPlayCheck(self):#checks if hands/decks are empty using the any method |
|||
goto "Main" |
|||
return self.deck or self.player[0].hand or self.player[1].hand |
|||
def play(self): |
|||
random.shuffle(self.deck) |
|||
for i in xrange(9): # Deal the first cards |
|||
self.player[0].Draw() |
|||
self.player[1].Draw() |
|||
turn = 0 |
|||
while self.endOfPlayCheck(): |
|||
print '\nTurn %d (%s:%d %s:%d) %d cards remaining.' % (turn,self.player[0].name, |
|||
self.player[0].score,self.player[1].name,self.player[1].score,len(self.deck)) |
|||
whoseTurn = turn%2 |
|||
otherPlayer = (turn+1)%2 |
|||
while True: #loop until player finishes turn |
|||
cardFished = self.player[whoseTurn].makeTurn() |
|||
result = self.player[otherPlayer].fishFor(cardFished) |
|||
if not result: #Draws and ends turn |
|||
self.player[whoseTurn].Draw() |
|||
break |
|||
print '%s got %d more %s.' % (self.player[whoseTurn].name,result, cardFished) |
|||
self.player[whoseTurn].gotCard(cardFished,result) |
|||
if not self.endOfPlayCheck(): break |
|||
turn+=1 |
|||
print '\nScores: \n%s: %d\n%s: %d\n' % (self.player[0].name,self.player[0].score, |
|||
self.player[1].name,self.player[1].score) |
|||
if self.player[0].score>self.player[1].score: |
|||
print self.player[0].name,'won!' |
|||
elif self.player[0].score==self.player[1].score: |
|||
print 'Draw!' |
|||
else: |
|||
print self.player[1].name,'won!' |
|||
handleevents |
|||
if __name__=="__main__": |
|||
game = PlayGoFish() |
|||
game.play()</lang> |
|||
</syntaxhighlight> |
|||
=={{header|Ruby}}== |
|||
<lang ruby>class Card |
|||
RANKS = %w(2 3 4 5 6 7 8 9 10 J Q K A) |
|||
SUITS = %w(C D H S) |
|||
=={{header|Go}}== |
|||
def initialize(rank, suit) |
|||
See [[Go Fish/Go]] |
|||
@rank = rank |
|||
@suit = suit |
|||
end |
|||
attr_accessor :rank, :suit |
|||
=={{header|Haskell}}== |
|||
def <=>(other) |
|||
See [[Go Fish/Haskell]] |
|||
# this ordering sorts first by rank, then by suit |
|||
(RANKS.find_index(self.rank) <=> RANKS.find_index(other.rank)).nonzero? || |
|||
(SUITS.find_index(self.suit) <=> SUITS.find_index(other.suit)) |
|||
end |
|||
=={{header|Icon}} and {{header|Unicon}}== |
|||
def to_s |
|||
See [[Go Fish/Unicon]] |
|||
@rank + @suit |
|||
end |
|||
end |
|||
=={{header|J}}== |
|||
####################################################################### |
|||
See [[Go Fish/J]] |
|||
class Deck |
|||
def initialize |
|||
@deck = [] |
|||
Card::SUITS.each do |suit| |
|||
Card::RANKS.each do |rank| |
|||
@deck << Card.new(rank, suit) |
|||
end |
|||
end |
|||
@deck.shuffle! |
|||
end |
|||
attr_reader :deck |
|||
=={{header|Java}}== |
|||
# returns an array of cards, even for dealing just 1 card |
|||
See [[Go Fish/Java]] |
|||
def deal(n=1) |
|||
@deck.pop(n) |
|||
end |
|||
=={{header|Julia}}== |
|||
def empty? |
|||
see [[Go Fish/Julia]] |
|||
@deck.empty? |
|||
end |
|||
=={{header|Kotlin}}== |
|||
def cards_remaining |
|||
See [[Go Fish/Kotlin]] |
|||
@deck.length |
|||
end |
|||
end |
|||
=={{header|Lua}}== |
|||
####################################################################### |
|||
See [[Go Fish/Lua]] |
|||
class Player |
|||
def initialize(game) |
|||
@hand = {} |
|||
@books = [] |
|||
@game = game |
|||
@opponents_hand = { |
|||
:known_to_have => [], |
|||
:known_not_to_have => [], |
|||
} |
|||
end |
|||
attr_reader :name |
|||
=={{header|Locomotive Basic}}== |
|||
def take_cards(cards) |
|||
See [[Go Fish/Locomotive Basic]] |
|||
my_cards = @hand.values.flatten.concat(cards) |
|||
@hand = my_cards.group_by {|card| card.rank} |
|||
=={{header|Mathematica}} / {{header|Wolfram Language}}== |
|||
# look for, and remove, any books |
|||
See [[Go Fish/Mathematica]] |
|||
@hand.each do |rank, cards| |
|||
if cards.length == 4 |
|||
puts "#@name made a book of #{rank}" |
|||
@books << rank |
|||
@hand.delete(rank) |
|||
end |
|||
end |
|||
if @hand.length == 0 and not @game.deck.empty? |
|||
@game.deal(self, 1) |
|||
end |
|||
end |
|||
=={{header|Nim}}== |
|||
def num_books |
|||
See [[Go Fish/Nim]] |
|||
@books.length |
|||
end |
|||
=={{header|OCaml}}== |
|||
# return true if the next turn is still mine |
|||
See [[Go Fish/OCaml]] |
|||
# return false if the next turn is my opponent's |
|||
def query(opponent) |
|||
wanted = wanted_card |
|||
puts "#@name: Do you have a #{wanted}?" |
|||
received = opponent.answer(wanted) |
|||
@opponents_hand[:known_to_have].delete(wanted) |
|||
if received.empty? |
|||
@game.deal(self, 1) |
|||
# by my next turn, opponent will have been dealt a card |
|||
# so I cannot know what he does not have. |
|||
@opponents_hand[:known_not_to_have] = [] |
|||
false |
|||
else |
|||
take_cards(received) |
|||
@opponents_hand[:known_not_to_have].push(wanted).uniq! |
|||
true |
|||
end |
|||
end |
|||
=={{header|Perl}}== |
|||
def answer(rank) |
|||
<syntaxhighlight lang="perl">#!/usr/bin/perl |
|||
cards = [] |
|||
@opponents_hand[:known_to_have].push(rank).uniq! |
|||
if not @hand[rank] |
|||
puts "#@name: Go Fish!" |
|||
else |
|||
cards = @hand[rank] |
|||
@hand.delete(rank) |
|||
puts "#@name: Here you go -- #{cards.join(', ')}" |
|||
@game.deal(self, 1) if @hand.empty? |
|||
end |
|||
cards |
|||
end |
|||
use strict; # https://rosettacode.org/wiki/Go_Fish |
|||
def print_hand |
|||
use warnings; |
|||
puts "hand for #@name:" |
|||
use List::Util qw( first shuffle ); |
|||
puts " hand: "+ @hand.values.flatten.sort.join(', ') |
|||
puts " books: "+ @books.join(', ') |
|||
puts "opponent is known to have: " + @opponents_hand[:known_to_have].sort.join(', ') |
|||
end |
|||
end |
|||
my $pat = qr/[atjqk2-9]/; # ranks |
|||
####################################################################### |
|||
my $deck = join '', shuffle map { my $rank = $_; map "$rank$_", qw( S H C D ) } |
|||
class ComputerPlayer < Player |
|||
qw( a t j q k ), 2 .. 9; |
|||
def initialize(game) |
|||
super |
|||
@name = 'Computer' |
|||
end |
|||
my $mebooks = my $youbooks = 0; |
|||
def wanted_card |
|||
known = @hand.keys & @opponents_hand[:known_to_have] |
|||
if not known.empty? |
|||
sort_cards_by_most(known).first |
|||
else |
|||
possibilities = @hand.keys - @opponents_hand[:known_not_to_have] |
|||
if not possibilities.empty? |
|||
possibilities.shuffle.first |
|||
else |
|||
#sort_cards_by_most(@hand.keys).first |
|||
@hand.keys.shuffle.first |
|||
end |
|||
end |
|||
end |
|||
my $me = substr $deck, 0, 2 * 9, ''; |
|||
# sort ranks by ones with most cards in my hand. better chance to make a book |
|||
my $mepicks = join '', $me =~ /$pat/g; |
|||
def sort_cards_by_most(array_of_ranks) |
|||
arrange($me); |
|||
array_of_ranks.sort_by {|rank| 4 - @hand[rank].length} |
|||
$mebooks++ while $me =~ s/($pat).\1.\1.\1.//; |
|||
end |
|||
my $you = substr $deck, 0, 2 * 9, ''; |
|||
end |
|||
my $youpicks = join '', $you =~ /$pat/g; |
|||
arrange($you); |
|||
$youbooks++ while $you =~ s/($pat).\1.\1.\1.//; |
|||
while( $mebooks + $youbooks < 13 ) |
|||
####################################################################### |
|||
{ |
|||
class HumanPlayer < Player |
|||
play( \$you, \$youbooks, \$youpicks, \$me, \$mebooks, 1 ); |
|||
def initialize(game) |
|||
$mebooks + $youbooks == 13 and last; |
|||
super |
|||
play( \$me, \$mebooks, \$mepicks, \$you, \$youbooks, 0 ); |
|||
@name = 'Human' |
|||
} |
|||
print "me $mebooks you $youbooks\n"; |
|||
sub arrange { $_[0] = join '', sort $_[0] =~ /../g } |
|||
def take_cards(cards) |
|||
puts "#@name received: #{cards.join(', ')}" |
|||
super |
|||
end |
|||
sub human |
|||
def wanted_card |
|||
{ |
|||
print_hand |
|||
my $have = shift =~ s/($pat).\K(?!\1)/ /gr; |
|||
wanted = nil |
|||
local $| = 1; |
|||
my $pick; |
|||
print "\nWhat rank to ask for? " |
|||
do |
|||
wanted = $stdin.gets |
|||
{ |
|||
wanted.strip!.upcase! |
|||
print "You have $have, enter request: "; |
|||
if not Card::RANKS.include?(wanted) |
|||
($pick) = lc(<STDIN>) =~ /$pat/g; |
|||
puts "not a valid rank: #{wanted} -- try again." |
|||
} until $pick and $have =~ /$pick/; |
|||
elsif not @hand.keys.include?(wanted) |
|||
return $pick; |
|||
puts "you don't have a #{wanted} -- try again" |
|||
} |
|||
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 |
else |
||
{ |
|||
print "GO FISH !!\n"; |
|||
$$me .= substr $deck, 0, 2, ''; |
|||
end |
|||
$more = 0; |
|||
} |
|||
} |
|||
end |
|||
elsif( $deck ) |
|||
{ |
|||
$$me .= substr $deck, 0, 2, ''; |
|||
} |
|||
else |
|||
{ |
|||
$more = 0; |
|||
} |
|||
} |
|||
arrange( $$me ); |
|||
}</syntaxhighlight> |
|||
=={{header|Phix}}== |
|||
####################################################################### |
|||
See [[Go Fish/Phix]] |
|||
class GoFishGame |
|||
def initialize |
|||
@deck = Deck.new |
|||
@players = [HumanPlayer.new(self), ComputerPlayer.new(self)] |
|||
rotate_players if rand(2) == 1 |
|||
@players.each {|p| deal(p, 9)} |
|||
end |
|||
attr_reader :deck |
|||
=={{header|PicoLisp}}== |
|||
def start |
|||
See [[Go Fish/PicoLisp]] |
|||
loop do |
|||
p1, p2 = @players |
|||
# p1.query(p2) method returns true if p1 keeps his turn |
|||
# and returns false otherwise |
|||
p1.query(p2) or rotate_players |
|||
break if p1.num_books + p2.num_books == 13 |
|||
end |
|||
puts "==============================" # add a separator between turns |
|||
puts "Game over" |
|||
@players.each {|p| puts "#{p.name} has #{p.num_books} books"} |
|||
nil |
|||
end |
|||
=={{header|PowerShell}}== |
|||
def rotate_players |
|||
See [[Go Fish/PowerShell]] |
|||
@players.push(@players.shift) |
|||
puts "------------------------------" # add a separator between turns |
|||
end |
|||
=={{header|PureBasic}}== |
|||
def deal(player, n=1) |
|||
See [[Go Fish/PureBasic]] |
|||
if n > @deck.cards_remaining |
|||
n = @deck.cards_remaining |
|||
end |
|||
puts "Dealer: #{n} card(s) to #{player.name}" |
|||
player.take_cards(@deck.deal(n)) |
|||
end |
|||
end |
|||
=={{header|Python}}== |
|||
####################################################################### |
|||
See [[Go Fish/Python]] |
|||
# main |
|||
=={{header|Raku}}== |
|||
srand |
|||
(formerly Perl 6) |
|||
GoFishGame.new.start</lang> |
|||
See [[Go Fish/Raku]] |
|||
=={{header| |
=={{header|Red}}== |
||
<syntaxhighlight lang="red"> |
|||
{{works with|Tcl|8.6}} |
|||
Red [ |
|||
<lang tcl>package require Tcl 8.6 |
|||
Title: "Go Fish" |
|||
Author: "gltewalt" |
|||
# How to sort ranks |
|||
] |
|||
proc suitorder {a b} { |
|||
set a1 [lsearch -exact {2 3 4 5 6 7 8 9 10 J Q K A} $a] |
|||
chand: [] ;-- c and p = computer and player |
|||
set b1 [lsearch -exact {2 3 4 5 6 7 8 9 10 J Q K A} $b] |
|||
cguesses: [] |
|||
expr {$a1 - $b1} |
|||
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. |
|||
# Class to manage the deck of cards |
|||
oo::class create Deck { |
|||
variable deck |
|||
constructor {{packs 1}} { |
|||
set deck [list] |
|||
for {set p 0} {$p < $packs} {incr p} { |
|||
foreach suit {C D H S} { |
|||
foreach pip {2 3 4 5 6 7 8 9 10 J Q K A} { |
|||
lappend deck [list $pip $suit] |
|||
} |
|||
} |
|||
} |
|||
} |
} |
||
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 |
|||
method shuffle {} { |
|||
their next turn if their previous guess resulted |
|||
# Shuffle in-place |
|||
in a Go Fish. |
|||
for {set i [llength $deck]} {[incr i -1] > 0} {} { |
|||
set n [expr {int($i * rand())}] |
|||
set card [lindex $deck $n] |
|||
lset deck $n [lindex $deck $i] |
|||
lset deck $i $card |
|||
} |
|||
} |
} |
||
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 [ |
|||
method deal {num} { |
|||
clear-and-show 0 "" |
|||
incr num -1 |
|||
print [newline "Player cards:" newline sort phand newline] |
|||
set hand [lrange $deck 0 $num] |
|||
print ["Computer books:" cbooks] |
|||
set deck [lreplace $deck 0 $num] |
|||
print ["Player books:" pbooks newline] |
|||
return $hand |
|||
] |
|||
} |
|||
shuffle: function [deck [block!]] [deck: random deck] |
|||
method renderCard {card} { |
|||
string map {C \u2663 D \u2662 H \u2661 S \u2660 " " {}} $card |
|||
;------------- end of helper functions ----------------- |
|||
} |
|||
method print {hand} { |
|||
set prev {} |
|||
foreach card [my sortHand $hand] { |
|||
if {[lindex $card 0] ne $prev} { |
|||
if {$prev ne ""} {puts ""} |
|||
puts -nonewline \t[my renderCard $card] |
|||
} else { |
|||
puts -nonewline " [my renderCard $card]" |
|||
} |
|||
set prev [lindex $card 0] |
|||
} |
|||
puts "" |
|||
} |
|||
check-for-books: func [ |
|||
method sortHand {hand} { |
|||
{ |
|||
lsort -index 0 -command suitorder [lsort -index 1 $hand] |
|||
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 |
|||
proc empty {} { |
|||
clear-and-show 1.0 |
|||
return [expr {[llength $deck] == 0}] |
|||
"You have to have that rank in your hand to ask for it.^/Computers turn..." |
|||
} |
|||
exit |
|||
} |
|||
] |
|||
either find-in fhand kind [ |
|||
# "Abstract" class of all players; implements core game mechanics |
|||
check-for-books thand kind |
|||
# from a player's perspective |
|||
transfer-cards fhand thand kind |
|||
oo::class create GoFishPlayer { |
|||
show-cards |
|||
variable theDeck hand opponent |
|||
if find-in thand kind [ |
|||
constructor {deck otherPlayer} { |
|||
p: ask "Your guess: " |
|||
set theDeck $deck |
|||
either p = "x" [halt][player-turn fhand thand p] |
|||
set hand [$deck deal 9] |
|||
check-for-books thand p |
|||
set opponent $otherPlayer |
|||
] |
|||
][ |
|||
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. |
|||
method ask {rank} { |
|||
go-fish 3 phand |
|||
set response {} |
|||
show-cards |
|||
set new {} |
|||
] |
|||
foreach card $hand { |
|||
p: ask "Your guess: " |
|||
if {[lindex $card 0] eq $rank} { |
|||
either p = "x" [halt][player-turn chand phand find-in phand p] |
|||
lappend response $card |
|||
check-for-books phand p |
|||
} else { |
|||
show-cards |
|||
lappend new $card |
|||
] |
|||
} |
|||
main: does [ |
|||
set hand [expr {[llength $new] ? $new : [$theDeck deal 1]}] |
|||
deck: shuffle make-deck |
|||
return $response |
|||
deal-cards 9 chand |
|||
} |
|||
deal-cards 9 phand |
|||
method AskFor {rank} { |
|||
show-cards |
|||
set withoutOne 1 |
|||
while [cbooks + pbooks < 13][ |
|||
foreach card $hand { |
|||
game-round |
|||
] |
|||
set withoutOne 0 |
|||
clear-and-show 0 "" |
|||
break |
|||
print "GAME OVER" |
|||
} |
|||
print [newline "Computer books:" cbooks newline "Player books:" pbooks] |
|||
} |
|||
] |
|||
if {$withoutOne} { |
|||
error "do not have any $rank cards" |
|||
} |
|||
main |
|||
set response [$opponent ask $rank] |
|||
</syntaxhighlight> |
|||
if {[llength $response]} { |
|||
lappend hand {*}$response |
|||
} else { |
|||
my GoFish |
|||
lappend hand {*}[$theDeck deal 1] |
|||
} |
|||
=={{header|Rust}}== |
|||
return [llength $response] |
|||
See [[Go Fish/Rust]] |
|||
} |
|||
=={{header|Ruby}}== |
|||
method MakeBooks {} { |
|||
See [[Go Fish/Ruby]] |
|||
foreach rank {2 3 4 5 6 7 8 9 10 J Q K A} { |
|||
set n {} |
|||
set idx -1 |
|||
foreach card $hand { |
|||
incr idx |
|||
if {[lindex $card 0] eq $rank} { |
|||
lappend n $idx |
|||
} |
|||
} |
|||
if {[llength $n] == 4} { |
|||
announceBook $rank [self] |
|||
foreach idx [lreverse $n] { |
|||
set hand [lreplace $hand $idx $idx] |
|||
} |
|||
} |
|||
} |
|||
if {[llength $hand] == 0} { |
|||
set hand [$theDeck deal 1] |
|||
} |
|||
} |
|||
=={{header|Tcl}}== |
|||
method makeAPlay {} { |
|||
See [[Go Fish/Tcl]] |
|||
set msg "" |
|||
while {$::books(total) < 13} { |
|||
set rank [my SelectRank $msg] |
|||
try { |
|||
if {![my AskFor $rank]} { |
|||
my YieldToOpponent |
|||
break |
|||
} |
|||
} on error msg { |
|||
# Back round the loop with an error message |
|||
} on ok {} { |
|||
my MakeBooks |
|||
set msg "" |
|||
} |
|||
} |
|||
my MakeBooks |
|||
} |
|||
=={{header|V (Vlang)}}== |
|||
method GoFish {} { |
|||
See [[Go Fish/V (Vlang)]] |
|||
# Do nothing with this notification by default |
|||
} |
|||
method madeBook {rank who} { |
|||
# Do nothing with this notification by default |
|||
} |
|||
method YieldToOpponent {} { |
|||
# Do nothing with this notification by default |
|||
} |
|||
method SelectRank {msg} { |
|||
error "not implemented" |
|||
} |
|||
} |
|||
=={{header|Wren}}== |
|||
# A player that works by communicating with a human |
|||
See [[Go Fish/Wren]] |
|||
oo::class create HumanPlayer { |
|||
superclass GoFishPlayer |
|||
variable theDeck hand opponent |
|||
method madeBook {rank who} { |
|||
if {$who eq [self]} {set who "You"} |
|||
puts "$who made a book of $rank" |
|||
} |
|||
method YieldToOpponent {} { |
|||
puts "Now your opponent's turn" |
|||
} |
|||
method AskFor {rank} { |
|||
set count [next $rank] |
|||
puts "You asked for ${rank}s and received $count cards" |
|||
if {$count > 0} { |
|||
puts "You may ask again!" |
|||
} |
|||
return $count |
|||
} |
|||
method ask {rank} { |
|||
set cards [next $rank] |
|||
puts "[namespace tail $opponent] asked for $rank cards, and got [llength $cards] of them" |
|||
return $cards |
|||
} |
|||
method GoFish {} { |
|||
puts "You were told to \"Go Fish!\"" |
|||
} |
|||
method SelectRank {msg} { |
|||
if {$msg ne ""} { |
|||
puts "ERROR: $msg" |
|||
} |
|||
set I [namespace tail [self]] |
|||
puts "You are ${I}: Your cards are:" |
|||
$theDeck print $hand |
|||
while 1 { |
|||
puts -nonewline "What rank to ask for? " |
|||
flush stdout |
|||
set rank [string toupper [gets stdin]] |
|||
if {$rank in {2 3 4 5 6 7 8 9 10 J Q K A}} { |
|||
return $rank |
|||
} |
|||
puts "Rank must be 2, 3, 4, 5, 6, 7, 8, 9, 10, J, Q, K, or A" |
|||
puts "You must also have at least one of them already" |
|||
} |
|||
} |
|||
} |
|||
# A computer player that tracks what it's opponent must have |
|||
oo::class create ThinkingPlayer { |
|||
superclass GoFishPlayer |
|||
variable state hand |
|||
constructor args { |
|||
next {*}$args |
|||
foreach rank {2 3 4 5 6 7 8 9 10 J Q K A} { |
|||
set state($rank) unknown |
|||
} |
|||
} |
|||
method madeBook {rank who} { |
|||
set state($rank) booked |
|||
} |
|||
method AskFor {rank} { |
|||
set count [next $rank] |
|||
set state($rank) none |
|||
if {$count == 0} { |
|||
foreach rank {2 3 4 5 6 7 8 9 10 J Q K A} { |
|||
if {$state($rank) eq "none"} { |
|||
set state($rank) unknown |
|||
} |
|||
} |
|||
} |
|||
return $count |
|||
} |
|||
method ask {rank} { |
|||
set cards [next $rank] |
|||
set state($rank) some |
|||
return $cards |
|||
} |
|||
method GoFish {} { |
|||
puts "You told your opponent to \"Go Fish!\"" |
|||
} |
|||
method SelectRank {ignored} { |
|||
# If we know they have the cards and we can grab them, do so! |
|||
# It's a safe move since we get to go again. |
|||
foreach {rank s} [array get state] { |
|||
if {$s eq "some" && [lsearch -exact -index 0 $hand $rank] >= 0} { |
|||
return $rank |
|||
} |
|||
} |
|||
# Only unsafe moves remain; pick a random non-stupid one |
|||
foreach c $hand { |
|||
set rank [lindex $c 0] |
|||
if {$state($rank) ne "none"} { |
|||
set r([lindex $c 0]) . |
|||
} |
|||
} |
|||
if {[array size r]} { |
|||
return [lindex [array names r] [expr {int([array size r]*rand())}]] |
|||
} |
|||
# No good choices; oh well... |
|||
return [lindex $hand [expr {int([llength $hand]*rand())}] 0] |
|||
} |
|||
} |
|||
# How announcements of a book being made are done |
|||
proc announceBook {rank who} { |
|||
global books |
|||
A madeBook $rank $who |
|||
B madeBook $rank $who |
|||
lappend books($who) $rank |
|||
incr books(total) |
|||
} |
|||
# Stitch things together to make a whole game. |
|||
Deck create deck |
|||
deck shuffle |
|||
array set books {total 0 ::A {} ::B {}} |
|||
HumanPlayer create A deck B |
|||
ThinkingPlayer create B deck A |
|||
while {$books(total) < 13} { |
|||
A makeAPlay |
|||
if {$books(total) < 13} { |
|||
B makeAPlay |
|||
} |
|||
} |
|||
puts "You have [llength $books(::A)]: [lsort -command suitorder $books(::A)]" |
|||
puts "The computer has [llength $books(::B)]: [lsort -command suitorder $books(::B)]" |
|||
if {[llength $books(::A)] > [llength $books(::B)]} { |
|||
puts "You win!" |
|||
} else { |
|||
puts "The computer won!" |
|||
}</lang> |
|||
{{omit from|XSLT|XSLT lacks standard interactive I/O and pseudorandom number generation facilities.}} |
|||
===Notes on the Mechanical Player=== |
|||
The computer player (implemented as a subclass of the generic player class) has four states for ''each'' rank (aside from basic overall state like what cards it is holding, which every player has to have): |
|||
;unknown |
|||
: Don't know if the opponent has any cards in that rank. |
|||
;none |
|||
: Opponent has no cards there; I took them away. |
|||
;some |
|||
: Opponent has cards there; they tried to get them off me and haven't booked them yet. |
|||
;booked |
|||
: Someone has booked the rank. |
|||
It prefers to take cards away from the opponent if it can and tries hard to avoid moves it knows will fail. It never makes illegal moves. It does not bother to look at the number of booked suits, though as that is global state it ''could''. No player or the deck has any method to reveal (within the game world, not the display) what hand of cards it actually has. |
Revision as of 23:33, 6 May 2024
You are encouraged to solve this task according to the task description, using any language you may know.
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.
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
Translated from FreeBasic May 5, 2024 Rich Love Fixed intermittent hang Also, now using && and || to be compatible with later versions of FutureBasic. ( replaces AND and OR )
/*
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 || 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 " || 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