Expand description
§Gin Rummy
This crate models the mechanics of gin rummy: strongly typed cards and melds, an exact deadwood solver, and a rules-driven state machine for complete two-player rounds and games.
Gin rummy ranks the ace LOW: A-2-3 is a run, Q-K-A is not, and an ace counts
one point of deadwood. Rank therefore encodes A = 1 through K = 13, unlike
crates for ace-high games such as contract-bridge whose patterns this crate
otherwise follows.
Hands are written as four dot-separated suit groups in ascending order,
clubs first: "A23.456.789.T" holds ♣A ♣2 ♣3 ♦4 ♦5 ♦6 ♥7 ♥8 ♥9 ♠10.
§Modules
hand: cards and card sets —Suit,Rank,Card,Holding,Handmeld: sets, runs, and the deadwood solver —Meld,Melds,best_melds,deadwoodround: one deal from upcard to showdown —Round,Phase,RoundResultgame: the scoreboard across deals —Game,FinalScorerules: scoring configuration —Rules,Shutoutdeck(featurerand): shuffled dealing —Deck
§Feature flags
rand: shuffled dealing (Deck,Round::deal,Game::deal)serde: serialization for every public type, with validated deserialization of mid-gameRoundsnapshots
§Quick start
Deadwood analysis needs no features:
use gin_rummy::{best_melds, deadwood};
let hand = "A23.456.789.T".parse::<gin_rummy::Hand>()?;
assert_eq!(deadwood(hand), 10);
println!("{}", best_melds(hand));A complete bot-vs-bot game with the rand feature:
use gin_rummy::{Game, Player, Rules};
let mut game = Game::new(Rules::default(), Player::One);
while !game.is_over() {
let mut round = game.deal(&mut rand::rng());
drive(&mut round); // pass / draw / discard / knock / lay_off …
game.record(round.result().expect("round finished")).unwrap();
}
println!("{:?}", game.final_score());§Examples
deadwood: parse hands from the command line and print their best melds —cargo run --example deadwood -- "45.456.567.789"simulate: greedy bots play a full game —cargo run --features rand --example simulate
§Alternatives
Open-source gin rummy mostly lives inside research frameworks rather than reusable libraries:
- OpenSpiel’s
gin_rummy(C++/Python) has thoroughly tested single-hand rules with an Oklahoma option — but plays isolated hands only, with no match play: games to 100, boxes, shutouts, and dealer rotation are out of its scope. - RLCard’s environment (Python) targets reinforcement learning; its deal and rewards deviate from table rules (an 11-card opening deal, no undercut bonus).
- gin-rummy-eaai (Java) is the minimal framework behind the EAAI-2021 Gin Rummy AI challenge and its 13 papers — the academic reference point, though dormant since 2020 and unlicensed.
This crate aims to be the reusable one: a dependency-free core, an exact solver, a validated state machine covering complete matches, and school-by-school rule knobs including Oklahoma gin. Bots and strength benchmarks live in the sibling gin-rummy-engine crate.
Re-exports§
pub use game::FinalScore;pub use game::Game;pub use hand::Card;pub use hand::Hand;pub use hand::Holding;pub use hand::Rank;pub use meld::Meld;pub use meld::MeldKind;pub use meld::Melds;pub use meld::best_melds;pub use meld::deadwood;pub use meld::pip_sum;pub use player::Player;pub use round::Phase;pub use round::Round;pub use round::RoundResult;pub use rules::OklahomaAce;pub use rules::Rules;pub use rules::Shutout;
Modules§
- deck
- Random card shuffling and dealing.
- game
- The scoreboard across deals.
- hand
- Card primitives: ranks, cards, holdings, and hands.
- meld
- Melds, arrangements, and the exact deadwood solver.
- player
- The two players of gin rummy.
- round
- One deal of gin rummy, from the opening upcard to the showdown.
- rules
- Scoring configuration.
Structs§
- Parse
Suit Error - Error returned when parsing a
Suitfails
Enums§
- Suit
- A suit of playing cards