rusty_marvin/docs/api.md
Jan-Peter von Hunnius 5c271b279f Added Documentation
Added Test Cases
Added Comments
2025-10-02 18:33:31 +02:00

389 lines
No EOL
8.9 KiB
Markdown

# API Documentation
## Core Types
### `LookupHandEvaluator`
The main hand evaluation engine that uses precomputed lookup tables for O(1) hand evaluation.
#### Constructor
```rust
pub fn new() -> io::Result<Self>
```
Creates a new evaluator instance. On first use, generates evaluation tables if they don't exist.
**Returns:**
- `Ok(LookupHandEvaluator)` - Successfully initialized evaluator
- `Err(io::Error)` - Failed to load or generate tables
#### Methods
##### `rank_hand(&self, hand: &Hand) -> u32`
Evaluates any poker hand (5, 6, or 7 cards) and returns its rank value.
```rust
let rank = evaluator.rank_hand(&hand);
```
**Parameters:**
- `hand: &Hand` - Poker hand containing 5-7 cards
**Returns:**
- `u32` - Hand rank (higher values = stronger hands)
##### `rank_hand5(&self, hand: &Hand) -> u32`
Optimized evaluation for exactly 5-card hands.
```rust
let rank = evaluator.rank_hand5(&hand);
```
**Parameters:**
- `hand: &Hand` - Poker hand containing exactly 5 cards
**Returns:**
- `u32` - Hand rank value
##### `rank_hand6(&self, cards: &[u32]) -> u32`
Evaluates a 6-card hand by finding the best 5-card combination.
```rust
let rank = evaluator.rank_hand6(&card_indices);
```
**Parameters:**
- `cards: &[u32]` - Array of 6 card indices
**Returns:**
- `u32` - Best possible 5-card hand rank
##### `rank_hand7(&self, cards: &[u32]) -> u32`
Evaluates a 7-card hand by finding the best 5-card combination.
```rust
let rank = evaluator.rank_hand7(&card_indices);
```
**Parameters:**
- `cards: &[u32]` - Array of 7 card indices
**Returns:**
- `u32` - Best possible 5-card hand rank
### `HandEval` Trait
Standardized interface for poker hand evaluators.
#### Constants
```rust
const HAND_CATEGORY_SHIFT: u32 = 24;
const HAND_CATEGORY_MASK: u32 = 0xF << Self::HAND_CATEGORY_SHIFT;
const VALUE_MASK: u32 = 0x000FFFFF;
```
#### Methods
##### `rank_hand(&self, hand: &Hand) -> u32`
Evaluates a poker hand of any supported size.
##### `rank_hand7(&self, cards: &[Card; 7]) -> u32`
Evaluates exactly 7 cards.
##### `hand_description(&self, hand_value: u32) -> String`
Returns human-readable description of a hand rank.
##### `hand_description_hand(&self, hand: &Hand) -> String`
Describes a hand by evaluating it first.
##### `hand_description7(&self, cards: &[Card; 7]) -> String`
Describes the best 5-card hand from 7 cards.
## Supporting Types
### `Hand`
Collection of cards that can be evaluated.
#### Key Methods
```rust
// Construction
let mut hand = Hand::new();
hand.add_card(card).unwrap();
// Information
let size = hand.size();
let is_valid = hand.size() >= 5;
// String representation
println!("{}", hand.to_string()); // "As Ks Qs Js Ts"
```
### `Card`
Individual playing card representation.
#### Construction
```rust
// From string notation
let card = Card::from_string("As").unwrap();
let card = Card::from_string("Kh").unwrap();
// String representation
assert_eq!(card.to_string(), "As");
```
#### Properties
```rust
let rank = card.rank(); // Card rank (0-12)
let suit = card.suit(); // Card suit (0-3)
let index = card.index(); // Unique card index (0-51)
```
## Hand Ranking Values
### Category Extraction
```rust
// Extract hand category (bits 24-27)
let category = (hand_value & HandEval::HAND_CATEGORY_MASK) >> HandEval::HAND_CATEGORY_SHIFT;
// Extract relative value (bits 0-23)
let value = hand_value & HandEval::VALUE_MASK;
```
### Hand Categories
| Category | Value | Description |
|----------|-------|-------------|
| Straight Flush | 9 | Five cards in sequence, same suit |
| Four of a Kind | 8 | Four cards of same rank |
| Full House | 7 | Three of a kind + pair |
| Flush | 6 | Five cards, same suit |
| Straight | 5 | Five cards in sequence |
| Three of a Kind | 4 | Three cards of same rank |
| Two Pair | 3 | Two different pairs |
| One Pair | 2 | Two cards of same rank |
| High Card | 1 | No matching cards |
### Rank Value Ranges
| Hand Type | Rank Range | Count |
|-----------|------------|-------|
| Straight Flush | 368,793,253 - 371,292,191 | 40 |
| Four of a Kind | 184,396,629 - 368,793,252 | 624 |
| Full House | 92,198,315 - 184,396,628 | 3,744 |
| Flush | 46,099,158 - 92,198,314 | 5,108 |
| Straight | 23,049,579 - 46,099,157 | 10,200 |
| Three of a Kind | 11,524,790 - 23,049,578 | 54,912 |
| Two Pair | 5,762,395 - 11,524,789 | 123,552 |
| One Pair | 2,881,198 - 5,762,394 | 1,098,240 |
| High Card | 1 - 2,881,197 | 1,302,540 |
## Performance Characteristics
### Time Complexity
| Operation | Time Complexity | Notes |
|-----------|----------------|-------|
| 5-Card evaluation | O(1) | Direct table lookup |
| 6-Card evaluation | O(1) | 6 table lookups |
| 7-Card evaluation | O(1) | 21 table lookups |
| Table generation | O(N) | N = 32M combinations |
### Memory Usage
| Component | Size | Description |
|-----------|------|-------------|
| Hand ranks table | ~128 MB | Complete evaluation table |
| Working tables | ~2.4 MB | Generation workspace |
| Code size | ~50 KB | Compiled binary |
### Cache Performance
The lookup table design provides excellent cache performance:
- **Sequential Access**: Table generation processes data sequentially
- **Compact Encoding**: Cards encoded in 8 bits each
- **Prefetch Friendly**: Linear table layout enables hardware prefetching
- **Low Branch Misprediction**: Perfect hash eliminates conditional logic
## Error Handling
### Common Error Cases
```rust
// Invalid hand size
let rank = evaluator.rank_hand(&hand); // Returns 0 for < 5 cards
// Card parsing errors
let card = Card::from_string("XX"); // Returns Err
// Table loading errors
let evaluator = LookupHandEvaluator::new(); // May fail if disk full
```
### Error Types
- `io::Error` - File system errors during table loading/generation
- `CardParseError` - Invalid card string format
- `HandFullError` - Attempting to add cards to full hand
## Thread Safety
The `LookupHandEvaluator` is designed for read-only usage after construction:
```rust
// Safe: Read-only evaluator
let evaluator = LookupHandEvaluator::new().unwrap();
// Multiple threads can use the same evaluator
let rank1 = evaluator.rank_hand(&hand1);
let rank2 = evaluator.rank_hand(&hand2);
// NOT safe: Modifying evaluator during use
// (evaluator is not Sync + Send for mutation)
```
## Integration Examples
### Texas Hold'em Engine
```rust
use poker_api::hand_evaluator::LookupHandEvaluator;
use poker_api::api::{hand::Hand, card::Card};
struct HoldemEngine {
evaluator: LookupHandEvaluator,
}
impl HoldemEngine {
fn evaluate_board(&self, hole_cards: &[Card; 2], board: &[Card; 5]) -> u32 {
let mut all_cards = Vec::new();
all_cards.extend_from_slice(hole_cards);
all_cards.extend_from_slice(board);
let mut hand = Hand::new();
for card in all_cards {
hand.add_card(card).unwrap();
}
self.evaluator.rank_hand(&hand)
}
}
```
### Hand Range Analysis
```rust
use poker_api::hand_evaluator::LookupHandEvaluator;
struct RangeAnalyzer {
evaluator: LookupHandEvaluator,
}
impl RangeAnalyzer {
fn compare_hands(&self, hand1: &Hand, hand2: &Hand) -> std::cmp::Ordering {
let rank1 = self.evaluator.rank_hand(hand1);
let rank2 = self.evaluator.rank_hand(hand2);
rank1.cmp(&rank2)
}
}
```
## Testing Integration
### Unit Tests
```rust
#[cfg(test)]
mod tests {
use super::*;
use poker_api::hand_evaluator::LookupHandEvaluator;
#[test]
fn test_royal_flush() {
let evaluator = LookupHandEvaluator::new().unwrap();
let mut hand = Hand::new();
// Add A,K,Q,J,10 of same suit
let rank = evaluator.rank_hand(&hand);
assert!(rank > 368_793_253); // Royal flush range
}
}
```
### Benchmark Tests
```rust
#[cfg(test)]
mod benchmarks {
use super::*;
use std::time::Instant;
#[test]
fn benchmark_evaluation() {
let evaluator = LookupHandEvaluator::new().unwrap();
let hand = create_test_hand();
let start = Instant::now();
for _ in 0..1_000_000 {
let _rank = evaluator.rank_hand(&hand);
}
let duration = start.elapsed();
println!("1M evaluations in {:?}", duration);
}
}
```
## Advanced Configuration
### Custom Table Paths
The evaluator uses default paths, but this can be customized by modifying the source:
```rust
// In hand_evaluator.rs
const FILE_NAME: &'static str = "custom/path/HandRanks.dat";
```
### Memory Management
For systems with limited memory, consider:
```rust
// Use Box<[u32]> for heap allocation control
let hand_ranks: Box<[u32]> = vec![0; SIZE].into_boxed_slice();
// Monitor memory usage
println!("Table memory usage: {} MB",
std::mem::size_of_val(&*hand_ranks) / 1_048_576);
```
### Performance Tuning
For maximum performance:
```rust
// Use release mode
cargo build --release
// Consider SIMD optimizations for batch evaluation
// (requires custom implementation)
```
This API documentation covers the complete public interface for poker hand evaluation. For implementation details, see the source code comments and the developer guide.