# User Guide ## Introduction This guide explains how to use the Poker Hand Evaluator library for evaluating poker hands in your applications. Whether you're building a poker game, analysis tool, or AI bot, this library provides the fast and accurate hand evaluation you need. ## Quick Start ### Basic Setup 1. **Add dependency** to your `Cargo.toml`: ```toml [dependencies] poker-api = "0.1.0" ``` 2. **Import and use** in your code: ```rust use poker_api::hand_evaluator::LookupHandEvaluator; use poker_api::api::hand::Hand; fn main() -> Result<(), Box> { // Create the evaluator (generates tables on first run) let evaluator = LookupHandEvaluator::new()?; // Create a poker hand let mut hand = Hand::new(); // ... add cards // Evaluate the hand let rank = evaluator.rank_hand(&hand); println!("Hand strength: {}", rank); Ok(()) } ``` ### First Run Experience On the first run, you'll see: ``` Evaluation tables do not exist, generating them... Generating state table... Hand evaluation tables saved to math/HandRanks.dat Evaluation tables loaded. ``` This generates the lookup tables (~1-2 seconds) and saves them for future use. ## Working with Cards ### Card Creation Cards can be created from string notation: ```rust use poker_api::api::card::Card; // Face cards let ace_spades = Card::from_string("As")?; let king_hearts = Card::from_string("Kh")?; // Number cards let five_clubs = Card::from_string("5c")?; let ten_diamonds = Card::from_string("Td")?; // All suits: s (spades), h (hearts), d (diamonds), c (clubs) // All ranks: A, K, Q, J, T, 9, 8, 7, 6, 5, 4, 3, 2 ``` ### Card Properties ```rust let card = Card::from_string("As")?; println!("Rank: {}", card.rank()); // 12 (Ace) println!("Suit: {}", card.suit()); // 0 (Spades) println!("Index: {}", card.index()); // 51 (unique card ID) println!("String: {}", card.to_string()); // "As" ``` ## Working with Hands ### Creating Hands ```rust use poker_api::api::hand::Hand; use poker_api::api::card::Card; // Create empty hand let mut hand = Hand::new(); // Add cards one by one hand.add_card(Card::from_string("As")?).unwrap(); hand.add_card(Card::from_string("Ks")?).unwrap(); hand.add_card(Card::from_string("Qs")?).unwrap(); hand.add_card(Card::from_string("Js")?).unwrap(); hand.add_card(Card::from_string("Ts")?).unwrap(); println!("Hand size: {}", hand.size()); // 5 println!("Hand: {}", hand.to_string()); // "As Ks Qs Js Ts" ``` ### Hand Evaluation ```rust // 5-card hand evaluation let rank = evaluator.rank_hand(&hand); println!("Royal flush rank: {}", rank); // 6-card hand (finds best 5-card combination) let mut six_card_hand = Hand::new(); six_card_hand.add_card(Card::from_string("As")?).unwrap(); six_card_hand.add_card(Card::from_string("Ks")?).unwrap(); // ... add 4 more cards let rank = evaluator.rank_hand(&six_card_hand); // 7-card hand (Texas Hold'em) let mut seven_card_hand = Hand::new(); // ... add 7 cards let rank = evaluator.rank_hand(&seven_card_hand); ``` ## Understanding Hand Ranks ### Rank Values Higher rank values indicate stronger hands: ```rust // Compare hand strengths let hand1_rank = evaluator.rank_hand(&hand1); let hand2_rank = evaluator.rank_hand(&hand2); if hand1_rank > hand2_rank { println!("Hand 1 is stronger"); } else if hand1_rank < hand2_rank { println!("Hand 2 is stronger"); } else { println!("Hands are equal"); } ``` ### Hand Categories Extract hand category from rank: ```rust use poker_api::api::hand_eval::HandEval; fn get_hand_category(rank: u32) -> u32 { (rank & HandEval::HAND_CATEGORY_MASK) >> HandEval::HAND_CATEGORY_SHIFT } let category = get_hand_category(rank); match category { 9 => println!("Straight Flush"), 8 => println!("Four of a Kind"), 7 => println!("Full House"), 6 => println!("Flush"), 5 => println!("Straight"), 4 => println!("Three of a Kind"), 3 => println!("Two Pair"), 2 => println!("One Pair"), 1 => println!("High Card"), _ => println!("Unknown"), } ``` ## Texas Hold'em Example Here's a complete example of evaluating Texas Hold'em hands: ```rust use poker_api::hand_evaluator::LookupHandEvaluator; use poker_api::api::hand::Hand; use poker_api::api::card::Card; struct PokerGame { evaluator: LookupHandEvaluator, } impl PokerGame { fn new() -> Result> { Ok(Self { evaluator: LookupHandEvaluator::new()?, }) } fn evaluate_texas_holdem( &self, hole_cards: &[Card; 2], board: &[Card; 5] ) -> u32 { let mut hand = Hand::new(); // Add hole cards hand.add_card(hole_cards[0]).unwrap(); hand.add_card(hole_cards[1]).unwrap(); // Add community cards for &card in board { hand.add_card(card).unwrap(); } self.evaluator.rank_hand(&hand) } } fn main() -> Result<(), Box> { let game = PokerGame::new()?; // Example: Royal Flush let hole_cards = [ Card::from_string("As").unwrap(), Card::from_string("Ks").unwrap(), ]; let board = [ Card::from_string("Qs").unwrap(), Card::from_string("Js").unwrap(), Card::from_string("Ts").unwrap(), Card::from_string("2d").unwrap(), Card::from_string("3c").unwrap(), ]; let rank = game.evaluate_texas_holdem(&hole_cards, &board); println!("Royal flush rank: {}", rank); Ok(()) } ``` ## Performance Optimization ### Table Preloading For applications that need immediate response: ```rust // Warm up the evaluator before use fn preload_evaluator() -> LookupHandEvaluator { println!("Loading poker evaluator..."); let start = std::time::Instant::now(); let evaluator = LookupHandEvaluator::new().unwrap(); let duration = start.elapsed(); println!("Evaluator ready in {:?}", duration); evaluator } ``` ### Batch Evaluation For evaluating many hands: ```rust fn evaluate_multiple_hands(evaluator: &LookupHandEvaluator, hands: &[Hand]) -> Vec { hands.iter() .map(|hand| evaluator.rank_hand(hand)) .collect() } ``` ## Error Handling ### Common Errors ```rust use poker_api::api::card::Card; // Invalid card strings let invalid = Card::from_string("XX"); // Err let invalid = Card::from_string("53"); // Err // Hand capacity exceeded let mut hand = Hand::new(); // Adding more than 7 cards will fail // Table loading failures let evaluator = LookupHandEvaluator::new(); // May fail if disk is full or permissions are insufficient ``` ### Proper Error Handling ```rust use std::io; fn create_evaluator() -> Result { match LookupHandEvaluator::new() { Ok(evaluator) => { println!("Evaluator created successfully"); Ok(evaluator) } Err(e) => { eprintln!("Failed to create evaluator: {}", e); Err(e) } } } ``` ## Best Practices ### 1. Reuse Evaluators ```rust // Good: Reuse the same evaluator struct GameEngine { evaluator: LookupHandEvaluator, } impl GameEngine { fn new() -> Result { Ok(Self { evaluator: LookupHandEvaluator::new()?, }) } fn evaluate_hand(&self, hand: &Hand) -> u32 { self.evaluator.rank_hand(hand) } } ``` ### 2. Validate Input Data ```rust fn safe_evaluate_hand(evaluator: &LookupHandEvaluator, hand: &Hand) -> Option { if hand.size() >= 5 && hand.size() <= 7 { Some(evaluator.rank_hand(hand)) } else { None } } ``` ### 3. Handle Edge Cases ```rust // Check for invalid hands let rank = evaluator.rank_hand(&hand); if rank == 0 { println!("Invalid hand: must have 5-7 cards"); } ``` ## Integration Examples ### Poker Bot ```rust use poker_api::hand_evaluator::LookupHandEvaluator; struct PokerBot { evaluator: LookupHandEvaluator, } impl PokerBot { fn should_raise(&self, my_hand: &Hand, pot_odds: f32) -> bool { let hand_strength = self.evaluator.rank_hand(my_hand); // Simple strategy: raise with strong hands match hand_strength { rank if rank > 300_000_000 => true, // Very strong rank if rank > 100_000_000 => pot_odds > 0.1, // Medium strength _ => false, // Weak hands } } } ``` ### Hand Range Analysis ```rust use poker_api::hand_evaluator::LookupHandEvaluator; use poker_api::api::hand::Hand; struct RangeAnalyzer { evaluator: LookupHandEvaluator, } impl RangeAnalyzer { fn analyze_range(&self, hands: &[Hand]) -> HandStrengthStats { let ranks: Vec = hands.iter() .map(|hand| self.evaluator.rank_hand(hand)) .collect(); HandStrengthStats { average_rank: ranks.iter().sum::() / ranks.len() as u32, median_rank: self.calculate_median(&ranks), strongest_hand: ranks.iter().max().copied().unwrap_or(0), weakest_hand: ranks.iter().min().copied().unwrap_or(0), } } } ``` ## Troubleshooting ### Common Issues **Problem**: "Evaluation tables do not exist, generating them..." every time **Solution**: Ensure write permissions in the current directory, or specify a custom path **Problem**: Slow first startup **Solution**: Expected behavior - table generation takes 1-2 seconds **Problem**: High memory usage **Solution**: The 128MB lookup table is required for performance. Consider if this fits your deployment constraints **Problem**: Card parsing fails **Solution**: Verify card strings use correct format: rank + suit (e.g., "As", "Kh", "Td") ### Performance Issues If evaluation seems slow: 1. **Check build mode**: Use `cargo build --release` 2. **Verify table loading**: Ensure tables are generated and cached 3. **Monitor memory**: Ensure sufficient RAM for table storage 4. **Consider batching**: Evaluate multiple hands together when possible ## Support For additional help: 1. Check the [API Documentation](api.md) for detailed reference 2. Review test files for usage examples 3. Open issues on GitHub for bugs or feature requests 4. Study the source code comments for implementation details This user guide covers the most common use cases. For advanced usage or customization, see the developer guide and source code documentation.