chironaut 0.3.5

A poker game library for Texas Hold'em and other poker variants
Documentation
use chironaut::{
    action::Action,
    game::Game,
    rules::GameRules,
    game::GameStage,
};

#[test]
fn test_force_win_basic() {
    // Create a new game with 3 players
    let rules = GameRules::nlhe(10, 20);
    let mut game = Game::new(rules);
    
    // Add players to specific seats
    let p1 = game.add_player_to_seat("Player 1".to_string(), 1000, 0).unwrap();
    let p2 = game.add_player_to_seat("Player 2".to_string(), 1000, 2).unwrap();
    let p3 = game.add_player_to_seat("Player 3".to_string(), 1000, 4).unwrap();
    
    // Verify players are in the correct seats
    assert_eq!(game.players[p1].seat_position, 0);
    assert_eq!(game.players[p2].seat_position, 2);
    assert_eq!(game.players[p3].seat_position, 4);
    
    // Start a hand
    game.start_hand().unwrap();
    
    // Track initial state
    let initial_pot = game.pot; // Should be SB + BB + antes if any
    let initial_chips = game.players.iter().map(|p| p.chips).collect::<Vec<_>>();
    
    println!("Initial state:");
    println!("Pot: {}", initial_pot);
    for (i, chips) in initial_chips.iter().enumerate() {
        println!("Player {} chips: {}", i, chips);
    }
    
    // Declare player in seat 2 the winner
    let winning_seat = 2;
    let result = game.force_win(winning_seat).unwrap();
    
    // Verify game went to showdown
    assert_eq!(game.stage, GameStage::Showdown);
    
    // Verify only one player is not folded
    let active_players: Vec<usize> = game.players.iter()
        .enumerate()
        .filter(|(_, p)| !p.is_folded)
        .map(|(i, _)| i)
        .collect();
    assert_eq!(active_players.len(), 1);
    
    // Verify the active player is in seat 2
    assert_eq!(game.players[active_players[0]].seat_position, winning_seat);
    
    // Verify the pot has been awarded
    assert_eq!(game.pot, 0);
    
    // Verify the correct player got the pot
    let winner_index = active_players[0];
    let expected_winnings = initial_chips[winner_index] + initial_pot;
    assert_eq!(game.players[winner_index].chips, expected_winnings);
    
    // Check the ShowdownResult details
    assert_eq!(result.winners.len(), 1);
    assert_eq!(result.winners[0], winner_index);
    assert_eq!(result.pot_distributions.len(), 1);
    assert_eq!(result.pot_distributions[0].chips_per_winner, initial_pot);
    assert_eq!(result.disbursements.len(), 1);
    assert_eq!(result.disbursements[0].player, winner_index);
    assert_eq!(result.disbursements[0].total_won, initial_pot);
}

#[test]
fn test_force_win_after_betting() {
    // Create a new game with 3 players
    let rules = GameRules::nlhe(10, 20);
    let mut game = Game::new(rules);
    
    // Add players to specific seats
    game.add_player_to_seat("Player 1".to_string(), 1000, 0).unwrap();
    game.add_player_to_seat("Player 2".to_string(), 1000, 2).unwrap();
    game.add_player_to_seat("Player 3".to_string(), 1000, 4).unwrap();
    
    // Start a hand
    game.start_hand().unwrap();
    
    // Some betting to increase the pot
    // First player raises
    game.handle_action(Action::Bet(100)).unwrap(); // Call 20 + raise 80
    
    // Second player calls
    let current_bet = game.current_bet;
    let player_bet = game.players[game.current_position].bet_amount;
    let call_amount = current_bet - player_bet;
    game.handle_action(Action::Bet(call_amount)).unwrap();
    
    // Third player calls
    let current_bet = game.current_bet;
    let player_bet = game.players[game.current_position].bet_amount;
    let call_amount = current_bet - player_bet;
    game.handle_action(Action::Bet(call_amount)).unwrap();
    
    // Check pot amount after betting
    let pot_after_betting = game.pot;
    println!("Pot after betting: {}", pot_after_betting);
    
    // Record chips before forcing winner
    let chips_before = game.players.iter().map(|p| p.chips).collect::<Vec<_>>();
    
    // Force the winner to be the player in seat 4
    let winning_seat = 4;
    let winner_idx = game.players.iter().position(|p| p.seat_position == winning_seat).unwrap();
    let result = game.force_win(winning_seat).unwrap();
    
    // Verify winner got the pot
    assert_eq!(game.players[winner_idx].chips, chips_before[winner_idx] + pot_after_betting);
    
    // Verify pot is now empty
    assert_eq!(game.pot, 0);
    
    // Verify ShowdownResult is consistent
    assert_eq!(result.winners.len(), 1);
    assert_eq!(result.winners[0], winner_idx);
    assert_eq!(result.disbursements[0].total_won, pot_after_betting);
}

#[test]
fn test_force_win_errors() {
    // Create a new game with 2 players
    let rules = GameRules::nlhe(10, 20);
    let mut game = Game::new(rules);
    
    // Add players
    game.add_player_to_seat("Player 1".to_string(), 1000, 0).unwrap();
    game.add_player_to_seat("Player 2".to_string(), 1000, 3).unwrap();
    
    // Try to force win before hand starts - should error
    assert_eq!(game.pot, 0); // No pot yet
    assert_eq!(game.community_cards.len(), 0); // No cards yet
    
    let result = game.force_win(0);
    assert!(result.is_err(), "force_win should fail before hand starts");
    
    // Start a hand
    game.start_hand().unwrap();
    
    // Try to force win for a non-existent seat
    let result = game.force_win(7);
    assert!(result.is_err(), "force_win should fail for non-existent seat");
    
    // Once a hand is complete, start a new test for the already-at-showdown case
    // We'll fast forward by forcing a win for seat 0
    game.force_win(0).unwrap();
    
    // Verify we're at showdown
    assert_eq!(game.stage, GameStage::Showdown, "Game should be at showdown stage");
    
    // Try to force win after hand is complete - should error
    let result = game.force_win(0);
    assert!(result.is_err(), "force_win should fail after showdown");
}