1 unstable release
new 0.1.0 | May 2, 2025 |
---|
#91 in Games
100 downloads per month
92KB
2K
SLoC
Chironaut
A complete and flexible Texas Hold'em and Omaha poker engine written in Rust.
Features
- ๐ Support for Texas Hold'em and multiple Omaha variants (4, 5, and 6-card)
- ๐ฐ Fully functional betting logic with blinds, antes, raises, and all-in situations
- ๐ Side pot calculation and distribution with multiple all-in players
- ๐ฎ Simple action model for easy integration with user interfaces
- ๐คฒ Hand evaluation for all poker hand rankings
- ๐ Support for running it multiple times (2 or 3 runs)
- ๐พ Game state serialization for saving and loading games
- ๐งช Thoroughly tested with comprehensive test suite
Usage
Basic Game Setup
use chironaut::{
action::Action,
game::Game,
rules::GameRules,
game::GameStage,
};
// 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("Player 1".to_string(), 1000).unwrap();
game.add_player("Player 2".to_string(), 1000).unwrap();
game.add_player("Player 3".to_string(), 1000).unwrap();
// Start a hand
game.start_hand().unwrap();
// Player actions are handled with the simplified Action model
// Player 1 calls the big blind
game.handle_action(Action::Bet(20)).unwrap();
// Player 2 raises to 60
game.handle_action(Action::Bet(60)).unwrap();
// Player 3 folds
game.handle_action(Action::Fold).unwrap();
// Player 1 calls the raise
game.handle_action(Action::Bet(40)).unwrap();
// Move to the flop
game.next_street().unwrap();
println!("Community cards: {:?}", game.community_cards);
Action Model
Chironaut uses a simplified action model to represent player actions:
Action::Fold
- Player folds their hand and gives up claim to the potAction::Bet(amount)
- A unified betting action that covers:- Check:
Bet(0)
when current_bet = player's current bet - Call:
Bet(amount)
to match the current bet - Raise:
Bet(amount)
higher than the amount needed to call - All-in:
Bet(player.chips)
to go all-in with remaining chips
- Check:
This unified model simplifies integration with user interfaces while maintaining all poker functionality.
All-in and Side Pots
The engine automatically handles all-in scenarios and side pot calculations:
// Player goes all-in with their remaining chips
let all_in_amount = game.players[current_position].chips;
game.handle_action(Action::Bet(all_in_amount)).unwrap();
// When a round is complete with all-in players, side pots are calculated
if game.is_round_complete() {
game.calculate_side_pots();
println!("Side pots: {:?}", game.side_pots);
}
// At showdown, pots are awarded to winners automatically
if game.stage == GameStage::Showdown {
game.evaluate_winner();
}
Running Multiple Times
The engine supports running the community cards multiple times:
// After players are all-in, you can run the board multiple times
let run_count = 2; // Can be 2 or 3
let multi_run = game.run_multiple_times(run_count).unwrap();
// Pot is distributed proportionally based on run wins
game.complete_with_multiple_runs(run_count).unwrap();
Game State Serialization
Save and load game states:
// Save the current game state
let snapshot = game.get_snapshot();
let json = serde_json::to_string(&snapshot).unwrap();
// Load a game from a saved state
let loaded_snapshot: GameSnapshot = serde_json::from_json(&json).unwrap();
let game = Game::from_snapshot(loaded_snapshot);
Seating and Blind Structure
In heads-up (2 player) games, the button posts the small blind and acts first preflop. After the flop, the big blind acts first.
For 3+ player games, the standard poker seating and blind structure applies:
- Button (dealer) is last to act
- Small blind is to the left of the button
- Big blind is to the left of the small blind
- First to act (UTG) is to the left of the big blind
Seat positions can be explicitly assigned:
// Add players to specific seats (0-based index)
game.add_player_to_seat("Button".to_string(), 1000, 0).unwrap();
game.add_player_to_seat("Small Blind".to_string(), 1000, 1).unwrap();
game.add_player_to_seat("Big Blind".to_string(), 1000, 2).unwrap();
Testing
The library includes comprehensive tests for all functionality:
cargo test
Example CLI Application
A simple command-line poker game is included as an example:
use chironaut::{
action::Action,
game::Game,
rules::GameRules,
};
fn main() {
// Create a game with 10/20 blinds
let rules = GameRules::nlhe(10, 20);
let mut game = Game::new(rules);
// Add players
game.add_player("Alice".to_string(), 1000).unwrap();
game.add_player("Bob".to_string(), 1000).unwrap();
// Start the hand
game.start_hand().unwrap();
// Play through a simple hand
println!("Starting the hand");
println!("Alice's cards: {}", game.players[0].hand);
println!("Bob's cards: {}", game.players[1].hand);
// Alice calls
game.handle_action(Action::Bet(10)).unwrap();
// Bob checks
game.handle_action(Action::Bet(0)).unwrap();
// Deal the flop
game.next_street().unwrap();
println!("Flop: {:?}", game.community_cards);
// Complete the hand
// ...
}
License
MIT
Dependencies
~0.9โ1.8MB
~38K SLoC