#hold-em #poker #variant #position #plo

bin+lib deadhand

A poker game library for Texas Hold'em and other poker variants

1 unstable release

new 0.1.0 Apr 27, 2025

#96 in Games

MIT/Apache

74KB
1.5K SLoC

Deadman

A Rust poker library for simulating Texas Hold'em and Omaha poker variants.

Overview

Deadman is a comprehensive poker game library designed to create, simulate, and analyze poker games. It supports multiple poker variants including:

  • No-Limit Texas Hold'em
  • Pot-Limit Omaha (4-card)
  • Pot-Limit Omaha (5-card)
  • Pot-Limit Omaha (6-card)

Features

  • Create and manage poker games with customizable rules
  • Add and remove players with specific seat positions
  • Deal cards and handle betting rounds
  • Process player actions (bet, call, raise, fold, check)
  • Support for side pots and all-in situations
  • Evaluate hands and determine winners
  • Run the board multiple times after all-ins
  • Game state snapshots for persistence/database storage
  • JSON serialization support

Installation

Add this to your Cargo.toml:

[dependencies]
deadman = { path = "path/to/deadman" }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0" # For JSON serialization

Usage Examples

Basic Texas Hold'em Game

use deadman::{
    action::Action,
    game::Game,
    rules::GameRules,
};

fn main() {
    // Create a No-Limit Hold'em game with 10/20 blinds
    let rules = GameRules::nlhe(10, 20);
    let mut game = Game::new(rules);

    // Add players
    game.add_player_to_seat("Alice".to_string(), 1000, 0).unwrap();
    game.add_player_to_seat("Bob".to_string(), 1000, 1).unwrap();

    // Start a hand
    game.start_hand().unwrap();
    
    // Preflop action
    game.handle_action(Action::Call).unwrap();  // Bob calls
    game.handle_action(Action::Check).unwrap(); // Alice checks
    
    // Deal flop
    game.next_street().unwrap();
    println!("Flop: {:?}", game.community_cards);
    
    // Flop action
    game.handle_action(Action::Check).unwrap(); // Alice checks
    game.handle_action(Action::Bet(50)).unwrap(); // Bob bets
    game.handle_action(Action::Call).unwrap(); // Alice calls
    
    // Deal turn
    game.next_street().unwrap();
    println!("Turn: {:?}", game.community_cards);
    
    // Continue with the game...
}

Running the Board Multiple Times

// After players are all-in
match game.run_multiple_times(3) {
    Ok(result) => {
        // Display results for each run
        for (i, run) in result.runs.iter().enumerate() {
            println!("Run #{}: {:?}", i+1, run.community_cards);
            println!("Winners: {:?}", run.winning_player_indices);
        }
        
        // Distribute pot based on win percentages
        game.complete_with_multiple_runs(3).unwrap();
    },
    Err(e) => println!("Error: {}", e),
}

Side Pots and All-In Situations

The library handles uneven stack sizes and creates appropriate side pots when players go all-in:

// Create a game with varying stack sizes
let rules = GameRules::nlhe(10, 20);
let mut game = Game::new(rules);

game.add_player_to_seat("Alice".to_string(), 1000, 0).unwrap();
game.add_player_to_seat("Bob".to_string(), 500, 1).unwrap();
game.add_player_to_seat("Charlie".to_string(), 200, 2).unwrap();

game.start_hand().unwrap();

// Preflop action
game.handle_action(Action::Call).unwrap();  // Charlie calls
game.handle_action(Action::Raise(200)).unwrap(); // Alice raises

// Bob goes all-in with his 500 chips
game.handle_action(Action::Raise(500)).unwrap();

// Charlie goes all-in with his smaller stack (200 chips)
game.handle_action(Action::Call).unwrap();

// Alice calls
game.handle_action(Action::Call).unwrap();

// Side pots will be automatically calculated
// - Main pot: 600 (200 × 3 players)
// - Side pot 1: 600 (300 × 2 players, Alice and Bob)

// When the hand completes, pots are awarded to appropriate winners
game.next_street().unwrap(); // Flop
game.next_street().unwrap(); // Turn
game.next_street().unwrap(); // River
game.next_street().unwrap(); // Showdown - side pots distributed automatically

The library handles:

  • Players with different stack sizes
  • Calculating correct side pots when players are all-in
  • Evaluating each pot separately and awarding to appropriate winners
  • Special handling for heads-up play
  • Running the board multiple times with side pot distribution

Game State Snapshots

The library provides a robust snapshot system for saving and restoring game state. This is useful for:

  • Persisting games in a database
  • Creating game history and replays
  • Supporting game recovery after crashes
  • Analytics and post-game analysis
use deadman::{
    game::{Game, GameSnapshot},
    // other imports...
};
use serde_json;

// Take a snapshot of the current game state
let snapshot = game.get_snapshot();

// Serialize to JSON for database storage
let json = serde_json::to_string_pretty(&snapshot).unwrap();
// Save json to database...

// Later, restore the game from the snapshot
let loaded_snapshot: GameSnapshot = serde_json::from_str(&json).unwrap();
let restored_game = Game::from_snapshot(loaded_snapshot);

// Continue the game from where it was saved
restored_game.handle_action(Action::Check).unwrap();
// ...

The snapshot includes comprehensive state information:

  • Game rules and current stage
  • Player information (chips, hands, bet amounts)
  • Community cards and pot size
  • Dealer position and active player
  • Deck state (for accurate game restoration)
  • Side pot information

Library Structure

  • Game: Main class for poker game management
  • Player: Represents a player in the game
  • Card: Represents a playing card
  • Deck: Manages the deck of cards
  • Action: Available player actions (call, bet, fold, etc.)
  • GameRules: Configure game variants and limits
  • GameStage: Game stages (preflop, flop, turn, river, showdown)
  • GameSnapshot: For saving/loading game state

Game Variants

Create different game variants using these constructors:

// No-Limit Hold'em
let nlhe = GameRules::nlhe(small_blind, big_blind);

// Pot-Limit Omaha (4-card)
let plo4 = GameRules::plo4(small_blind, big_blind);

// 5-card PLO
let plo5 = GameRules::plo5(small_blind, big_blind);

// 6-card PLO
let plo6 = GameRules::plo6(small_blind, big_blind);

Examples

The library includes several examples:

  • basic_game.rs: Simple Texas Hold'em game example
  • run_it_multiple_times.rs: Demonstrates running the board multiple times
  • game_snapshot.rs: Shows how to save and restore game state
  • omaha_variants.rs: Examples of different Omaha variants
  • seat_selection.rs: Player seat selection and management

Run examples with:

cargo run --example game_snapshot

License

MIT License

Copyright (c) 2023

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Dependencies

~0.9–1.8MB
~38K SLoC