Fix supersonic evaluator and documentation examples

- Remove debug_assert(false) from supersonic evaluator
- Disable buggy supersonic generator
- Fix documentation examples in README.md and holdem_core/README.md
This commit is contained in:
Jan-Peter von Hunnius 2026-05-25 14:30:16 +02:00
parent 2da48d43fb
commit 912445d992
3 changed files with 82 additions and 94 deletions

View file

@ -161,26 +161,27 @@ The evaluator recognizes all standard poker hand types:
### Texas Hold'em Bot Analysis
```rust
use holdem_core::hand_evaluator::LookupHandEvaluator;
use holdem_core::api::{card::Card, hand::Hand};
use holdem_core::{Card, Hand, HoleCards, Board, Evaluator};
use std::str::FromStr;
let evaluator = LookupHandEvaluator::new().unwrap();
let evaluator = Evaluator::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();
let hole_cards = HoleCards::from_notation("AKs").unwrap();
let board = Board::new()
.with_flop([
Card::from_str("Td").unwrap(),
Card::from_str("Jc").unwrap(),
Card::from_str("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);
let hand = Hand::from_hole_cards_and_board(&hole_cards, &board).unwrap();
let hand_value = evaluator.evaluate_hand(&hand);
println!("Hand strength after flop: {:?}", hand_value.rank);
// Bot uses this for post-flop decision making
if hand_strength < 2000 { // Strong hand
if hand_value.rank as u8 >= 4 { // Straight or better
println!("Bot: Continuing with strong hand");
}
```
@ -188,25 +189,22 @@ if hand_strength < 2000 { // Strong hand
### Bot Range Analysis
```rust
use holdem_core::hand_evaluator::LookupHandEvaluator;
use holdem_core::api::card::Card;
use holdem_core::{Card, Hand, Evaluator};
use std::str::FromStr;
let evaluator = LookupHandEvaluator::new().unwrap();
let evaluator = Evaluator::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()),
Hand::from_notation("As Ah").unwrap(),
Hand::from_notation("Ks Kh").unwrap(),
Hand::from_notation("Qs Qh").unwrap(),
Hand::from_notation("As Ks").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);
for hand in premium_hands {
let hand_value = evaluator.evaluate_hand(&hand);
println!("Bot range analysis - {}: {:?}", hand, hand_value.rank);
}
```
@ -215,29 +213,26 @@ for (card1, card2) in premium_hands {
### 7-Card Hand Evaluation for Bot Testing
```rust
use holdem_core::hand_evaluator::LookupHandEvaluator;
use holdem_core::api::card::Card;
use holdem_core::{Card, Hand, HoleCards, Board, Evaluator};
use std::str::FromStr;
let evaluator = LookupHandEvaluator::new().unwrap();
let evaluator = Evaluator::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 hole_cards = HoleCards::from_notation("AKs").unwrap();
let board = Board::new()
.with_flop([
Card::from_str("Td").unwrap(),
Card::from_str("Jc").unwrap(),
Card::from_str("Qh").unwrap(),
]).unwrap()
.with_turn(Card::from_str("9s").unwrap()).unwrap()
.with_river(Card::from_str("2d").unwrap()).unwrap();
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);
// Bot evaluates best possible hand from all 7 cards
let hand = Hand::from_hole_cards_and_board(&hole_cards, &board).unwrap();
let hand_value = evaluator.evaluate_hand(&hand);
println!("Bot best hand rank: {:?}", hand_value.rank);
```
## Testing

View file

@ -53,8 +53,7 @@ Key modules:
### Basic Usage
```rust
use math::{Evaluator, HandRank};
use holdem_core::{Card, Hand};
use holdem_core::{Card, Hand, Evaluator, evaluator::HandRank};
use std::str::FromStr;
// Get the singleton evaluator instance
@ -67,22 +66,30 @@ let hand = Hand::from_notation("As Ks Qs Js Ts").unwrap();
let hand_value = evaluator.evaluate_hand(&hand);
println!("Hand rank: {:?}", hand_value.rank);
println!("Hand value: {}", hand_value.value);
```
### Advanced Usage with Integration
```rust
use math::evaluator::integration::HandEvaluator;
use holdem_core::{HoleCards, Board};
use holdem_core::{HoleCards, Board, Hand, Evaluator};
use std::str::FromStr;
// Evaluate hole cards with a board
let hole_cards = HoleCards::from_strings(&["As", "Ks"]).unwrap();
let board = Board::from_strings(&["Qs", "Js", "Ts", "7h", "3d"]).unwrap();
let hole_cards = HoleCards::from_notation("AKs").unwrap();
let board = Board::new()
.with_flop([
std::str::FromStr::from_str("Qs").unwrap(),
std::str::FromStr::from_str("Js").unwrap(),
std::str::FromStr::from_str("Ts").unwrap(),
]).unwrap()
.with_turn(std::str::FromStr::from_str("7h").unwrap()).unwrap()
.with_river(std::str::FromStr::from_str("3d").unwrap()).unwrap();
let hand_value = HandEvaluator::evaluate_hole_cards_with_board(&hole_cards, &board).unwrap();
let hand = Hand::from_hole_cards_and_board(&hole_cards, &board).unwrap();
let evaluator = Evaluator::new().unwrap();
let hand_value = evaluator.evaluate_hand(&hand);
println!("Final hand: {}", HandEvaluator::format_hand_value(hand_value));
println!("Final hand rank: {:?}", hand_value.rank);
```
## 🎯 Hand Ranking System
@ -170,7 +177,7 @@ Lookup tables are automatically managed:
### Poker Server Implementation
```rust
use math::Evaluator;
use holdem_core::Evaluator;
use std::sync::Arc;
struct PokerServer {
@ -183,10 +190,6 @@ impl PokerServer {
Ok(Self { evaluator })
}
fn evaluate_hand(&self, cards: &[Card; 5]) -> HandValue {
self.evaluator.evaluate_5_card(cards)
}
fn process_game_state(&self, game_state: GameState) -> GameResult {
// High-performance hand evaluation for poker server
// Can handle 100,000+ hands per second
@ -197,11 +200,10 @@ impl PokerServer {
### Poker Analysis Tool
```rust
use math::evaluator::integration::{HandEvaluator, HandEvaluation};
use holdem_core::{Hand, HoleCards, Board};
use holdem_core::{Hand, HoleCards, Board, Evaluator};
struct PokerAnalyzer {
evaluator: math::Evaluator,
evaluator: Evaluator,
}
impl PokerAnalyzer {
@ -209,9 +211,9 @@ impl PokerAnalyzer {
let mut analysis = RangeAnalysis::default();
for notation in hole_cards_list {
let hole_cards = HoleCards::from_strings(&[notation]).unwrap();
let hole_cards = HoleCards::from_notation(notation).unwrap();
let hand = Hand::from_hole_cards_and_board(&hole_cards, board).unwrap();
let hand_value = hand.evaluate();
let hand_value = self.evaluator.evaluate_hand(&hand);
// Analyze hand strength distribution
analysis.total_hands += 1;
@ -228,18 +230,16 @@ impl PokerAnalyzer {
Built-in performance monitoring and diagnostics:
```rust
use math::Evaluator;
use holdem_core::Evaluator;
// Monitor evaluation performance
let evaluator = Evaluator::instance();
// Check table file status
let table_info = evaluator.get_table_info().unwrap();
println!("Table files: {:?}", table_info);
// Validate table integrity
let is_valid = evaluator.validate_table_files().unwrap();
println!("Tables valid: {}", is_valid);
// Evaluate a hand to verify the evaluator is working
use holdem_core::Hand;
let hand = Hand::from_notation("As Ks Qs Js Ts").unwrap();
let hand_value = evaluator.evaluate_hand(&hand);
println!("Hand rank: {:?}", hand_value.rank);
```
## 🚨 Error Handling
@ -247,7 +247,8 @@ println!("Tables valid: {}", is_valid);
Comprehensive error handling for all failure modes:
```rust
use math::{Evaluator, evaluator::errors::EvaluatorError};
use holdem_core::Evaluator;
use holdem_core::evaluator::errors::EvaluatorError;
match Evaluator::new() {
Ok(evaluator) => println!("Evaluator ready"),

View file

@ -200,34 +200,27 @@ impl SupersonicEvaluator {
}
Err(e) => {
log::warn!(
"Failed to load Supersonic table ({}), regenerating...",
"Failed to load Supersonic table ({}), falling back to Cactus Kev",
e
);
}
}
}
// Table doesn't exist or is corrupt — generate it.
// Table doesn't exist or is corrupt.
//
// NOTE: The built-in generator has a known bug that produces invalid
// trie pointers (out-of-bounds indices), so we do NOT attempt to
// regenerate here. Instead, we return `None` so that callers fall
// back to the Cactus Kev JumpTable evaluator, which is correct.
//
// To obtain a valid Supersonic table, generate it externally with a
// corrected generator and place the file at the default path.
log::info!(
"Supersonic table not found at {}, generating (takes a few seconds)...",
"Supersonic table not found at {}, falling back to Cactus Kev evaluator",
path.display()
);
let hand_ranks = super::supersonic_generator::generate_hand_ranks();
match Self::from_hand_ranks(hand_ranks) {
Ok(se) => {
// Persist for future runs.
if let Err(e) = se.save_to_file(&path) {
log::warn!("Failed to save Supersonic table to {}: {}", path.display(), e);
} else {
log::info!("Supersonic table saved to: {}", path.display());
}
Some(se)
}
Err(e) => {
log::error!("Failed to create Supersonic evaluator: {}", e);
None
}
}
None
}
// -----------------------------------------------------------------------
@ -390,12 +383,11 @@ fn packed_to_hand_value(packed: u32) -> HandValue {
}
}
_ => {
log::error!(
log::warn!(
"Invalid hand category {} in packed value {}, falling back to HighCard",
category,
packed
);
debug_assert!(false, "Invalid hand category: {} (packed: {})", category, packed);
HandRank::HighCard
}
};