The most advanced open-source poker library available. Hand evaluation at 50M+ hands/sec per core, a CFR solver for game-theory optimal strategy approximation, Omaha support (PLO4-PLO7), multi-agent arena simulation, Monte Carlo equity calculation, and ICM tournament simulation — all in Rust.
Available as both a library (rs_poker) and a CLI binary (rsp).
Install the binary:
cargo install rs_poker --features rspRank a hand:
rsp holdem rank AcKdQhJsTsMonte Carlo equity simulation (3M hands by default):
rsp holdem simulate AdKh 8c8sCalculate outs with board cards:
rsp holdem outs AcAd KsKh --board QhJhTh --detailedRank an Omaha hand:
rsp omaha rank AhAsKhKs QhJhThPit agents against each other:
rsp arena compare ./examples/configs -n 5000 -p 3 --parallel 8Generate hand histories in Open Hand History format:
rsp arena generate ./examples/configs -o hands.ohh -n 1000Convert chipEV to $EV in tournaments:
rsp icm simulate --chip-stacks 1500 1250 600 500 850 800 --payments 50 30 20 --iterations 50000Add to your project:
cargo add rs_pokeruse rs_poker::core::{FlatHand, Rankable};
let hand = FlatHand::new_from_str("AcKdQhJsTs").unwrap();
let rank = hand.rank();
println!("{}", rank); // StraightFlushuse rs_poker::core::{Card, Hand, Suit, Value};
use rs_poker::holdem::MonteCarloGame;
let hero = Hand::new_with_cards(vec![
Card::new(Value::Ace, Suit::Spade),
Card::new(Value::Ace, Suit::Heart),
]);
let villain = Hand::new_with_cards(vec![
Card::new(Value::King, Suit::Spade),
Card::new(Value::King, Suit::Heart),
]);
let mut sim = MonteCarloGame::new(vec![hero, villain]).unwrap();
let equity = sim.estimate_equity(100_000);
// equity[0] ≈ 0.82 (AA vs KK)use rs_poker::core::Rankable;
use rs_poker::omaha::OmahaHand;
let hand = OmahaHand::new_from_str("AhAsKhKs", "QhJhTh").unwrap();
let rank = hand.rank();
println!("{}", rank); // StraightFlush — uses exactly 2 hole + 3 boardFoundational types for all poker variants:
- Card, Suit, Value — standard 52-card representations
- Hand — bitset-backed hand with O(1) card operations via
CardBitSet(u64) - FlatHand — vector-backed hand optimized for ranking
- Deck — shuffleable deck with dead card support
- Rank — full hand ranking: HighCard through StraightFlush with accurate kicker comparison
- Rankable trait — unified ranking API implemented by all hand types
- PlayerBitSet (u16) — O(1) player tracking for up to 16 players
Hand evaluation runs at 50M+ hands/sec per core (~20ns per 5-card hand, <25ns per 7-card hand). This is achieved through:
- CardBitSet (u64) for O(1) card membership, intersection, and union
- Gosper's hack for zero-allocation combinatorial iteration
- PDEP hardware acceleration on x86_64 for bit manipulation
- Accurate kicker comparison — no single-kicker shortcuts that break tie resolution
Full support for Omaha variants: PLO4, PLO5, PLO6, and PLO7.
- Enforces the "exactly 2 hole cards + exactly 3 board cards" rule
- Uses the same
Rankabletrait as Hold'em — one API for all variants - Evaluates all valid hole+board combinations to find the best hand
use rs_poker::core::Rankable;
use rs_poker::omaha::OmahaHand;
// PLO5 with 5 hole cards
let hand = OmahaHand::new_from_str("AhAsKhKs9d", "QhJhTh").unwrap();
let rank = hand.rank();Texas Hold'em-specific tools:
- Starting hands — all 169 unique hands (1,326 total combos)
- Range parsing —
"AKs","TT+","JTs-67s","KQo+" - Monte Carlo simulation — multi-player equity estimation via
MonteCarloGame - Outs calculation — exhaustive enumeration of remaining cards
use rs_poker::holdem::StartingHand;
// Parse a range of hands
let hands = StartingHand::new_from_range("TT+").unwrap();
// Returns: TT, JJ, QQ, KK, AAMulti-agent simulation framework for autonomous poker play. Supports 2-16 players with configurable blinds, antes, and stack sizes.
Implement act() to create a custom strategy:
use rs_poker::arena::{Agent, AgentAction, GameState};
struct MyAgent;
impl Agent for MyAgent {
fn act(&mut self, _id: u128, game_state: &GameState) -> AgentAction {
AgentAction::Call(game_state.current_bet())
}
fn name(&self) -> &str { "my-agent" }
}| Agent | Strategy |
|---|---|
CallingAgent |
Always calls |
FoldingAgent |
Always folds (checks when possible) |
AllInAgent |
Always goes all-in |
RandomAgent |
Configurable fold/call probabilities per street |
RandomPotControlAgent |
Random with pot-size-aware bet limiting |
ConfigAgentBuilder |
JSON-configurable preflop ranges + postflop strategy |
VecReplayAgent |
Replays a recorded action sequence |
CFRAgent |
Counterfactual Regret Minimization solver |
Event recorders that observe every action during simulation:
| Historian | Purpose |
|---|---|
VecHistorian |
Collects all actions in memory |
StatsTrackingHistorian |
Aggregates VPIP, PFR, 3-bet, win rate, positional profit |
DirectoryHistorian |
Writes hand histories to disk |
OpenHandHistoryHistorian |
Exports in OHH format |
FnHistorian |
Closure-based custom recording |
NullHistorian |
No-op (discards all records) |
HoldemCompetition— run multiple cash game hands and track per-player P&L, win/loss counts, and per-street statisticsSingleTableTournament— elimination-style tournament with finishing positions and stack tracking
The CFR (Counterfactual Regret Minimization) agent learns game-theory optimal strategies by exploring the game tree and minimizing regret over iterations.
- PCFR+ regret matching with quadratic weighting
- Lock-free concurrent tree — shared across agents via
Arc - Arena allocator — nodes stored in
Vecby index for cache-friendly traversal - Parallel exploration via rayon at configurable depth
- Depth-based iteration scheduling — more iterations at deeper nodes where the tree is smaller
- Configurable action generators — per-street bet sizing (raise multipliers, pot fractions, all-in)
- Graphviz export for decision tree visualization
Run CFR agents via the CLI:
rsp arena compare ./examples/configs -n 5000 -p 3 --parallel 8Or configure them via JSON:
{
"type": "cfr_configurable",
"name": "CFR-Agent",
"depth_hands": [24, 3, 1],
"action_config": {
"preflop": {
"call_enabled": true,
"raise_mult": [4.0],
"pot_mult": [],
"setup_shove": false,
"all_in": true
},
"flop": {
"call_enabled": true,
"raise_mult": [],
"pot_mult": [0.5, 1.0],
"setup_shove": false,
"all_in": true
}
}
}Monte Carlo-based ICM (Independent Chip Model) tournament equity calculation.
use rs_poker::simulated_icm::simulate_icm_tournament;
let chip_stacks = vec![10000, 5000, 3000, 2000];
let payments = vec![100, 50, 25, 10];
let winnings = simulate_icm_tournament(&chip_stacks, &payments);
// winnings[i] = expected payout for player i based on chip stackAvoids the O(N!) complexity of traditional ICM by simulating all-in confrontations. Parallelizable across independent tournaments.
| Flag | Default | Description |
|---|---|---|
arena |
Yes | Multi-agent simulation framework, CFR solver |
serde |
Yes | JSON serialization for hands, game states, configs |
omaha |
Yes | Omaha (PLO4/PLO5/PLO6/PLO7) hand evaluation |
open-hand-history |
Yes | Open Hand History format import/export |
rsp |
No | CLI binary with all features enabled |
arena-test-util |
No | Approximate comparison helpers for tests |
open-hand-history-test-util |
No | OHH format testing helpers |
- Fuzzing — hand ranking, game simulation replay, CFR agent, and Omaha evaluation all have fuzz targets
- Mutation testing —
cargo-mutantsvalidates test coverage catches real bugs - Benchmarks — comprehensive suite covering hand ranking, Monte Carlo simulation, arena games, CFR, ICM, and Omaha
Apache-2.0
