# Poker Simulation Testbed [![Crates.io](https://img.shields.io/crates/v/holdem_core.svg)](https://crates.io/crates/holdem_core) [![Documentation](https://docs.rs/holdem_core/badge.svg)](https://docs.rs/holdem_core) [![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) A comprehensive poker simulation testbed and unit test framework for bot development. Features two Rust-native hand evaluators — the **Cactus Kev** perfect-hash evaluator (~100 KB tables) and the **Supersonic** LUT trie evaluator (~124 MB tables) — designed for automated poker bot testing, strategy analysis, and simulation at scale. ## Recent Updates - **Supersonic Evaluator**: New high-throughput LUT trie evaluator (~124 MB) for O(n) hand evaluation - **Dual Evaluator Architecture**: Choose between Cactus Kev (compact) and Supersonic (fast) per use case - **Simulation Testbed**: Run cash games, SNGs, and MTTs with configurable bots via TOML - **Input Validation**: Added comprehensive validation to `Card::new()` ensuring rank (0-12) and suit (0-3) are within valid ranges - **Enhanced Documentation**: All public methods now include working code examples and panic condition documentation - **Error Handling**: Improved error handling throughout the codebase with proper `Result` types ## Features - **Bot Testing Framework**: Specifically designed for automated poker bot testing and development - **Dual Evaluators**: Cactus Kev (compact ~100 KB) and Supersonic LUT trie (~124 MB) hand evaluators - **Blazing Fast**: Sub-microsecond hand evaluation using perfect hash and trie-based lookup - **Memory Efficient**: Choose between compact Cactus Kev tables or high-throughput Supersonic trie - **Standards Compliant**: Based on proven poker evaluation algorithms - **Multi-Hand Support**: Evaluate 5, 6, or 7-card poker hands - **Texas Hold'em Ready**: Optimized for Texas Hold'em bot analysis and testing - **Comprehensive Testing**: Extensive test suite with millions of verification cases - **Deterministic Results**: Consistent hand evaluation for reproducible bot testing - **Simulation Engine**: Run cash games, SNGs, and MTTs with configurable bots via TOML ## Performance ### Cactus Kev Evaluator | Hand Type | Evaluation Time | Method | |-----------|----------------|--------| | 5-Card | ~50-100ns | Single prime-product hash → table lookup | | 6-Card | ~300-500ns | Six 5-card lookups | | 7-Card | ~1-2µs | 21 enumeration + HashMap cache | ### Supersonic Evaluator | Hand Type | Evaluation Time | Method | |-----------|----------------|--------| | 5-Card | O(5) array lookups | Direct trie traversal | | 6-Card | O(6) array lookups | Direct trie traversal | | 7-Card | O(7) array lookups | Direct trie traversal | ## Documentation For detailed project information, see: - **[VISION.md](docs/VISION.md)** - Project goals and architectural vision - **[ROADMAP.md](docs/ROADMAP.md)** - Future development phases and implementation plan ## Installation Add this to your `Cargo.toml`: ```toml [dependencies] holdem_core = "0.1.0" ``` ## Quick Start - Bot Testing ```rust use holdem_core::{Card, Hand, HoleCards, Board, Evaluator}; use std::str::FromStr; // Create cards from string notation let ace_spades = Card::from_str("As").unwrap(); let king_spades = Card::from_str("Ks").unwrap(); // Create hole cards from notation let hole_cards = HoleCards::from_notation("AKs").unwrap(); // Create a board with community cards let board = Board::new() .with_flop([ Card::from_str("Qh").unwrap(), Card::from_str("Jh").unwrap(), Card::from_str("Th").unwrap(), ]).unwrap() .with_turn(Card::from_str("2c").unwrap()).unwrap() .with_river(Card::from_str("3d").unwrap()).unwrap(); // Create a hand from hole cards and board let hand = Hand::from_hole_cards_and_board(&hole_cards, &board).unwrap(); // Evaluate the hand let evaluator = Evaluator::new().unwrap(); let hand_value = evaluator.evaluate_hand(&hand); println!("Hand rank: {:?}", hand_value.rank); ``` ## Bot Testing Capabilities This framework provides specialized capabilities for poker bot testing and development: ### Automated Bot Testing - **Standardized Evaluation**: Consistent hand evaluation across both Cactus Kev and Supersonic evaluators - **Performance Benchmarking**: Fast evaluation for large-scale bot performance testing - **Range Analysis**: Efficient hand range evaluation for bot strategy analysis - **Decision Tree Testing**: Quick hand strength calculation for bot decision trees ### Dual Evaluator Support - **Cactus Kev**: Compact ~100 KB tables with prime-product hashing — ideal for memory-constrained environments - **Supersonic**: High-throughput ~124 MB LUT trie with O(n) array lookups — fastest for bulk evaluation - **Algorithmic Fallback**: Rule-based evaluator serves as correctness oracle for validation ### Bot Development Features - **Hole Card Analysis**: Fast evaluation of starting hand strength for pre-flop bots - **Post-Flop Analysis**: Efficient board texture and hand strength analysis - **Incremental Evaluation**: Multi-street hand evaluation for complex bot scenarios - **Memory Efficient**: Optimized for bot testing environments with limited resources ## Algorithm Overview This library provides **two hand evaluators** with different performance/memory tradeoffs: ### Cactus Kev Evaluator (compact) Uses prime-product hashing into two small lookup tables (~100 KB total): 1. **Prime Product Hashing**: Each rank maps to a unique prime; the product of 5 primes uniquely identifies the hand 2. **Dual Lookup Tables**: 1,287 flush entries + 6,175 unsuited entries = 7,462 total (~30 KB) 3. **7-card Cache**: C(7,5)=21 enumeration with HashMap cache for amortized O(1) lookups 4. **Zero Collisions**: Validated against all 2,598,960 five-card hands ### Supersonic Evaluator (high-throughput) Uses a pre-computed LUT trie (~124 MB) for O(n) array lookups: 1. **Trie Structure**: 32,487,834 `u32` entries organized in pages of 53 (one per card + base) 2. **Direct Lookup**: Follow `hand_ranks[p + card_index + 1]` for each card — no enumeration needed 3. **Packed Hand Rank**: 16-bit format (category + equivalency class) for compact result representation 4. **Best for Bulk**: Fastest evaluator for large-scale simulations and batch evaluation ### Table Generation Lookup tables are generated automatically on first use and persisted to disk: - **Cactus Kev**: Small tables (~100 KB) generated in-memory from prime products - **Supersonic**: Large LUT trie (~124 MB) loaded from pre-generated binary file ## Hand Types The evaluator recognizes all standard poker hand types: | Hand Type | Description | Example | |-----------|-------------|---------| | Straight Flush | Five cards in sequence, same suit | A♠ K♠ Q♠ J♠ T♠ | | Four of a Kind | Four cards of same rank | A♠ A♥ A♦ A♣ K♦ | | Full House | Three of a kind + one pair | K♠ K♥ K♦ Q♠ Q♥ | | Flush | Five cards of same suit | A♠ J♠ 8♠ 5♠ 2♠ | | Straight | Five cards in sequence | A♦ K♣ Q♥ J♠ T♦ | | Three of a Kind | Three cards of same rank | Q♠ Q♥ Q♦ A♣ 7♦ | | Two Pair | Two different pairs | J♠ J♥ 7♦ 7♣ A♦ | | One Pair | Two cards of same rank | A♠ A♥ K♦ Q♣ 7♦ | | High Card | No matching cards | A♠ K♥ Q♦ J♣ 9♦ | ## Bot Testing Examples ### Texas Hold'em Bot Analysis ```rust use holdem_core::{Card, Hand, HoleCards, Board, Evaluator}; use std::str::FromStr; let evaluator = Evaluator::new().unwrap(); // Bot analyzes hole cards + flop for decision making let hole_cards = HoleCards::from_notation("AKs").unwrap(); let board = Board::new() .with_flop([ Card::from_str("Td").unwrap(), Card::from_str("Jc").unwrap(), Card::from_str("Qh").unwrap(), ]).unwrap(); // Bot evaluates complete hand strength let hand = Hand::from_hole_cards_and_board(&hole_cards, &board).unwrap(); let hand_value = evaluator.evaluate_hand(&hand); println!("Hand strength after flop: {:?}", hand_value.rank); // Bot uses this for post-flop decision making if hand_value.rank as u8 >= 4 { // Straight or better println!("Bot: Continuing with strong hand"); } ``` ### Bot Range Analysis ```rust use holdem_core::{Card, Hand, Evaluator}; use std::str::FromStr; let evaluator = Evaluator::new().unwrap(); // Bot analyzes range of starting hands for pre-flop strategy let premium_hands = vec![ Hand::from_notation("As Ah").unwrap(), Hand::from_notation("Ks Kh").unwrap(), Hand::from_notation("Qs Qh").unwrap(), Hand::from_notation("As Ks").unwrap(), ]; for hand in premium_hands { let hand_value = evaluator.evaluate_hand(&hand); println!("Bot range analysis - {}: {:?}", hand, hand_value.rank); } ``` ## Advanced Usage ### 7-Card Hand Evaluation for Bot Testing ```rust use holdem_core::{Card, Hand, HoleCards, Board, Evaluator}; use std::str::FromStr; let evaluator = Evaluator::new().unwrap(); // Texas Hold'em complete hand: 2 hole cards + 5 community cards let hole_cards = HoleCards::from_notation("AKs").unwrap(); let board = Board::new() .with_flop([ Card::from_str("Td").unwrap(), Card::from_str("Jc").unwrap(), Card::from_str("Qh").unwrap(), ]).unwrap() .with_turn(Card::from_str("9s").unwrap()).unwrap() .with_river(Card::from_str("2d").unwrap()).unwrap(); // Bot evaluates best possible hand from all 7 cards let hand = Hand::from_hole_cards_and_board(&hole_cards, &board).unwrap(); let hand_value = evaluator.evaluate_hand(&hand); println!("Bot best hand rank: {:?}", hand_value.rank); ``` ## Testing Run the comprehensive test suite: ```bash cargo test ``` Run performance benchmarks: ```bash cargo test --release hand_eval_integration_test -- --nocapture ``` ## Simulation Testbed The `holdem_sim` binary provides a CLI for running poker simulations with configurable bots, game types, and formats. It supports cash games, Sit & Go (SNG) tournaments, and Multi-Table Tournaments (MTT). ### Running Simulations ```bash # Run a cash game simulation cargo run --bin holdem_sim -- holdem_core/examples/configs/cash_game.toml # Run with a specific seed for reproducibility cargo run --bin holdem_sim -- holdem_core/examples/configs/cash_game.toml --seed 42 # Override the number of hands cargo run --bin holdem_sim -- holdem_core/examples/configs/cash_game.toml --hands 5000 ``` ### Example Configuration (Cash Game) ```toml [game] game_type = "Cash" num_seats = 6 small_blind = 10 big_blind = 20 ante = 0 starting_chips = 10000 num_hands = 1000 [game.bet_limit] type = "no_limit" min_raise = 20 [[game.bots]] bot_type = "call_bot" name = "Alice" [[game.bots]] bot_type = "fold_bot" name = "Bob" [[game.bots]] bot_type = "random_bot" name = "Charlie" ``` Example configs are available in [`holdem_core/examples/configs/`](holdem_core/examples/configs/): - [`cash_game.toml`](holdem_core/examples/configs/cash_game.toml) — 6-max NLHE cash game - [`sng_tournament.toml`](holdem_core/examples/configs/sng_tournament.toml) — 9-seat Sit & Go - [`mtt_tournament.toml`](holdem_core/examples/configs/mtt_tournament.toml) — Multi-table tournament ### Built-in Bots | Bot | Description | |-----|-------------| | `call_bot` | Calls every bet, never raises or folds | | `fold_bot` | Folds whenever facing a bet, otherwise checks | | `raise_bot` | Raises with configurable aggression thresholds | | `random_bot` | Takes random legal actions with configurable tendencies | ### Example Output ``` === Simulation Results === Hands played: 1000 Player Statistics: Alice (call_bot) Hands: 1000 | VPIP: 100.0% | PFR: 0.0% | Win: $45,230 Bob (fold_bot) Hands: 1000 | VPIP: 0.0% | PFR: 0.0% | Win: -$32,100 Charlie (random_bot) Hands: 1000 | VPIP: 67.3% | PFR: 22.1% | Win: -$13,130 ``` ## Mathematical Foundation ### Cactus Kev — Perfect Hash Algorithm The Cactus Kev evaluator uses prime-product hashing: ``` Hash = prime(rank₁) × prime(rank₂) × ... × prime(rank₅) Index = Hash % TABLE_SIZE Rank = TABLE[Index] ``` Each rank maps to a unique prime (2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41), so the product of 5 primes uniquely identifies the hand pattern. ### Supersonic — LUT Trie Algorithm The Supersonic evaluator uses a pre-computed trie of 32.5M `u32` entries: ``` p = INITIAL_STATE (page 1 base) for each card: p = hand_ranks[p + card_index + 1] rank = p // (for 7-card hands) ``` Each step is a single array lookup — no hashing, no enumeration, no branching. ## References - **Cactus Kev**: Perfect hash algorithm for 5-card poker hand evaluation - **Supersonic**: LUT trie evaluator for high-throughput hand evaluation - **Poker Standards**: Standard poker hand ranking rules - **Poker Testbed**: Framework designed for automated bot testing and analysis ## License This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. ## Contributing Contributions are welcome! Areas for improvement: - Hardware acceleration (SIMD optimizations) - Additional poker variants (Omaha, Stud, etc.) - Memory-mapped table loading - Distributed table generation - Advanced benchmarking tools ## Support For questions, issues, or contributions, please: 1. Check existing documentation 2. Review test cases for usage examples 3. Open GitHub issues for bugs or feature requests 4. Submit pull requests with comprehensive tests --- **Performance Note**: The Cactus Kev evaluator generates its small lookup tables (~100 KB) in-memory on first use. The Supersonic evaluator requires a pre-generated ~124 MB LUT file loaded at startup.