feat: add AlgorithmicEvaluator, migrate to log crate, fix flush value calculation
- Add AlgorithmicEvaluator wrapper for direct hand evaluation without lookup tables, with proper Result-based error handling - Replace all println! and #[cfg(debug_assertions)] debug output with log crate macros (log::info!, log::debug!, log::warn!) - Fix calculate_flush_value to use base-13 encoding for unique flush hand values instead of simple linear sum - Fix is_straight to use cleaner control flow for regular and wheel straight detection - Remove jump table HighCard/value=0 guard in evaluate_5_card to simplify evaluation path - Add evaluate_n_card_hand_public as pub(crate) for AlgorithmicEvaluator - Add .gitignore to exclude target/ and .idea/ from version control - Add comprehensive tests for AlgorithmicEvaluator (14 test cases) - Update README with new API usage examples - Add log dependency to Cargo.toml - Add placeholder modules for future implementations (tables_new, benchmark_utils, integration_utils, test_utils)
This commit is contained in:
parent
51e1f58ef9
commit
dd605e8a66
16 changed files with 1666 additions and 228 deletions
10
.gitignore
vendored
Normal file
10
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
# Build artifacts
|
||||
/target
|
||||
|
||||
# IDE
|
||||
.idea/
|
||||
*.iml
|
||||
|
||||
# OS
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
1145
Cargo.lock
generated
Normal file
1145
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load diff
44
README.md
44
README.md
|
|
@ -1,7 +1,7 @@
|
|||
# Poker Testbed - Java-Compatible Hand Evaluator for Bot Testing
|
||||
|
||||
[](https://crates.io/crates/poker-api)
|
||||
[](https://docs.rs/poker-api)
|
||||
[](https://crates.io/crates/holdem_core)
|
||||
[](https://docs.rs/holdem_core)
|
||||
[](LICENSE)
|
||||
|
||||
A comprehensive poker bot testing framework with Java-compatible hand evaluation. This library implements the Meerkat API algorithm with full Java compatibility, specifically designed for automated poker bot testing, development, and integration with existing poker tools.
|
||||
|
|
@ -50,31 +50,39 @@ Add this to your `Cargo.toml`:
|
|||
|
||||
```toml
|
||||
[dependencies]
|
||||
poker-api = "0.1.0"
|
||||
holdem_core = "0.1.0"
|
||||
```
|
||||
|
||||
## Quick Start - Bot Testing
|
||||
|
||||
```rust
|
||||
use holdem_core::hand_evaluator::LookupHandEvaluator;
|
||||
use holdem_core::api::{hand::Hand, card::Card};
|
||||
use holdem_core::{Card, Hand, HoleCards, Board, Evaluator};
|
||||
use std::str::FromStr;
|
||||
|
||||
// Initialize Java-compatible evaluator for bot testing
|
||||
let evaluator = LookupHandEvaluator::new().unwrap();
|
||||
// Create cards from string notation
|
||||
let ace_spades = Card::from_str("As").unwrap();
|
||||
let king_spades = Card::from_str("Ks").unwrap();
|
||||
|
||||
// Create hole cards for bot analysis
|
||||
let mut hole_cards = Hand::new();
|
||||
hole_cards.add_card(Card::from_string("As").unwrap()).unwrap();
|
||||
hole_cards.add_card(Card::from_string("Ks").unwrap()).unwrap();
|
||||
// Create hole cards from notation
|
||||
let hole_cards = HoleCards::from_notation("AKs").unwrap();
|
||||
|
||||
// Evaluate hand strength for bot decision making
|
||||
let rank = evaluator.rank_hand(&hole_cards);
|
||||
println!("Hole card rank: {}", rank); // Lower = stronger hand
|
||||
// Create a board with community cards
|
||||
let board = Board::new()
|
||||
.with_flop([
|
||||
Card::from_str("Qh").unwrap(),
|
||||
Card::from_str("Jh").unwrap(),
|
||||
Card::from_str("Th").unwrap(),
|
||||
]).unwrap()
|
||||
.with_turn(Card::from_str("2c").unwrap()).unwrap()
|
||||
.with_river(Card::from_str("3d").unwrap()).unwrap();
|
||||
|
||||
// Use rank for bot strategy decisions
|
||||
if rank < 1000 { // Strong hand threshold
|
||||
println!("Bot: This is a premium starting hand!");
|
||||
}
|
||||
// Create a hand from hole cards and board
|
||||
let hand = Hand::from_hole_cards_and_board(&hole_cards, &board).unwrap();
|
||||
|
||||
// Evaluate the hand
|
||||
let evaluator = Evaluator::new().unwrap();
|
||||
let hand_value = evaluator.evaluate_hand(&hand);
|
||||
println!("Hand rank: {:?}", hand_value.rank);
|
||||
```
|
||||
|
||||
## Bot Testing Capabilities
|
||||
|
|
|
|||
|
|
@ -8,10 +8,10 @@ readme = "README.md"
|
|||
license = "MIT"
|
||||
repository = "https://github.com/jhunnius/rusty_marvin"
|
||||
documentation = "https://docs.rs/holdem_core"
|
||||
homepage = "https://github.com/your-org/holdem_core"
|
||||
homepage = "https://github.com/jhunnius/rusty_marvin"
|
||||
keywords = ["poker", "bot-testing", "texas-holdem", "testbed"]
|
||||
categories = ["games", "api-bindings", "mathematics"]
|
||||
exclude = ["docs/*", "target/*", "*.md"]
|
||||
exclude = ["docs/*", "target/*"]
|
||||
|
||||
[dependencies]
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
|
|
@ -24,6 +24,7 @@ tempfile = "3.23.0"
|
|||
once_cell = "1.19"
|
||||
chrono = { version = "0.4", features = ["serde"] }
|
||||
indicatif = "0.17"
|
||||
log = "0.4"
|
||||
|
||||
[dev-dependencies]
|
||||
proptest = "1.0"
|
||||
|
|
|
|||
67
holdem_core/src/evaluator/algorithmic_evaluator.rs
Normal file
67
holdem_core/src/evaluator/algorithmic_evaluator.rs
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
//! Algorithmic hand evaluator for direct poker hand evaluation.
|
||||
//!
|
||||
//! This module provides a standalone evaluator that uses pure algorithmic
|
||||
//! methods (no lookup tables) for evaluating poker hands. It wraps the
|
||||
//! direct evaluation logic from [`Evaluator::evaluate_5_card_direct`].
|
||||
|
||||
use crate::Card;
|
||||
use super::errors::EvaluatorError;
|
||||
use super::evaluator::{Evaluator, HandValue};
|
||||
use std::sync::Arc;
|
||||
|
||||
/// Statistics tracking for evaluation operations.
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct EvaluationStats {
|
||||
/// Total number of evaluations performed.
|
||||
pub total_evaluations: u64,
|
||||
/// Average time per evaluation in nanoseconds.
|
||||
pub average_time_ns: u64,
|
||||
/// Total time spent evaluating in nanoseconds.
|
||||
pub total_time_ns: u64,
|
||||
}
|
||||
|
||||
/// Algorithmic poker hand evaluator.
|
||||
///
|
||||
/// Performs direct hand evaluation without relying on lookup tables.
|
||||
/// Delegates to the same core algorithm used by [`Evaluator::evaluate_5_card_direct`].
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct AlgorithmicEvaluator {
|
||||
inner: Arc<Evaluator>,
|
||||
stats: EvaluationStats,
|
||||
}
|
||||
|
||||
impl AlgorithmicEvaluator {
|
||||
/// Create a new algorithmic evaluator instance.
|
||||
pub fn new() -> Result<Self, EvaluatorError> {
|
||||
let inner = Evaluator::new()?;
|
||||
Ok(Self {
|
||||
inner: Arc::new(inner),
|
||||
stats: EvaluationStats::default(),
|
||||
})
|
||||
}
|
||||
|
||||
/// Evaluate a 5-card hand directly using the algorithmic approach.
|
||||
pub fn evaluate_5_card_direct(&self, cards: &[Card; 5]) -> HandValue {
|
||||
self.inner.evaluate_5_card_direct(cards)
|
||||
}
|
||||
|
||||
/// Evaluate a 6-card hand, finding the best 5-card combination.
|
||||
pub fn evaluate_6_card(&self, cards: &[Card; 6]) -> HandValue {
|
||||
self.inner.evaluate_n_card_hand_public(cards)
|
||||
}
|
||||
|
||||
/// Evaluate a 7-card hand, finding the best 5-card combination.
|
||||
pub fn evaluate_7_card(&self, cards: &[Card; 7]) -> HandValue {
|
||||
self.inner.evaluate_n_card_hand_public(cards)
|
||||
}
|
||||
|
||||
/// Get a reference to the current evaluation statistics.
|
||||
pub fn stats(&self) -> &EvaluationStats {
|
||||
&self.stats
|
||||
}
|
||||
|
||||
/// Reset the evaluation statistics.
|
||||
pub fn reset_stats(&mut self) {
|
||||
self.stats = EvaluationStats::default();
|
||||
}
|
||||
}
|
||||
200
holdem_core/src/evaluator/algorithmic_evaluator_test.rs
Normal file
200
holdem_core/src/evaluator/algorithmic_evaluator_test.rs
Normal file
|
|
@ -0,0 +1,200 @@
|
|||
//! Tests for the algorithmic evaluator.
|
||||
|
||||
use super::algorithmic_evaluator::AlgorithmicEvaluator;
|
||||
use super::evaluator::HandRank;
|
||||
use crate::Card;
|
||||
use std::str::FromStr;
|
||||
|
||||
#[test]
|
||||
fn test_new_evaluator() {
|
||||
let evaluator = AlgorithmicEvaluator::new();
|
||||
assert!(evaluator.is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_royal_flush() {
|
||||
let evaluator = AlgorithmicEvaluator::new().unwrap();
|
||||
let cards = [
|
||||
Card::from_str("As").unwrap(),
|
||||
Card::from_str("Ks").unwrap(),
|
||||
Card::from_str("Qs").unwrap(),
|
||||
Card::from_str("Js").unwrap(),
|
||||
Card::from_str("Ts").unwrap(),
|
||||
];
|
||||
let result = evaluator.evaluate_5_card_direct(&cards);
|
||||
assert_eq!(result.rank, HandRank::RoyalFlush);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_straight_flush() {
|
||||
let evaluator = AlgorithmicEvaluator::new().unwrap();
|
||||
let cards = [
|
||||
Card::from_str("9s").unwrap(),
|
||||
Card::from_str("Ks").unwrap(),
|
||||
Card::from_str("Qs").unwrap(),
|
||||
Card::from_str("Js").unwrap(),
|
||||
Card::from_str("Ts").unwrap(),
|
||||
];
|
||||
let result = evaluator.evaluate_5_card_direct(&cards);
|
||||
assert_eq!(result.rank, HandRank::StraightFlush);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_four_of_a_kind() {
|
||||
let evaluator = AlgorithmicEvaluator::new().unwrap();
|
||||
let cards = [
|
||||
Card::from_str("As").unwrap(),
|
||||
Card::from_str("Ah").unwrap(),
|
||||
Card::from_str("Ad").unwrap(),
|
||||
Card::from_str("Ac").unwrap(),
|
||||
Card::from_str("Ks").unwrap(),
|
||||
];
|
||||
let result = evaluator.evaluate_5_card_direct(&cards);
|
||||
assert_eq!(result.rank, HandRank::FourOfAKind);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_full_house() {
|
||||
let evaluator = AlgorithmicEvaluator::new().unwrap();
|
||||
let cards = [
|
||||
Card::from_str("As").unwrap(),
|
||||
Card::from_str("Ah").unwrap(),
|
||||
Card::from_str("Ad").unwrap(),
|
||||
Card::from_str("Ks").unwrap(),
|
||||
Card::from_str("Kh").unwrap(),
|
||||
];
|
||||
let result = evaluator.evaluate_5_card_direct(&cards);
|
||||
assert_eq!(result.rank, HandRank::FullHouse);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_flush() {
|
||||
let evaluator = AlgorithmicEvaluator::new().unwrap();
|
||||
let cards = [
|
||||
Card::from_str("As").unwrap(),
|
||||
Card::from_str("Ks").unwrap(),
|
||||
Card::from_str("Qs").unwrap(),
|
||||
Card::from_str("Js").unwrap(),
|
||||
Card::from_str("9s").unwrap(),
|
||||
];
|
||||
let result = evaluator.evaluate_5_card_direct(&cards);
|
||||
assert_eq!(result.rank, HandRank::Flush);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_straight() {
|
||||
let evaluator = AlgorithmicEvaluator::new().unwrap();
|
||||
let cards = [
|
||||
Card::from_str("As").unwrap(),
|
||||
Card::from_str("Kh").unwrap(),
|
||||
Card::from_str("Qd").unwrap(),
|
||||
Card::from_str("Jc").unwrap(),
|
||||
Card::from_str("Ts").unwrap(),
|
||||
];
|
||||
let result = evaluator.evaluate_5_card_direct(&cards);
|
||||
assert_eq!(result.rank, HandRank::Straight);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_wheel_straight() {
|
||||
let evaluator = AlgorithmicEvaluator::new().unwrap();
|
||||
let cards = [
|
||||
Card::from_str("As").unwrap(),
|
||||
Card::from_str("2h").unwrap(),
|
||||
Card::from_str("3d").unwrap(),
|
||||
Card::from_str("4c").unwrap(),
|
||||
Card::from_str("5s").unwrap(),
|
||||
];
|
||||
let result = evaluator.evaluate_5_card_direct(&cards);
|
||||
assert_eq!(result.rank, HandRank::Straight);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_three_of_a_kind() {
|
||||
let evaluator = AlgorithmicEvaluator::new().unwrap();
|
||||
let cards = [
|
||||
Card::from_str("As").unwrap(),
|
||||
Card::from_str("Ah").unwrap(),
|
||||
Card::from_str("Ad").unwrap(),
|
||||
Card::from_str("Ks").unwrap(),
|
||||
Card::from_str("Qh").unwrap(),
|
||||
];
|
||||
let result = evaluator.evaluate_5_card_direct(&cards);
|
||||
assert_eq!(result.rank, HandRank::ThreeOfAKind);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_two_pair() {
|
||||
let evaluator = AlgorithmicEvaluator::new().unwrap();
|
||||
let cards = [
|
||||
Card::from_str("As").unwrap(),
|
||||
Card::from_str("Ah").unwrap(),
|
||||
Card::from_str("Ks").unwrap(),
|
||||
Card::from_str("Kh").unwrap(),
|
||||
Card::from_str("Qd").unwrap(),
|
||||
];
|
||||
let result = evaluator.evaluate_5_card_direct(&cards);
|
||||
assert_eq!(result.rank, HandRank::TwoPair);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pair() {
|
||||
let evaluator = AlgorithmicEvaluator::new().unwrap();
|
||||
let cards = [
|
||||
Card::from_str("As").unwrap(),
|
||||
Card::from_str("Ah").unwrap(),
|
||||
Card::from_str("Ks").unwrap(),
|
||||
Card::from_str("Qh").unwrap(),
|
||||
Card::from_str("Jd").unwrap(),
|
||||
];
|
||||
let result = evaluator.evaluate_5_card_direct(&cards);
|
||||
assert_eq!(result.rank, HandRank::Pair);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_high_card() {
|
||||
let evaluator = AlgorithmicEvaluator::new().unwrap();
|
||||
let cards = [
|
||||
Card::from_str("As").unwrap(),
|
||||
Card::from_str("Kh").unwrap(),
|
||||
Card::from_str("Qd").unwrap(),
|
||||
Card::from_str("Jc").unwrap(),
|
||||
Card::from_str("9s").unwrap(),
|
||||
];
|
||||
let result = evaluator.evaluate_5_card_direct(&cards);
|
||||
assert_eq!(result.rank, HandRank::HighCard);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hand_rank_ordering() {
|
||||
let evaluator = AlgorithmicEvaluator::new().unwrap();
|
||||
|
||||
let royal_flush = [
|
||||
Card::from_str("As").unwrap(),
|
||||
Card::from_str("Ks").unwrap(),
|
||||
Card::from_str("Qs").unwrap(),
|
||||
Card::from_str("Js").unwrap(),
|
||||
Card::from_str("Ts").unwrap(),
|
||||
];
|
||||
let four_of_a_kind = [
|
||||
Card::from_str("As").unwrap(),
|
||||
Card::from_str("Ah").unwrap(),
|
||||
Card::from_str("Ad").unwrap(),
|
||||
Card::from_str("Ac").unwrap(),
|
||||
Card::from_str("Ks").unwrap(),
|
||||
];
|
||||
|
||||
let rf = evaluator.evaluate_5_card_direct(&royal_flush);
|
||||
let foak = evaluator.evaluate_5_card_direct(&four_of_a_kind);
|
||||
|
||||
assert!(rf.rank as u8 > foak.rank as u8);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_stats_initially_default() {
|
||||
let evaluator = AlgorithmicEvaluator::new().unwrap();
|
||||
let stats = evaluator.stats();
|
||||
assert_eq!(stats.total_evaluations, 0);
|
||||
assert_eq!(stats.average_time_ns, 0);
|
||||
assert_eq!(stats.total_time_ns, 0);
|
||||
}
|
||||
4
holdem_core/src/evaluator/benchmark_utils.rs
Normal file
4
holdem_core/src/evaluator/benchmark_utils.rs
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
//! Benchmark utilities for the hand evaluator.
|
||||
//!
|
||||
//! This module provides helper functions and data structures for benchmarking
|
||||
//! hand evaluation performance.
|
||||
|
|
@ -321,12 +321,12 @@ impl JumpTableBenchmark {
|
|||
|
||||
/// Print benchmark results in a formatted table
|
||||
pub fn print_results(&self, results: &[BenchmarkResult]) {
|
||||
println!("\n=== Jump Table Performance Benchmarks ===");
|
||||
println!("{:<20} {:<15} {:<15} {:<15} {}",
|
||||
log::info!("\n=== Jump Table Performance Benchmarks ===");
|
||||
log::info!("{:<20} {:<15} {:<15} {:<15} {}",
|
||||
"Test", "Total Time", "Avg Time/Op", "Ops/Second", "Memory");
|
||||
|
||||
for result in results {
|
||||
println!(
|
||||
log::info!(
|
||||
"{:<20} {:<15} {:<15} {:<15.0} {}",
|
||||
result.name,
|
||||
format!("{:.2?}", result.total_time),
|
||||
|
|
@ -339,7 +339,7 @@ impl JumpTableBenchmark {
|
|||
);
|
||||
}
|
||||
|
||||
println!("\n=== Performance Requirements Check ===");
|
||||
log::info!("\n=== Performance Requirements Check ===");
|
||||
self.check_performance_requirements(results);
|
||||
}
|
||||
|
||||
|
|
@ -350,7 +350,7 @@ impl JumpTableBenchmark {
|
|||
"5-Card Evaluation" => {
|
||||
let target_ns = 100; // Target: 100 nanoseconds
|
||||
let actual_ns = result.avg_time_per_op.as_nanos() as u64;
|
||||
println!(
|
||||
log::info!(
|
||||
"5-Card Evaluation: {} ns (target: {} ns) - {}",
|
||||
actual_ns,
|
||||
target_ns,
|
||||
|
|
@ -360,7 +360,7 @@ impl JumpTableBenchmark {
|
|||
"6-Card Evaluation" => {
|
||||
let target_ns = 500; // Target: 500 nanoseconds
|
||||
let actual_ns = result.avg_time_per_op.as_nanos() as u64;
|
||||
println!(
|
||||
log::info!(
|
||||
"6-Card Evaluation: {} ns (target: {} ns) - {}",
|
||||
actual_ns,
|
||||
target_ns,
|
||||
|
|
@ -370,7 +370,7 @@ impl JumpTableBenchmark {
|
|||
"7-Card Evaluation" => {
|
||||
let target_us = 2; // Target: 2 microseconds
|
||||
let actual_us = result.avg_time_per_op.as_micros() as u64;
|
||||
println!(
|
||||
log::info!(
|
||||
"7-Card Evaluation: {} μs (target: {} μs) - {}",
|
||||
actual_us,
|
||||
target_us,
|
||||
|
|
@ -381,7 +381,7 @@ impl JumpTableBenchmark {
|
|||
let target_mb = 130; // Target: 130 MB
|
||||
if let Some(bytes) = result.memory_usage {
|
||||
let actual_mb = bytes / 1_000_000;
|
||||
println!(
|
||||
log::info!(
|
||||
"Memory Usage: {} MB (target: {} MB) - {}",
|
||||
actual_mb,
|
||||
target_mb,
|
||||
|
|
|
|||
|
|
@ -145,101 +145,88 @@ impl HandValue {
|
|||
}
|
||||
|
||||
// DEBUG: Log the flat rank being processed
|
||||
#[cfg(debug_assertions)]
|
||||
println!("DEBUG: Processing flat_rank: {}", flat_rank);
|
||||
log::debug!("Processing flat_rank: {}", flat_rank);
|
||||
|
||||
// Find which rank this flat_rank belongs to using proper poker hand distribution
|
||||
let result = match flat_rank {
|
||||
1..=1_302_539 => {
|
||||
#[cfg(debug_assertions)]
|
||||
println!("DEBUG: Mapping to HighCard with value {}", flat_rank);
|
||||
log::debug!("Mapping to HighCard with value {}", flat_rank);
|
||||
Self::new(HandRank::HighCard, flat_rank)
|
||||
}
|
||||
1_302_540..=2_400_779 => {
|
||||
#[cfg(debug_assertions)]
|
||||
println!(
|
||||
"DEBUG: Mapping to Pair with value {}",
|
||||
log::debug!(
|
||||
"Mapping to Pair with value {}",
|
||||
flat_rank - 1_302_540
|
||||
);
|
||||
Self::new(HandRank::Pair, flat_rank - 1_302_540)
|
||||
}
|
||||
2_400_780..=2_524_331 => {
|
||||
#[cfg(debug_assertions)]
|
||||
println!(
|
||||
"DEBUG: Mapping to TwoPair with value {}",
|
||||
log::debug!(
|
||||
"Mapping to TwoPair with value {}",
|
||||
flat_rank - 2_400_780
|
||||
);
|
||||
Self::new(HandRank::TwoPair, flat_rank - 2_400_780)
|
||||
}
|
||||
2_524_332..=2_579_243 => {
|
||||
#[cfg(debug_assertions)]
|
||||
println!(
|
||||
"DEBUG: Mapping to ThreeOfAKind with value {}",
|
||||
log::debug!(
|
||||
"Mapping to ThreeOfAKind with value {}",
|
||||
flat_rank - 2_524_332
|
||||
);
|
||||
Self::new(HandRank::ThreeOfAKind, flat_rank - 2_524_332)
|
||||
}
|
||||
2_579_244..=2_589_443 => {
|
||||
#[cfg(debug_assertions)]
|
||||
println!(
|
||||
"DEBUG: Mapping to Straight with value {}",
|
||||
log::debug!(
|
||||
"Mapping to Straight with value {}",
|
||||
flat_rank - 2_579_244
|
||||
);
|
||||
Self::new(HandRank::Straight, flat_rank - 2_579_244)
|
||||
}
|
||||
2_589_444..=2_594_551 => {
|
||||
#[cfg(debug_assertions)]
|
||||
println!(
|
||||
"DEBUG: Mapping to Flush with value {}",
|
||||
log::debug!(
|
||||
"Mapping to Flush with value {}",
|
||||
flat_rank - 2_589_444
|
||||
);
|
||||
Self::new(HandRank::Flush, flat_rank - 2_589_444)
|
||||
}
|
||||
2_594_552..=2_598_295 => {
|
||||
#[cfg(debug_assertions)]
|
||||
println!(
|
||||
"DEBUG: Mapping to FullHouse with value {}",
|
||||
log::debug!(
|
||||
"Mapping to FullHouse with value {}",
|
||||
flat_rank - 2_594_552
|
||||
);
|
||||
Self::new(HandRank::FullHouse, flat_rank - 2_594_552)
|
||||
}
|
||||
2_598_296..=2_598_919 => {
|
||||
#[cfg(debug_assertions)]
|
||||
println!(
|
||||
"DEBUG: Mapping to FourOfAKind with value {}",
|
||||
log::debug!(
|
||||
"Mapping to FourOfAKind with value {}",
|
||||
flat_rank - 2_598_296
|
||||
);
|
||||
Self::new(HandRank::FourOfAKind, flat_rank - 2_598_296)
|
||||
}
|
||||
2_598_920..=2_598_955 => {
|
||||
#[cfg(debug_assertions)]
|
||||
println!(
|
||||
"DEBUG: Mapping to StraightFlush with value {}",
|
||||
log::debug!(
|
||||
"Mapping to StraightFlush with value {}",
|
||||
flat_rank - 2_598_920
|
||||
);
|
||||
Self::new(HandRank::StraightFlush, flat_rank - 2_598_920)
|
||||
}
|
||||
2_598_956..=2_598_959 => {
|
||||
#[cfg(debug_assertions)]
|
||||
println!(
|
||||
"DEBUG: Mapping to RoyalFlush with value {}",
|
||||
log::debug!(
|
||||
"Mapping to RoyalFlush with value {}",
|
||||
flat_rank - 2_598_956
|
||||
);
|
||||
Self::new(HandRank::RoyalFlush, flat_rank - 2_598_956)
|
||||
}
|
||||
_ => {
|
||||
// Out of range, fallback to high card
|
||||
#[cfg(debug_assertions)]
|
||||
println!(
|
||||
"DEBUG: Out of range, falling back to HighCard with value {}",
|
||||
log::debug!(
|
||||
"Out of range, falling back to HighCard with value {}",
|
||||
flat_rank
|
||||
);
|
||||
Self::new(HandRank::HighCard, flat_rank)
|
||||
}
|
||||
};
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
println!("DEBUG: Result: {:?}", result);
|
||||
log::debug!("Result: {:?}", result);
|
||||
result
|
||||
}
|
||||
|
||||
|
|
@ -634,11 +621,11 @@ impl Evaluator {
|
|||
if JumpTable::exists(&path) {
|
||||
match JumpTable::load_from_file(&path) {
|
||||
Ok(table) => {
|
||||
println!("Loaded existing jump table from: {}", path.display());
|
||||
log::info!("Loaded existing jump table from: {}", path.display());
|
||||
return Ok(table);
|
||||
}
|
||||
Err(e) => {
|
||||
println!(
|
||||
log::warn!(
|
||||
"Failed to load existing jump table ({}), creating new one...",
|
||||
e
|
||||
);
|
||||
|
|
@ -652,7 +639,7 @@ impl Evaluator {
|
|||
|
||||
/// Create a new jump table and save it to file
|
||||
fn create_and_save_table(path: &Path) -> Result<JumpTable, EvaluatorError> {
|
||||
println!("Creating new jump table...");
|
||||
log::info!("Creating new jump table...");
|
||||
let mut table = JumpTable::with_target_memory();
|
||||
|
||||
// Build the jump table with proper evaluation data
|
||||
|
|
@ -668,7 +655,7 @@ impl Evaluator {
|
|||
EvaluatorError::table_init_failed(&format!("Failed to save jump table: {}", e))
|
||||
})?;
|
||||
|
||||
println!(
|
||||
log::info!(
|
||||
"Evaluator created successfully with {} table entries and saved to: {}",
|
||||
table.size,
|
||||
path.display()
|
||||
|
|
@ -696,11 +683,7 @@ impl Evaluator {
|
|||
let packed_array: [PackedCard; 5] = packed_cards.try_into().unwrap();
|
||||
|
||||
if let Ok(result) = self.tables.evaluate_5_card(&packed_array) {
|
||||
// Only use jump table result if it's not the default HighCard with value 0
|
||||
// This indicates the jump table lookup succeeded
|
||||
if result.rank != HandRank::HighCard || result.value != 0 {
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -771,6 +754,12 @@ impl Evaluator {
|
|||
best_hand_value
|
||||
}
|
||||
|
||||
/// Crate-internal wrapper for evaluating an N-card hand by finding the best 5-card combination.
|
||||
/// Used by [`AlgorithmicEvaluator`](super::algorithmic_evaluator::AlgorithmicEvaluator).
|
||||
pub(crate) fn evaluate_n_card_hand_public<T: AsRef<[Card]>>(&self, cards: T) -> HandValue {
|
||||
self.evaluate_n_card_hand(cards)
|
||||
}
|
||||
|
||||
/// Generate all combinations of K elements from a set of N elements
|
||||
fn generate_combinations(&self, set: &[usize], k: usize) -> Vec<Vec<usize>> {
|
||||
let mut result = Vec::new();
|
||||
|
|
@ -909,17 +898,19 @@ impl Evaluator {
|
|||
|
||||
/// Check if ranks form a straight
|
||||
fn is_straight(&self, ranks: &[u8; 5]) -> bool {
|
||||
// Check for regular straight (consecutive ranks)
|
||||
// Check for regular straight (consecutive ranks descending)
|
||||
let mut is_regular = true;
|
||||
for i in 0..4 {
|
||||
if ranks[i] != ranks[i + 1] + 1 {
|
||||
// Check for wheel straight (A,2,3,4,5)
|
||||
if *ranks == [12, 3, 2, 1, 0] {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
is_regular = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
true
|
||||
if is_regular {
|
||||
return true;
|
||||
}
|
||||
// Check for wheel straight: A,2,3,4,5 → sorted desc: [12,3,2,1,0]
|
||||
*ranks == [12, 3, 2, 1, 0]
|
||||
}
|
||||
|
||||
/// Check if hand has N of a kind
|
||||
|
|
@ -983,9 +974,9 @@ impl Evaluator {
|
|||
/// Calculate value for flush
|
||||
fn calculate_flush_value(&self, ranks: &[u8; 5]) -> u32 {
|
||||
// For flush, value is based on highest card, then next highest, etc.
|
||||
// Use minimal range to ensure flush values stay within expected bounds
|
||||
// Simple linear combination to ensure values stay in range
|
||||
ranks[0] as u32 * 1 + ranks[1] as u32 + ranks[2] as u32 + ranks[3] as u32 + ranks[4] as u32
|
||||
// Use base-13 encoding to ensure unique values for different flush hands
|
||||
ranks[0] as u32 * 28561 + ranks[1] as u32 * 2197
|
||||
+ ranks[2] as u32 * 169 + ranks[3] as u32 * 13 + ranks[4] as u32
|
||||
}
|
||||
|
||||
/// Calculate value for three of a kind
|
||||
|
|
@ -1094,7 +1085,7 @@ impl Evaluator {
|
|||
// Validate that the table was built correctly
|
||||
table.validate()?;
|
||||
|
||||
println!(
|
||||
log::info!(
|
||||
"Evaluator created successfully with {} table entries (no persistence)",
|
||||
table.size
|
||||
);
|
||||
|
|
@ -1108,7 +1099,7 @@ impl Evaluator {
|
|||
pub fn regenerate_table(&mut self) -> Result<(), EvaluatorError> {
|
||||
let path = JumpTable::default_file_path();
|
||||
|
||||
println!("Regenerating jump table...");
|
||||
log::info!("Regenerating jump table...");
|
||||
let mut table = JumpTable::with_target_memory();
|
||||
|
||||
// Build the jump table with proper evaluation data
|
||||
|
|
@ -1127,7 +1118,7 @@ impl Evaluator {
|
|||
// Update the evaluator's table
|
||||
self.tables = Arc::new(table);
|
||||
|
||||
println!("Jump table regenerated and saved successfully");
|
||||
log::info!("Jump table regenerated and saved successfully");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -1139,7 +1130,7 @@ impl Evaluator {
|
|||
/// Validate the compressed ranking system
|
||||
/// Ensures all 7,462 distinct hands are properly represented and comparison semantics are preserved
|
||||
pub fn validate_compressed_ranking(&self) -> Result<(), EvaluatorError> {
|
||||
println!("Validating compressed ranking system...");
|
||||
log::info!("Validating compressed ranking system...");
|
||||
|
||||
// Test 1: Ensure all compressed ranks are within 0-7461 range
|
||||
let mut compressed_ranks = std::collections::HashSet::new();
|
||||
|
|
@ -1366,9 +1357,9 @@ impl Evaluator {
|
|||
}
|
||||
}
|
||||
|
||||
println!("Compressed ranking validation completed successfully!");
|
||||
println!("Tested {} unique compressed ranks", compressed_ranks.len());
|
||||
println!("Range: {} - {}", min_rank, max_rank);
|
||||
log::info!("Compressed ranking validation completed successfully!");
|
||||
log::info!("Tested {} unique compressed ranks", compressed_ranks.len());
|
||||
log::info!("Range: {} - {}", min_rank, max_rank);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ use std::time::Instant;
|
|||
|
||||
/// Basic usage example demonstrating core functionality
|
||||
pub fn basic_usage_example() -> Result<(), EvaluatorError> {
|
||||
println!("=== Basic Usage Example ===");
|
||||
log::info!("=== Basic Usage Example ===");
|
||||
|
||||
// Create a 7-card poker hand
|
||||
let cards = [
|
||||
|
|
@ -35,7 +35,7 @@ pub fn basic_usage_example() -> Result<(), EvaluatorError> {
|
|||
Card::from_str("6d").unwrap(),
|
||||
];
|
||||
|
||||
println!(
|
||||
log::info!(
|
||||
"Evaluating hand: {:?}",
|
||||
cards.iter().map(|c| c.to_string()).collect::<Vec<_>>()
|
||||
);
|
||||
|
|
@ -44,7 +44,7 @@ pub fn basic_usage_example() -> Result<(), EvaluatorError> {
|
|||
let mut math_evaluator = MathEvaluator::new()?;
|
||||
let result1 = math_evaluator.evaluate_7_card(&cards);
|
||||
|
||||
println!("MathEvaluator result: {:?}", result1);
|
||||
log::info!("MathEvaluator result: {:?}", result1);
|
||||
|
||||
// Method 2: Using JumpTable directly (for advanced use cases)
|
||||
let mut table = JumpTable::with_target_memory();
|
||||
|
|
@ -54,18 +54,18 @@ pub fn basic_usage_example() -> Result<(), EvaluatorError> {
|
|||
let packed_array: [PackedCard; 7] = packed_cards.try_into().unwrap();
|
||||
let result2 = table.evaluate_7_card(&packed_array);
|
||||
|
||||
println!("JumpTable result: {:?}", result2);
|
||||
log::info!("JumpTable result: {:?}", result2);
|
||||
|
||||
// Results should be identical
|
||||
assert_eq!(result1, result2.unwrap());
|
||||
|
||||
println!("✓ Basic evaluation complete\n");
|
||||
log::info!("✓ Basic evaluation complete\n");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Performance benchmarking example
|
||||
pub fn performance_example() -> Result<(), EvaluatorError> {
|
||||
println!("=== Performance Benchmarking Example ===");
|
||||
log::info!("=== Performance Benchmarking Example ===");
|
||||
|
||||
// Create test hands of different types
|
||||
let test_hands = vec![
|
||||
|
|
@ -121,7 +121,7 @@ pub fn performance_example() -> Result<(), EvaluatorError> {
|
|||
|
||||
let mut math_evaluator = MathEvaluator::new()?;
|
||||
|
||||
println!("Benchmarking {} hand types...", test_hands.len());
|
||||
log::info!("Benchmarking {} hand types...", test_hands.len());
|
||||
|
||||
for (hand_type, cards) in test_hands {
|
||||
let iterations = 10000;
|
||||
|
|
@ -135,23 +135,23 @@ pub fn performance_example() -> Result<(), EvaluatorError> {
|
|||
let elapsed = start_time.elapsed();
|
||||
let avg_time = elapsed / iterations;
|
||||
|
||||
println!(" {}: {:?}", hand_type, avg_time);
|
||||
log::info!(" {}: {:?}", hand_type, avg_time);
|
||||
}
|
||||
|
||||
// Display evaluator statistics
|
||||
let stats = math_evaluator.stats();
|
||||
println!("\nEvaluator Statistics:");
|
||||
println!(" Total evaluations: {}", stats.total_evaluations);
|
||||
println!(" Average time: {} ns", stats.average_time_ns);
|
||||
println!(" Total time: {} ms", stats.total_time_ns / 1_000_000);
|
||||
log::info!("\nEvaluator Statistics:");
|
||||
log::info!(" Total evaluations: {}", stats.total_evaluations);
|
||||
log::info!(" Average time: {} ns", stats.average_time_ns);
|
||||
log::info!(" Total time: {} ms", stats.total_time_ns / 1_000_000);
|
||||
|
||||
println!("✓ Performance benchmarking complete\n");
|
||||
log::info!("✓ Performance benchmarking complete\n");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Integration example showing compatibility with holdem_core
|
||||
pub fn integration_example() -> Result<(), EvaluatorError> {
|
||||
println!("=== Integration Example ===");
|
||||
log::info!("=== Integration Example ===");
|
||||
|
||||
// Create hands using holdem_core
|
||||
let hole_cards = crate::HoleCards::from_notation("AKs")
|
||||
|
|
@ -160,10 +160,10 @@ pub fn integration_example() -> Result<(), EvaluatorError> {
|
|||
let hand = Hand::from_hole_cards_and_board(&hole_cards, &board)
|
||||
.map_err(|_| EvaluatorError::table_init_failed("Invalid hand"))?;
|
||||
|
||||
println!("Evaluating complete hand:");
|
||||
println!(" Hole cards: {}", hole_cards);
|
||||
println!(" Board: {}", board);
|
||||
println!(" Complete hand: {}", hand);
|
||||
log::info!("Evaluating complete hand:");
|
||||
log::info!(" Hole cards: {}", hole_cards);
|
||||
log::info!(" Board: {}", board);
|
||||
log::info!(" Complete hand: {}", hand);
|
||||
|
||||
// Compare results between math and holdem_core evaluators
|
||||
let mut comparison = EvaluatorComparison::new()?;
|
||||
|
|
@ -171,40 +171,40 @@ pub fn integration_example() -> Result<(), EvaluatorError> {
|
|||
let math_result = comparison.math_evaluator.evaluate_hand(&hand);
|
||||
let core_result = comparison.core_evaluator.evaluate_hand(&hand);
|
||||
|
||||
println!("\nEvaluation Results:");
|
||||
println!(" Math evaluator: {:?}", math_result);
|
||||
println!(" Core evaluator: {:?}", core_result);
|
||||
println!(" Results match: {}", math_result == core_result);
|
||||
log::info!("\nEvaluation Results:");
|
||||
log::info!(" Math evaluator: {:?}", math_result);
|
||||
log::info!(" Core evaluator: {:?}", core_result);
|
||||
log::info!(" Results match: {}", math_result == core_result);
|
||||
|
||||
// Test type conversion utilities
|
||||
let cards = hand.cards();
|
||||
let packed_cards = super::integration::convert_cards(&cards);
|
||||
let converted_back = super::integration::convert_cards_back(&packed_cards)?;
|
||||
|
||||
println!("\nType Conversion Test:");
|
||||
println!(
|
||||
log::info!("\nType Conversion Test:");
|
||||
log::info!(
|
||||
" Original: {:?}",
|
||||
cards.iter().map(|c| c.to_string()).collect::<Vec<_>>()
|
||||
);
|
||||
println!(
|
||||
log::info!(
|
||||
" Converted back: {:?}",
|
||||
converted_back
|
||||
.iter()
|
||||
.map(|c| c.to_string())
|
||||
.collect::<Vec<_>>()
|
||||
);
|
||||
println!(
|
||||
log::info!(
|
||||
" Conversion successful: {}",
|
||||
cards.len() == converted_back.len()
|
||||
);
|
||||
|
||||
println!("✓ Integration example complete\n");
|
||||
log::info!("✓ Integration example complete\n");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Canonical mapping example demonstrating suit canonicalization
|
||||
pub fn canonicalization_example() -> Result<(), EvaluatorError> {
|
||||
println!("=== Canonical Mapping Example ===");
|
||||
log::info!("=== Canonical Mapping Example ===");
|
||||
|
||||
// Create cards with different suit patterns
|
||||
let test_cases = vec![
|
||||
|
|
@ -240,12 +240,12 @@ pub fn canonicalization_example() -> Result<(), EvaluatorError> {
|
|||
];
|
||||
|
||||
for (description, cards) in test_cases {
|
||||
println!("Testing: {}", description);
|
||||
log::info!("Testing: {}", description);
|
||||
|
||||
let mapping = CanonicalMapping::from_cards(&cards);
|
||||
|
||||
println!(" Original suits: {:?}", extract_suits(&cards));
|
||||
println!(
|
||||
log::info!(" Original suits: {:?}", extract_suits(&cards));
|
||||
log::info!(
|
||||
" Canonical suits: {:?}",
|
||||
mapping
|
||||
.canonical_cards
|
||||
|
|
@ -253,46 +253,46 @@ pub fn canonicalization_example() -> Result<(), EvaluatorError> {
|
|||
.map(|&c| c & 0x03)
|
||||
.collect::<Vec<_>>()
|
||||
);
|
||||
println!(" Suit mapping: {:?}", mapping.suit_map);
|
||||
println!(" Reverse mapping: {:?}", mapping.reverse_map);
|
||||
log::info!(" Suit mapping: {:?}", mapping.suit_map);
|
||||
log::info!(" Reverse mapping: {:?}", mapping.reverse_map);
|
||||
|
||||
// Verify round-trip conversion
|
||||
let original_suits = mapping.to_original_suits(&mapping.canonical_cards);
|
||||
println!(
|
||||
log::info!(
|
||||
" Round-trip successful: {}",
|
||||
original_suits.len() == cards.len()
|
||||
);
|
||||
|
||||
println!();
|
||||
log::info!("");
|
||||
}
|
||||
|
||||
println!("✓ Canonical mapping example complete\n");
|
||||
log::info!("✓ Canonical mapping example complete\n");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Advanced configuration example
|
||||
pub fn advanced_configuration_example() -> Result<(), EvaluatorError> {
|
||||
println!("=== Advanced Configuration Example ===");
|
||||
log::info!("=== Advanced Configuration Example ===");
|
||||
|
||||
// Create custom jump table with specific size
|
||||
let custom_size = 25_000_000; // 25M entries
|
||||
let mut table = JumpTable::new(custom_size);
|
||||
|
||||
println!("Creating custom jump table with {} entries...", custom_size);
|
||||
log::info!("Creating custom jump table with {} entries...", custom_size);
|
||||
|
||||
let build_start = Instant::now();
|
||||
table.build()?;
|
||||
let build_time = build_start.elapsed();
|
||||
|
||||
println!("Table built in {:?}", build_time);
|
||||
println!(
|
||||
log::info!("Table built in {:?}", build_time);
|
||||
log::info!(
|
||||
"Memory usage: {:.2} MB",
|
||||
table.memory_usage() as f64 / 1_000_000.0
|
||||
);
|
||||
|
||||
// Validate table integrity
|
||||
table.validate()?;
|
||||
println!("Table validation: ✓ Passed");
|
||||
log::info!("Table validation: ✓ Passed");
|
||||
|
||||
// Test evaluation with custom table
|
||||
let test_cards = [
|
||||
|
|
@ -309,27 +309,27 @@ pub fn advanced_configuration_example() -> Result<(), EvaluatorError> {
|
|||
let packed_array: [PackedCard; 7] = packed_cards.try_into().unwrap();
|
||||
let result = table.evaluate_7_card(&packed_array);
|
||||
|
||||
println!("Custom table evaluation result: {:?}", result);
|
||||
log::info!("Custom table evaluation result: {:?}", result);
|
||||
|
||||
// Display table metadata
|
||||
println!("\nTable Metadata:");
|
||||
println!(" Version: {}", table.metadata.version);
|
||||
println!(" Created: {}", table.metadata.created_at);
|
||||
println!(
|
||||
log::info!("\nTable Metadata:");
|
||||
log::info!(" Version: {}", table.metadata.version);
|
||||
log::info!(" Created: {}", table.metadata.created_at);
|
||||
log::info!(
|
||||
" Total combinations: {}",
|
||||
table.metadata.total_combinations
|
||||
);
|
||||
println!(" Level 5 nodes: {}", table.metadata.stats.level5_nodes);
|
||||
println!(" Level 6 nodes: {}", table.metadata.stats.level6_nodes);
|
||||
println!(" Level 7 nodes: {}", table.metadata.stats.level7_nodes);
|
||||
log::info!(" Level 5 nodes: {}", table.metadata.stats.level5_nodes);
|
||||
log::info!(" Level 6 nodes: {}", table.metadata.stats.level6_nodes);
|
||||
log::info!(" Level 7 nodes: {}", table.metadata.stats.level7_nodes);
|
||||
|
||||
println!("✓ Advanced configuration example complete\n");
|
||||
log::info!("✓ Advanced configuration example complete\n");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Memory optimization example
|
||||
pub fn memory_optimization_example() -> Result<(), EvaluatorError> {
|
||||
println!("=== Memory Optimization Example ===");
|
||||
log::info!("=== Memory Optimization Example ===");
|
||||
|
||||
// Compare different table sizes
|
||||
let sizes = vec![10_000_000, 20_000_000, 30_000_000, 34_000_000];
|
||||
|
|
@ -343,7 +343,7 @@ pub fn memory_optimization_example() -> Result<(), EvaluatorError> {
|
|||
|
||||
let memory_mb = table.memory_usage() as f64 / 1_000_000.0;
|
||||
|
||||
println!(
|
||||
log::info!(
|
||||
"Size: {:8} entries | Memory: {:6.1} MB | Build time: {:?}",
|
||||
size, memory_mb, build_time
|
||||
);
|
||||
|
|
@ -356,22 +356,22 @@ pub fn memory_optimization_example() -> Result<(), EvaluatorError> {
|
|||
let target_table = JumpTable::with_target_memory();
|
||||
let target_memory = target_table.memory_usage() as f64 / 1_000_000.0;
|
||||
|
||||
println!("\nTarget configuration:");
|
||||
println!(" Memory usage: {:.1} MB", target_memory);
|
||||
println!(" Recommended for production use: ✓");
|
||||
log::info!("\nTarget configuration:");
|
||||
log::info!(" Memory usage: {:.1} MB", target_memory);
|
||||
log::info!(" Recommended for production use: ✓");
|
||||
|
||||
println!("✓ Memory optimization example complete\n");
|
||||
log::info!("✓ Memory optimization example complete\n");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Error handling example
|
||||
pub fn error_handling_example() -> Result<(), EvaluatorError> {
|
||||
println!("=== Error Handling Example ===");
|
||||
log::info!("=== Error Handling Example ===");
|
||||
|
||||
// Demonstrate proper error handling
|
||||
match MathEvaluator::new() {
|
||||
Ok(mut evaluator) => {
|
||||
println!("✓ MathEvaluator created successfully");
|
||||
log::info!("✓ MathEvaluator created successfully");
|
||||
|
||||
// Test with valid input
|
||||
let valid_cards = [
|
||||
|
|
@ -385,10 +385,10 @@ pub fn error_handling_example() -> Result<(), EvaluatorError> {
|
|||
];
|
||||
|
||||
let result = evaluator.evaluate_7_card(&valid_cards);
|
||||
println!("✓ Evaluation successful: {:?}", result);
|
||||
log::info!("✓ Evaluation successful: {:?}", result);
|
||||
}
|
||||
Err(e) => {
|
||||
println!("✗ Failed to create MathEvaluator: {:?}", e);
|
||||
log::info!("✗ Failed to create MathEvaluator: {:?}", e);
|
||||
return Err(e);
|
||||
}
|
||||
}
|
||||
|
|
@ -405,23 +405,23 @@ pub fn error_handling_example() -> Result<(), EvaluatorError> {
|
|||
}
|
||||
|
||||
match table.validate() {
|
||||
Ok(()) => println!("✓ Table validation passed"),
|
||||
Err(e) => println!("✗ Table validation failed: {:?}", e),
|
||||
Ok(()) => log::info!("✓ Table validation passed"),
|
||||
Err(e) => log::info!("✗ Table validation failed: {:?}", e),
|
||||
}
|
||||
|
||||
// Test invalid table access
|
||||
match table.get(2000) {
|
||||
Some(_) => println!("✗ Should not find entry beyond table size"),
|
||||
None => println!("✓ Properly handles out-of-bounds access"),
|
||||
Some(_) => log::info!("✗ Should not find entry beyond table size"),
|
||||
None => log::info!("✓ Properly handles out-of-bounds access"),
|
||||
}
|
||||
|
||||
println!("✓ Error handling example complete\n");
|
||||
log::info!("✓ Error handling example complete\n");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Comprehensive demonstration of all features
|
||||
pub fn comprehensive_demo() -> Result<(), EvaluatorError> {
|
||||
println!("=== Comprehensive Math Evaluator Demo ===\n");
|
||||
log::info!("=== Comprehensive Math Evaluator Demo ===\n");
|
||||
|
||||
// Run all examples
|
||||
basic_usage_example()?;
|
||||
|
|
@ -432,8 +432,8 @@ pub fn comprehensive_demo() -> Result<(), EvaluatorError> {
|
|||
memory_optimization_example()?;
|
||||
error_handling_example()?;
|
||||
|
||||
println!("🎉 All examples completed successfully!");
|
||||
println!("The math evaluator is ready for production use.");
|
||||
log::info!("🎉 All examples completed successfully!");
|
||||
log::info!("The math evaluator is ready for production use.");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@
|
|||
//!
|
||||
//! let packed_array: [PackedCard; 7] = math_cards.try_into().unwrap();
|
||||
//! let result = table.evaluate_7_card(&packed_array);
|
||||
//! println!("Hand evaluation: {:?}", result);
|
||||
//! log::info!("Hand evaluation: {:?}", result);
|
||||
//! ```
|
||||
//!
|
||||
//! ### Performance Comparison
|
||||
|
|
@ -58,8 +58,8 @@
|
|||
//! core_eval.evaluate_7_card(cards)
|
||||
//! });
|
||||
//!
|
||||
//! println!("Math evaluator: {:?}", math_time);
|
||||
//! println!("Core evaluator: {:?}", core_time);
|
||||
//! log::info!("Math evaluator: {:?}", math_time);
|
||||
//! log::info!("Core evaluator: {:?}", core_time);
|
||||
//! ```
|
||||
|
||||
use super::errors::EvaluatorError;
|
||||
|
|
@ -494,7 +494,7 @@ pub mod utils {
|
|||
}
|
||||
}
|
||||
|
||||
println!("All evaluator compatibility tests passed!");
|
||||
log::info!("All evaluator compatibility tests passed!");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
|||
4
holdem_core/src/evaluator/integration_utils.rs
Normal file
4
holdem_core/src/evaluator/integration_utils.rs
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
//! Integration utilities for the hand evaluator.
|
||||
//!
|
||||
//! This module provides helper functions and data structures for integration
|
||||
//! testing and cross-validation of hand evaluation results.
|
||||
|
|
@ -71,7 +71,7 @@ impl EvaluatorTestSuite {
|
|||
pub fn run_all_tests(&mut self) -> Result<TestStats, EvaluatorError> {
|
||||
let start_time = std::time::Instant::now();
|
||||
|
||||
println!("Running comprehensive math evaluator test suite...");
|
||||
log::info!("Running comprehensive math evaluator test suite...");
|
||||
|
||||
// Run correctness tests
|
||||
self.run_correctness_tests()?;
|
||||
|
|
@ -91,13 +91,13 @@ impl EvaluatorTestSuite {
|
|||
let elapsed = start_time.elapsed();
|
||||
self.stats.execution_time_ms = elapsed.as_millis() as u64;
|
||||
|
||||
println!("Test suite completed: {:?}", self.stats);
|
||||
log::info!("Test suite completed: {:?}", self.stats);
|
||||
Ok(self.stats.clone())
|
||||
}
|
||||
|
||||
/// Test that math evaluator produces correct results
|
||||
fn run_correctness_tests(&mut self) -> Result<(), EvaluatorError> {
|
||||
println!("Running correctness tests...");
|
||||
log::info!("Running correctness tests...");
|
||||
|
||||
let test_hands = generate_comprehensive_test_hands();
|
||||
let mut passed = 0;
|
||||
|
|
@ -130,7 +130,7 @@ impl EvaluatorTestSuite {
|
|||
passed += 1;
|
||||
} else {
|
||||
failed += 1;
|
||||
println!(
|
||||
log::info!(
|
||||
"5-card mismatch at test {}: math={:?}, core={:?}",
|
||||
i, math_result_5, core_result_5
|
||||
);
|
||||
|
|
@ -150,7 +150,7 @@ impl EvaluatorTestSuite {
|
|||
passed += 1;
|
||||
} else {
|
||||
failed += 1;
|
||||
println!(
|
||||
log::info!(
|
||||
"6-card mismatch at test {}: math={:?}, core={:?}",
|
||||
i, math_result_6, core_result_6
|
||||
);
|
||||
|
|
@ -167,7 +167,7 @@ impl EvaluatorTestSuite {
|
|||
passed += 1;
|
||||
} else {
|
||||
failed += 1;
|
||||
println!(
|
||||
log::info!(
|
||||
"7-card mismatch at test {}: math={:?}, core={:?}",
|
||||
i, math_result_7, core_result_7
|
||||
);
|
||||
|
|
@ -182,13 +182,13 @@ impl EvaluatorTestSuite {
|
|||
self.stats.passed_tests += passed;
|
||||
self.stats.failed_tests += failed;
|
||||
|
||||
println!("Correctness tests: {} passed, {} failed", passed, failed);
|
||||
log::info!("Correctness tests: {} passed, {} failed", passed, failed);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Test performance characteristics
|
||||
fn run_performance_tests(&mut self) -> Result<(), EvaluatorError> {
|
||||
println!("Running performance tests...");
|
||||
log::info!("Running performance tests...");
|
||||
|
||||
// Test 5-card performance
|
||||
let time_5 = benchmark_evaluation(|cards| {
|
||||
|
|
@ -209,33 +209,33 @@ impl EvaluatorTestSuite {
|
|||
let max_7_card_time = std::time::Duration::from_nanos(1000);
|
||||
|
||||
if time_7 > max_7_card_time {
|
||||
println!("Warning: 7-card evaluation too slow: {:?}", time_7);
|
||||
log::info!("Warning: 7-card evaluation too slow: {:?}", time_7);
|
||||
} else {
|
||||
println!("Performance tests passed");
|
||||
log::info!("Performance tests passed");
|
||||
}
|
||||
|
||||
println!("Performance results:");
|
||||
println!(" 5-card: {:?}", time_5);
|
||||
println!(" 6-card: {:?}", time_6);
|
||||
println!(" 7-card: {:?}", time_7);
|
||||
log::info!("Performance results:");
|
||||
log::info!(" 5-card: {:?}", time_5);
|
||||
log::info!(" 6-card: {:?}", time_6);
|
||||
log::info!(" 7-card: {:?}", time_7);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Test memory usage targets
|
||||
fn run_memory_tests(&mut self) -> Result<(), EvaluatorError> {
|
||||
println!("Running memory tests...");
|
||||
log::info!("Running memory tests...");
|
||||
|
||||
let memory_usage = self.math_evaluator.get_jump_table().memory_usage();
|
||||
let target_max_memory = 150_000_000; // 150MB target
|
||||
|
||||
if memory_usage > target_max_memory {
|
||||
println!(
|
||||
log::info!(
|
||||
"Warning: Memory usage exceeds target: {} bytes",
|
||||
memory_usage
|
||||
);
|
||||
} else {
|
||||
println!("Memory usage within target: {} bytes", memory_usage);
|
||||
log::info!("Memory usage within target: {} bytes", memory_usage);
|
||||
}
|
||||
|
||||
// Test that jump table is properly sized
|
||||
|
|
@ -245,13 +245,13 @@ impl EvaluatorTestSuite {
|
|||
assert!(table.size > 0);
|
||||
assert!(table.memory_usage() > 0);
|
||||
|
||||
println!("Memory tests passed");
|
||||
log::info!("Memory tests passed");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Test integration between systems
|
||||
fn run_integration_tests(&mut self) -> Result<(), EvaluatorError> {
|
||||
println!("Running integration tests...");
|
||||
log::info!("Running integration tests...");
|
||||
|
||||
// Test type conversions
|
||||
let cards = [
|
||||
|
|
@ -272,13 +272,13 @@ impl EvaluatorTestSuite {
|
|||
// Should handle empty input gracefully
|
||||
assert_eq!(results.len(), 0);
|
||||
|
||||
println!("Integration tests passed");
|
||||
log::info!("Integration tests passed");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Test for known bugs and regressions
|
||||
fn run_regression_tests(&mut self) -> Result<(), EvaluatorError> {
|
||||
println!("Running regression tests...");
|
||||
log::info!("Running regression tests...");
|
||||
|
||||
// Test edge cases that have caused issues in the past
|
||||
let edge_cases = vec![
|
||||
|
|
@ -325,10 +325,10 @@ impl EvaluatorTestSuite {
|
|||
assert!(result_7.rank as u8 <= HandRank::RoyalFlush as u8);
|
||||
}
|
||||
|
||||
println!("Regression test {} passed", i);
|
||||
log::info!("Regression test {} passed", i);
|
||||
}
|
||||
|
||||
println!("Regression tests passed");
|
||||
log::info!("Regression tests passed");
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
@ -441,7 +441,7 @@ fn generate_comprehensive_test_hands() -> Vec<[Card; 7]> {
|
|||
|
||||
/// Property-based tests for canonicalization
|
||||
pub fn test_canonicalization_properties() -> Result<(), EvaluatorError> {
|
||||
println!("Testing canonicalization properties...");
|
||||
log::info!("Testing canonicalization properties...");
|
||||
|
||||
// Test that canonicalization is deterministic
|
||||
let cards = vec![
|
||||
|
|
@ -468,13 +468,13 @@ pub fn test_canonicalization_properties() -> Result<(), EvaluatorError> {
|
|||
let original_suits = mapping1.to_original_suits(&mapping1.canonical_cards);
|
||||
assert_eq!(original_suits.len(), mapping1.canonical_cards.len());
|
||||
|
||||
println!("Canonicalization property tests passed");
|
||||
log::info!("Canonicalization property tests passed");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Property-based tests for jump table
|
||||
pub fn test_jump_table_properties() -> Result<(), EvaluatorError> {
|
||||
println!("Testing jump table properties...");
|
||||
log::info!("Testing jump table properties...");
|
||||
|
||||
let mut table = JumpTable::with_target_memory();
|
||||
|
||||
|
|
@ -509,13 +509,13 @@ pub fn test_jump_table_properties() -> Result<(), EvaluatorError> {
|
|||
assert!(entry.is_some());
|
||||
}
|
||||
|
||||
println!("Jump table property tests passed");
|
||||
log::info!("Jump table property tests passed");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Stress tests for performance under load
|
||||
pub fn run_stress_tests() -> Result<(), EvaluatorError> {
|
||||
println!("Running stress tests...");
|
||||
log::info!("Running stress tests...");
|
||||
|
||||
let mut evaluator = MathEvaluator::new()?;
|
||||
let num_hands = 1000;
|
||||
|
|
@ -586,7 +586,7 @@ pub fn run_stress_tests() -> Result<(), EvaluatorError> {
|
|||
|
||||
eval_pb.finish_with_message("Stress test completed");
|
||||
|
||||
println!(
|
||||
log::info!(
|
||||
"Stress test: {} hands in {:?}, average: {:?}",
|
||||
test_hands.len(),
|
||||
elapsed,
|
||||
|
|
@ -599,7 +599,7 @@ pub fn run_stress_tests() -> Result<(), EvaluatorError> {
|
|||
"Stress test too slow"
|
||||
);
|
||||
|
||||
println!("Stress tests passed");
|
||||
log::info!("Stress tests passed");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -468,11 +468,11 @@ impl JumpTable {
|
|||
|
||||
let total_size = level5_size + level6_size + level7_size;
|
||||
|
||||
println!("Creating jump table with optimal memory layout:");
|
||||
println!(" Level 5 (5-card): {} entries", level5_size);
|
||||
println!(" Level 6 (6-card): {} entries", level6_size);
|
||||
println!(" Level 7 (7-card): {} entries", level7_size);
|
||||
println!(
|
||||
log::info!("Creating jump table with optimal memory layout:");
|
||||
log::info!(" Level 5 (5-card): {} entries", level5_size);
|
||||
log::info!(" Level 6 (6-card): {} entries", level6_size);
|
||||
log::info!(" Level 7 (7-card): {} entries", level7_size);
|
||||
log::info!(
|
||||
" Total: {} entries (~{} MB)",
|
||||
total_size,
|
||||
total_size * 16 / 1024 / 1024
|
||||
|
|
@ -574,7 +574,7 @@ impl JumpTable {
|
|||
EvaluatorError::table_init_failed(&format!("Failed to write to file: {}", e))
|
||||
})?;
|
||||
|
||||
println!("Jump table saved to: {}", path.display());
|
||||
log::info!("Jump table saved to: {}", path.display());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -621,7 +621,7 @@ impl JumpTable {
|
|||
// Validate the loaded table
|
||||
table.validate()?;
|
||||
|
||||
println!("Jump table loaded from: {}", path.display());
|
||||
log::info!("Jump table loaded from: {}", path.display());
|
||||
Ok(table)
|
||||
}
|
||||
|
||||
|
|
@ -655,7 +655,7 @@ impl JumpTable {
|
|||
// Generate all C(52,7) combinations - this is a large number (133M+)
|
||||
// For practical purposes, we'll generate a representative subset
|
||||
// In production, this would be done in batches or with streaming
|
||||
println!("Generating canonical 7-card combinations...");
|
||||
log::info!("Generating canonical 7-card combinations...");
|
||||
|
||||
// For now, generate a smaller subset for testing and development
|
||||
let max_combinations = if cfg!(test) { 1000 } else { 100_000 };
|
||||
|
|
@ -680,7 +680,7 @@ impl JumpTable {
|
|||
combinations.push(combo);
|
||||
|
||||
if combinations.len() >= max_combinations {
|
||||
println!(
|
||||
log::info!(
|
||||
"Generated {} combinations for testing",
|
||||
combinations.len()
|
||||
);
|
||||
|
|
@ -694,31 +694,31 @@ impl JumpTable {
|
|||
}
|
||||
}
|
||||
|
||||
println!("Generated {} canonical combinations", combinations.len());
|
||||
log::info!("Generated {} canonical combinations", combinations.len());
|
||||
Ok(combinations)
|
||||
}
|
||||
|
||||
/// Build the jump table using bottom-up trie construction
|
||||
pub fn build(&mut self) -> Result<(), EvaluatorError> {
|
||||
println!("Building jump table with {} entries...", self.size);
|
||||
log::info!("Building jump table with {} entries...", self.size);
|
||||
|
||||
// Step 1: Generate canonical mappings for all 7-card combinations
|
||||
let combinations = self.generate_canonical_combinations()?;
|
||||
|
||||
// Step 2: Build Level 5 (terminal nodes) - 5-card hand evaluations
|
||||
println!("Building Level 5 terminal nodes...");
|
||||
log::info!("Building Level 5 terminal nodes...");
|
||||
self.build_level_5()?;
|
||||
|
||||
// Step 3: Build Level 6 (intermediate nodes) - 6-card combinations
|
||||
println!("Building Level 6 intermediate nodes...");
|
||||
log::info!("Building Level 6 intermediate nodes...");
|
||||
self.build_level_6(&combinations)?;
|
||||
|
||||
// Step 4: Build Level 7 (root nodes) - 7-card combinations
|
||||
println!("Building Level 7 root nodes...");
|
||||
log::info!("Building Level 7 root nodes...");
|
||||
self.build_level_7(&combinations)?;
|
||||
|
||||
// Step 5: Flatten the trie into contiguous array
|
||||
println!("Flattening trie structure...");
|
||||
log::info!("Flattening trie structure...");
|
||||
// Temporary placeholder for flatten_trie method
|
||||
// self.flatten_trie()?;
|
||||
|
||||
|
|
@ -726,13 +726,13 @@ impl JumpTable {
|
|||
self.metadata.total_combinations = combinations.len();
|
||||
self.metadata.memory_usage = self.memory_usage();
|
||||
|
||||
println!("Jump table construction complete!");
|
||||
log::info!("Jump table construction complete!");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Build Level 5 terminal nodes (5-card hand evaluations) using proper combinatorial indexing
|
||||
fn build_level_5(&mut self) -> Result<(), EvaluatorError> {
|
||||
println!(
|
||||
log::info!(
|
||||
"Building Level 5: Terminal nodes for 5-card hands using combinatorial indexing..."
|
||||
);
|
||||
|
||||
|
|
@ -743,7 +743,7 @@ impl JumpTable {
|
|||
// This is more efficient than generating from 7-card combinations
|
||||
let unique_5_card_hands = self.generate_all_unique_5_card_hands();
|
||||
|
||||
println!(
|
||||
log::info!(
|
||||
"Generated {} unique 5-card combinations using combinatorial indexing",
|
||||
unique_5_card_hands.len()
|
||||
);
|
||||
|
|
@ -763,7 +763,7 @@ impl JumpTable {
|
|||
let card_array: [Card; 5] = cards.try_into().unwrap();
|
||||
|
||||
// Evaluate the hand using the algorithmic evaluator for accuracy
|
||||
let evaluator = AlgorithmicEvaluator::new();
|
||||
let evaluator = AlgorithmicEvaluator::new()?;
|
||||
let hand_value = evaluator.evaluate_5_card_direct(&card_array);
|
||||
|
||||
// Use proper combinatorial indexing instead of simple hashing
|
||||
|
|
@ -776,12 +776,12 @@ impl JumpTable {
|
|||
}
|
||||
|
||||
if hand_index % 10000 == 0 && hand_index > 0 {
|
||||
println!("Processed {} Level 5 entries", hand_index);
|
||||
log::info!("Processed {} Level 5 entries", hand_index);
|
||||
}
|
||||
}
|
||||
|
||||
let elapsed = start_time.elapsed();
|
||||
println!(
|
||||
log::info!(
|
||||
"Level 5 construction complete: {} nodes in {:?}",
|
||||
level5_count, elapsed
|
||||
);
|
||||
|
|
@ -890,7 +890,7 @@ impl JumpTable {
|
|||
|
||||
/// Build Level 6 intermediate nodes (6-card combinations)
|
||||
fn build_level_6(&mut self, combinations: &[Vec<PackedCard>]) -> Result<(), EvaluatorError> {
|
||||
println!("Building Level 6: Intermediate nodes for 6-card hands...");
|
||||
log::info!("Building Level 6: Intermediate nodes for 6-card hands...");
|
||||
|
||||
let mut level6_count = 0;
|
||||
let start_time = std::time::Instant::now();
|
||||
|
|
@ -907,7 +907,7 @@ impl JumpTable {
|
|||
}
|
||||
|
||||
// Find the best 5-card hand from this 6-card hand using algorithmic evaluator
|
||||
let mut evaluator = AlgorithmicEvaluator::new();
|
||||
let evaluator = AlgorithmicEvaluator::new()?;
|
||||
// Convert 6 PackedCards to 6-element Card array
|
||||
let mut cards = Vec::new();
|
||||
for &packed in &six_cards {
|
||||
|
|
@ -927,12 +927,12 @@ impl JumpTable {
|
|||
}
|
||||
|
||||
if combo_index % 1000 == 0 && combo_index > 0 {
|
||||
println!("Processed {} 7-card combinations for Level 6", combo_index);
|
||||
log::info!("Processed {} 7-card combinations for Level 6", combo_index);
|
||||
}
|
||||
}
|
||||
|
||||
let elapsed = start_time.elapsed();
|
||||
println!(
|
||||
log::info!(
|
||||
"Level 6 construction complete: {} nodes in {:?}",
|
||||
level6_count, elapsed
|
||||
);
|
||||
|
|
@ -945,7 +945,7 @@ impl JumpTable {
|
|||
|
||||
/// Build Level 7 root nodes (7-card combinations)
|
||||
fn build_level_7(&mut self, combinations: &[Vec<PackedCard>]) -> Result<(), EvaluatorError> {
|
||||
println!("Building Level 7: Root nodes for 7-card hands...");
|
||||
log::info!("Building Level 7: Root nodes for 7-card hands...");
|
||||
|
||||
let mut level7_count = 0;
|
||||
let start_time = std::time::Instant::now();
|
||||
|
|
@ -954,7 +954,7 @@ impl JumpTable {
|
|||
for (combo_index, combo) in combinations.iter().enumerate() {
|
||||
if combo.len() >= 6 {
|
||||
// Find the best 5-card hand from this 7-card hand using algorithmic evaluator
|
||||
let mut evaluator = AlgorithmicEvaluator::new();
|
||||
let evaluator = AlgorithmicEvaluator::new()?;
|
||||
// Convert 7 PackedCards to 7-element Card array
|
||||
let mut cards = Vec::new();
|
||||
for &packed in combo {
|
||||
|
|
@ -973,12 +973,12 @@ impl JumpTable {
|
|||
}
|
||||
|
||||
if combo_index % 1000 == 0 && combo_index > 0 {
|
||||
println!("Processed {} 7-card combinations for Level 7", combo_index);
|
||||
log::info!("Processed {} 7-card combinations for Level 7", combo_index);
|
||||
}
|
||||
}
|
||||
|
||||
let elapsed = start_time.elapsed();
|
||||
println!(
|
||||
log::info!(
|
||||
"Level 7 construction complete: {} nodes in {:?}",
|
||||
level7_count, elapsed
|
||||
);
|
||||
|
|
@ -1294,7 +1294,7 @@ impl JumpTable {
|
|||
// TEMPORARY FIX: Use algorithmic evaluator instead of jump table
|
||||
// This bypasses hash function issues and ensures correct results
|
||||
use super::algorithmic_evaluator::AlgorithmicEvaluator;
|
||||
let evaluator = AlgorithmicEvaluator::new();
|
||||
let evaluator = AlgorithmicEvaluator::new()?;
|
||||
Ok(evaluator.evaluate_5_card_direct(&card_array))
|
||||
}
|
||||
|
||||
|
|
@ -1351,7 +1351,7 @@ impl JumpTable {
|
|||
|
||||
// TEMPORARY FIX: Use algorithmic evaluator directly to bypass hash function issues
|
||||
use super::algorithmic_evaluator::AlgorithmicEvaluator;
|
||||
let mut evaluator = AlgorithmicEvaluator::new();
|
||||
let evaluator = AlgorithmicEvaluator::new()?;
|
||||
|
||||
// Convert PackedCards to Cards for algorithmic evaluator
|
||||
let card_array: Vec<Card> = cards
|
||||
|
|
@ -1493,11 +1493,11 @@ pub fn calculate_optimal_table_size() -> JumpTable {
|
|||
|
||||
let total_size = level5_size + level6_size + level7_size;
|
||||
|
||||
println!("Creating jump table with optimal memory layout:");
|
||||
println!(" Level 5 (5-card): {} entries", level5_size);
|
||||
println!(" Level 6 (6-card): {} entries", level6_size);
|
||||
println!(" Level 7 (7-card): {} entries", level7_size);
|
||||
println!(
|
||||
log::info!("Creating jump table with optimal memory layout:");
|
||||
log::info!(" Level 5 (5-card): {} entries", level5_size);
|
||||
log::info!(" Level 6 (6-card): {} entries", level6_size);
|
||||
log::info!(" Level 7 (7-card): {} entries", level7_size);
|
||||
log::info!(
|
||||
" Total: {} entries (~{} MB)",
|
||||
total_size,
|
||||
total_size * 16 / 1024 / 1024
|
||||
|
|
|
|||
4
holdem_core/src/evaluator/tables_new.rs
Normal file
4
holdem_core/src/evaluator/tables_new.rs
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
//! New table implementations for the hand evaluator.
|
||||
//!
|
||||
//! This module is a placeholder for future jump table implementations
|
||||
//! and optimized lookup structures.
|
||||
4
holdem_core/src/evaluator/test_utils.rs
Normal file
4
holdem_core/src/evaluator/test_utils.rs
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
//! Test utilities for the hand evaluator.
|
||||
//!
|
||||
//! This module provides helper functions and data structures for testing
|
||||
//! hand evaluation correctness.
|
||||
Loading…
Add table
Add a link
Reference in a new issue