Expand description
§Gin Rummy Engine
Bots and strategy tooling for gin rummy, built on the gin-rummy mechanics crate. Where gin-rummy answers “what moves are legal?”, this crate answers “which move should I make?”
The design triangle:
Strategy: a decision procedure for one seat — take or pass the upcard, where to draw, what to shed, whether to knock, what to lay off.View: the information a seat may legally see. The underlyingRoundexposes both hands and the stock order; strategies never touch it. AViewshows only the seat’s own hand, the discard pile, the stock count, and what the opponent has revealed (cards taken from the pile, discards, declined upcards).Table: the driver. It owns theRound, tracks each seat’s knowledge, asks strategies for decisions, and applies them — so information hygiene holds by construction.
§Bots
HeuristicBot: deterministic and fast. Draws from the pile only when that strictly lowers deadwood, sheds the least useful card weighted by how dangerous it is to the opponent, knocks by a configurable threshold, and lays off greedily but never breaks its own melds.MonteCarloBot(featurerand): determinized Monte Carlo. At each decision it samples hidden worlds consistent with theView— opponent hands containing every known card, random stock orders over the unseen cards — rolls each out with the greedy policy, and picks the action with the best expected score.
§Quick start
A bot-vs-bot round needs no features:
use gin_rummy::{Hand, Player, Round, Rules};
use gin_rummy_engine::{HeuristicBot, play_round};
let hands: [Hand; 2] = ["A23.456.789.T".parse()?, "TJQK.A23.456.".parse()?];
let (upcard, stock) = (rest[0], rest[1..].to_vec()); // the other 32 cards
let round = Round::from_deal(Rules::default(), Player::One, hands, upcard, stock)?;
let result = play_round(round, [&mut HeuristicBot::new(), &mut HeuristicBot::new()])?;
println!("{result:?}");With the (default) rand feature, deal and settle whole games:
use gin_rummy::{Game, Player, Rules};
use gin_rummy_engine::{HeuristicBot, MonteCarloBot, play_game};
let mut rules = Rules::default();
let mut game = Game::new(rules, Player::One);
let mut greedy = HeuristicBot::new();
let mut mc = MonteCarloBot::new(rand::rng()).samples(8);
let score = play_game(&mut game, [&mut greedy, &mut mc], &mut rand::rng())?;
println!("{} wins {} : {}", score.winner, score.totals[0], score.totals[1]);Writing your own bot is implementing Strategy’s four decisions against a
View; the driver handles all bookkeeping.
§Feature flags
rand(default): the Monte Carlo bot,Table::deal,play_game, and the examples. Disable it for a dependency-free heuristic-only build.
§Examples
play: play against a bot in the terminal —cargo run --example play(--bot mc,--rules classic, …)arena: bot-vs-bot tournaments with win-rate statistics —cargo run --release --example arena -- --rounds 1000 --p1 greedy --p2 mc:64
Re-exports§
pub use gin_rummy;
Structs§
- Heuristic
Bot - A deterministic knowledge-based player
- Heuristic
Config - Tuning knobs for
HeuristicBot - Layoff
- One layoff onto the knocker’s spread
- Monte
Carlo Bot - A determinized Monte Carlo player
- Table
- A round in progress, with per-seat knowledge tracking
- View
- What one seat may legally see of a round
Enums§
- Draw
Action - Where to draw at the start of a normal turn
- Engine
Error - An error while driving a round
- Turn
Action - How to end a turn from an 11-card hand
- Upcard
Action - Response to the initial upcard offer
Traits§
- Strategy
- A decision procedure for one seat of gin rummy
Functions§
- play_
game - Deal and play rounds until the game is over, returning the settled score
- play_
round - Play one round to completion, one strategy per seat, indexed by
Player