chironaut 0.2.0

A poker game library for Texas Hold'em and other poker variants
Documentation
# 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

```rust
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 pot
- `Action::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

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:

```rust
// 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:

```rust
// 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:

```rust
// 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:

```rust
// 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:

```rust
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