Go Fish โ€” Design Document (Pseudocode)

Overview

The game is split into four logical modules: Card, Player, Game, and Main. Each module owns a clear slice of responsibility. The design supports 2โ€“6 players (human and/or AI) in a CLI environment.


Module: Card

Owns the raw building blocks โ€” suits, ranks, individual cards, the deck, and a player's hand.


Enum: Suit

1Suit = { Spades, Hearts, Diamonds, Clubs }

Enum: Rank

1Rank = { Ace, Two, Three, Four, Five, Six, Seven,
2         Eight, Nine, Ten, Jack, Queen, King }

Object: Card

1Card
2  properties:
3    rank : Rank
4    suit : Suit
5
6  methods:
7    toString() โ†’ "Ace of Spades"
8    toShortString() โ†’ "Aโ™ "

Object: Deck

 1Deck
 2  properties:
 3    cards : list of Card
 4
 5  methods:
 6    create()
 7      -- build one Card for every (Rank, Suit) combination โ†’ 52 cards total
 8
 9    shuffle()
10      -- randomize card order in place
11
12    deal(n) โ†’ list of Card
13      -- remove and return the top n cards
14      -- error if fewer than n cards remain
15
16    drawOne() โ†’ Card or null
17      -- remove and return the top card
18      -- return null if deck is empty
19
20    size() โ†’ number
21    isEmpty() โ†’ boolean

Object: Hand

 1Hand
 2  properties:
 3    cards : list of Card
 4
 5  methods:
 6    add(cards)
 7      -- append one or more cards to the hand
 8
 9    hasRank(rank) โ†’ boolean
10      -- return true if at least one card of this rank exists
11
12    takeByRank(rank) โ†’ list of Card
13      -- remove and return all cards matching rank
14
15    collectBooks() โ†’ list of Rank
16      -- find every rank that appears exactly 4 times
17      -- remove those cards from the hand
18      -- return the list of completed ranks
19
20    size() โ†’ number
21    isEmpty() โ†’ boolean
22    toString() โ†’ human-readable card list

Module: Player

Manages player identity, their hand, their completed books, and AI decision-making.


Object: Player

 1Player
 2  properties:
 3    id       : number
 4    name     : string
 5    hand     : Hand
 6    books    : list of Rank    -- completed four-of-a-kind sets
 7    isHuman  : boolean
 8
 9  methods:
10    bookCount() โ†’ number
11      -- return length of books list
12
13    recordBook(rank)
14      -- append rank to books
15
16    score() โ†’ number
17      -- same as bookCount, used at end of game
18
19    -- AI only --
20
21    chooseRank() โ†’ Rank
22      -- pick the rank in hand with the most copies
23      -- (ties broken randomly)
24
25    chooseTarget(otherPlayers) โ†’ Player
26      -- pick a random opponent who still has cards

Module: Game

The rules engine. Controls turn flow, enforces Go Fish rules, and tracks overall game state.


Enum: Phase

1Phase = { Ask, GoFish, GameOver }

Object: TurnResult

 1TurnResult
 2  properties:
 3    asker          : Player
 4    target         : Player
 5    rankAsked      : Rank
 6    cardsReceived  : list of Card   -- cards transferred from target โ†’ asker
 7    wentFishing    : boolean        -- true if target had no matching cards
 8    drawnCard      : Card or null   -- card drawn when fishing (null if deck empty)
 9    booksScored    : list of Rank   -- any books completed this turn
10    turnEnds       : boolean        -- false means asker gets to go again

Object: Game

 1Game
 2  properties:
 3    players       : list of Player
 4    deck          : Deck
 5    currentIndex  : number    -- index of the active player
 6    phase         : Phase
 7    history       : list of TurnResult
 8
 9  methods:
10    create(playerNames, humanFlags)
11      -- validate 2โ€“6 players
12      -- build Player objects
13      -- create and shuffle the Deck
14
15    start()
16      -- deal 7 cards each for 2 players, 5 cards each for 3โ€“6 players
17      -- collect any opening books from starting hands
18      -- set phase = Ask
19
20    currentPlayer() โ†’ Player
21      -- return players[currentIndex]
22
23    ask(targetIndex, rank) โ†’ TurnResult
24      -- validate phase is Ask
25      -- validate targetIndex is a different, eligible player
26      -- validate rank exists in asker's hand
27
28      -- if target has rank:
29         cards = target.hand.takeByRank(rank)
30         asker.hand.add(cards)
31         books = asker.hand.collectBooks()
32         record any new books on asker
33         set turnEnds = false   (asker goes again)
34
35      -- if target does not have rank:
36         set phase = GoFish
37         set wentFishing = true
38         set turnEnds = true
39
40      -- build and store TurnResult
41      -- if turnEnds: call advanceTurn()
42      -- return TurnResult
43
44    goFish() โ†’ TurnResult
45      -- validate phase is GoFish
46      -- draw one card from deck
47      -- add card to asker's hand
48      -- check for new book
49      -- set phase = Ask
50      -- advanceTurn()
51      -- return TurnResult
52
53    advanceTurn()
54      -- move currentIndex to the next player who still has cards
55      -- if no eligible players remain: set phase = GameOver
56
57    isOver() โ†’ boolean
58      -- return true when deck is empty AND all hands are empty
59
60    winners() โ†’ list of Player
61      -- return the player(s) with the highest book count
62
63    scores() โ†’ map of name โ†’ bookCount
64
65    eligiblePlayers() โ†’ list of Player
66      -- return players who still have cards in hand

Module: Main

Entry point and CLI loop. Handles input/output, leaving all rule logic to Game.


Functions

 1main()
 2  game = setupGame()
 3  game.start()
 4  runGameLoop(game)
 5
 6setupGame() โ†’ Game
 7  -- prompt for number of players
 8  -- prompt for each player's name and whether they are human or AI
 9  -- return Game.create(names, humanFlags)
10
11runGameLoop(game)
12  -- loop until game.isOver():
13       printState(game)
14       takeTurn(game)
15  -- printFinalScores(game)
16
17takeTurn(game)
18  -- if currentPlayer is human: humanTurn(game)
19  -- else: aiTurn(game)
20
21humanTurn(game)
22  -- display hand to the player
23  -- prompt: choose a target player
24  -- prompt: choose a rank to ask for
25  -- result = game.ask(targetIndex, rank)
26  -- printResult(result)
27  -- if result.wentFishing:
28       result = game.goFish()
29       printResult(result)
30
31aiTurn(game)
32  -- target = currentPlayer.chooseTarget(otherPlayers)
33  -- rank   = currentPlayer.chooseRank()
34  -- result = game.ask(target, rank)
35  -- printResult(result)
36  -- if result.wentFishing:
37       result = game.goFish()
38       printResult(result)
39
40printState(game)
41  -- show current player's name
42  -- show human player's hand (hide AI hands)
43  -- show book counts for all players
44  -- show cards remaining in deck
45
46printResult(result)
47  -- narrate what happened: who asked whom, for what, and the outcome
48
49printFinalScores(game)
50  -- display winner(s) and full score table

Data Flow Summary

 1main
 2 โ””โ”€โ”€ setupGame()       โ†’ creates Game
 3 โ””โ”€โ”€ game.start()      โ†’ shuffle + deal
 4 โ””โ”€โ”€ runGameLoop()
 5      โ””โ”€โ”€ takeTurn()
 6           โ”œโ”€โ”€ humanTurn()  or  aiTurn()
 7           โ”‚    โ””โ”€โ”€ game.ask(target, rank)
 8           โ”‚         โ”œโ”€โ”€ success โ†’ cards transferred, check books
 9           โ”‚         โ”‚             turnEnds = false โ†’ ask again
10           โ”‚         โ””โ”€โ”€ "Go Fish" โ†’ phase = GoFish
11           โ”‚              โ””โ”€โ”€ game.goFish() โ†’ draw card, check book
12           โ”‚                                  advanceTurn()
13           โ””โ”€โ”€ (repeat until game.isOver())

Key Design Decisions

Turn continuation. When a player receives cards they ask again immediately. TurnResult.turnEnds signals whether the turn passes, keeping this logic inside Game rather than in the UI.

Book detection. hand.collectBooks() is called automatically after any cards are added, so the hand is always in a valid state.

AI extensibility. chooseRank and chooseTarget live on Player, making it easy to swap in a smarter strategy (e.g. memory of past asks) without touching Game.

Phase gating. ask and goFish validate the current phase before executing, preventing invalid sequences of calls regardless of how the UI is built.