go-fish
A pure Rust library implementing the core engine for the classic Go Fish card game.
Features
- Complete game logic: dealing, turn resolution, book completion, player elimination, and win detection
- Serialization-ready — all public types derive
serde::Serialize/Deserialize - Instrumented with
tracingfor debug-level turn logging - No async, no I/O — plain library crate, suitable for embedding in any host (server, TUI, WASM, etc.)
Quick start
use ;
let deck = new.shuffle;
let mut game = new;
while !game.is_finished
let result = game.get_game_result.unwrap;
println!;
API overview
Types
| Type | Description |
|---|---|
Card |
A single playing card (suit, rank). Copy. |
Suit |
Clubs, Diamonds, Hearts, Spades. |
Rank |
Two through Ace. Implements Ord and Display. |
Deck |
A 52-card deck. Call .shuffle() before passing to Game::new. |
Hand |
A player's in-hand cards, grouped into IncompleteBooks by rank. |
IncompleteBook |
1–3 cards of the same rank. |
CompleteBook |
All 4 cards of a rank. Contributes to a player's score. |
Player |
An active player: ID, hand, and completed books. |
InactivePlayer |
An eliminated player (empty hand, deck exhausted). Still scored at game end. |
PlayerId |
Newtype wrapper around u8. |
Hook |
A turn action: ask target for all cards of rank. |
Game |
Top-level game state. |
Game::new(deck: Deck, player_count: u8) -> Game
Creates a game and deals initial hands (7 cards for 2–3 players, 5 cards otherwise). Completes any initial books before returning.
Game::take_turn(hook: Hook) -> Result<HookResult, TurnError>
The single method that advances game state. Returns:
Ok(HookResult::Catch(book))— the target held cards of the requested rank; they're transferred to the current player.Ok(HookResult::GoFish)— the target had nothing; the current player draws from the deck.Err(TurnError::TargetNotFound(id))— the target ID doesn't refer to an active player.Err(TurnError::GameIsFinished)— the game is already over.
After each turn the engine automatically handles book completion, player elimination (empty hand → draw or become inactive), and win detection.
Game::get_current_player() -> Option<&Player>
Returns the player whose turn it is, or None if the game is finished.
Game::get_game_result() -> Option<GameResult>
Returns winners and losers by completed-book count once game.is_finished is true.
Bots
The go_fish::bots module provides a Bot trait and a bundled SimpleBot implementation for driving automated players.
Bot trait
After each turn the host calls observe with a BotObservation (own hand, opponent hand sizes, completed books, deck size, last hook outcome), then calls generate_hook when it's the bot's turn.
SimpleBot
A probability-table bot. Construct with:
use SimpleBot;
let bot = new;
It builds a (opponent, rank) → probability table from retained observations, updates it using inference rules (Catch / GoFish outcomes), adds configurable noise, then picks the highest-scoring (target, rank) pair from the bot's current hand.
Testing
Integration tests in tests/complete_games.rs simulate up to 10,000 random turns for each player count (2–6) and assert the game terminates correctly.
License
MIT