- Delete ARCHITECTURE_HAND_LOGGING_TOURNAMENT_IMPROVEMENTS.md (implemented) - Delete ARCHITECTURE_SUPERSONIC_EVALUATOR.md (implemented) - Delete REFERENCES.md (no longer needed) - Simplify ROADMAP.md: remove Phases 4-7 (live server, advanced bots) - Simplify VISION.md: focus on simulation testbed only - Update README.md: dual evaluator architecture, fix broken links - Update holdem_core/README.md: fix title, add Supersonic evaluator docs |
||
|---|---|---|
| docs | ||
| holdem_core | ||
| holdem_sim | ||
| .gitignore | ||
| Cargo.lock | ||
| Cargo.toml | ||
| README.md | ||
Poker Simulation Testbed
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
Resulttypes
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 - Project goals and architectural vision
- ROADMAP.md - Future development phases and implementation plan
Installation
Add this to your Cargo.toml:
[dependencies]
holdem_core = "0.1.0"
Quick Start - Bot Testing
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):
- Prime Product Hashing: Each rank maps to a unique prime; the product of 5 primes uniquely identifies the hand
- Dual Lookup Tables: 1,287 flush entries + 6,175 unsuited entries = 7,462 total (~30 KB)
- 7-card Cache: C(7,5)=21 enumeration with HashMap cache for amortized O(1) lookups
- 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:
- Trie Structure: 32,487,834
u32entries organized in pages of 53 (one per card + base) - Direct Lookup: Follow
hand_ranks[p + card_index + 1]for each card — no enumeration needed - Packed Hand Rank: 16-bit format (category + equivalency class) for compact result representation
- 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
use holdem_core::hand_evaluator::LookupHandEvaluator;
use holdem_core::api::{card::Card, hand::Hand};
let evaluator = LookupHandEvaluator::new().unwrap();
// Bot analyzes hole cards + flop for decision making
let hole_card1 = Card::from_string("As").unwrap().index() as u32;
let hole_card2 = Card::from_string("Ks").unwrap().index() as u32;
let mut board = Hand::new();
board.add_card(Card::from_string("Td").unwrap()).unwrap();
board.add_card(Card::from_string("Jc").unwrap()).unwrap();
board.add_card(Card::from_string("Qh").unwrap()).unwrap();
// Bot evaluates complete hand strength
let hand_strength = evaluator.rank_hand_with_hole_cards(hole_card1, hole_card2, &board);
println!("Hand strength after flop: {}", hand_strength);
// Bot uses this for post-flop decision making
if hand_strength < 2000 { // Strong hand
println!("Bot: Continuing with strong hand");
}
Bot Range Analysis
use holdem_core::hand_evaluator::LookupHandEvaluator;
use holdem_core::api::card::Card;
let evaluator = LookupHandEvaluator::new().unwrap();
// Bot analyzes range of starting hands for pre-flop strategy
let premium_hands = vec![
(Card::from_string("AA").unwrap(), Card::from_string("KK").unwrap()),
(Card::from_string("QQ").unwrap(), Card::from_string("JJ").unwrap()),
(Card::from_string("AK").unwrap(), Card::from_string("AQ").unwrap()),
];
for (card1, card2) in premium_hands {
let mut hand = Hand::new();
hand.add_card(card1).unwrap();
hand.add_card(card2).unwrap();
let strength = evaluator.rank_hand(&hand);
println!("Bot range analysis - {}: {}", hand.to_string(), strength);
}
Advanced Usage
7-Card Hand Evaluation for Bot Testing
use holdem_core::hand_evaluator::LookupHandEvaluator;
use holdem_core::api::card::Card;
let evaluator = LookupHandEvaluator::new().unwrap();
// Texas Hold'em complete hand: 2 hole cards + 5 community cards
let hole_cards = [
Card::from_string("As").unwrap().index(),
Card::from_string("Ks").unwrap().index(),
];
let community_cards = [
Card::from_string("Td").unwrap().index(),
Card::from_string("Jc").unwrap().index(),
Card::from_string("Qh").unwrap().index(),
Card::from_string("9s").unwrap().index(),
Card::from_string("2d").unwrap().index(),
];
// Bot evaluates best possible hand from all cards
let all_cards: Vec<u32> = hole_cards.iter().chain(community_cards.iter()).cloned().collect();
let best_rank = evaluator.rank_hand7(&all_cards);
println!("Bot best hand rank: {}", best_rank);
Testing
Run the comprehensive test suite:
cargo test
Run performance benchmarks:
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
# 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)
[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/:
cash_game.toml— 6-max NLHE cash gamesng_tournament.toml— 9-seat Sit & Gomtt_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 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:
- Check existing documentation
- Review test cases for usage examples
- Open GitHub issues for bugs or feature requests
- 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.