feat: hand history logging, tournament series, MTT consolidation, Meerkat API
Major changes: - Add hand history module (iPoker format) with HandHistoryLogger - Add run_sng_series() for multi-tournament aggregate statistics - Fix MTT table consolidation deadlock (sub-minimum-player tables) - Add Meerkat-compatible convenience methods on Action and GameInfo - Add custom blind levels, prize structures, auto-rebuy to GameConfig - Add SngSeriesResult/SngPlayerSeriesResult for series tracking - Add Tournament::winner(), tables_mut(), shuffle_seats() Review fixes: - Fix TOML prizes field ordering (must precede [[game.blind_levels]]) - Add sensible serde defaults for small_blind (10) and big_blind (20) - Fix prize assignment in run_sng_series (use raw_placement directly) - Handle hand history filename collisions with suffixed retry - Add debug_assert guard on collect_hand_history_data double-consumption
This commit is contained in:
parent
9dfd9c3ee3
commit
c041cde3fe
18 changed files with 4601 additions and 208 deletions
|
|
@ -4,7 +4,7 @@ num_seats = 10
|
|||
small_blind = 10
|
||||
big_blind = 20
|
||||
ante = 0
|
||||
starting_chips = 5000
|
||||
starting_chips = 1500
|
||||
num_hands = 10000
|
||||
|
||||
# Rake configuration (optional, defaults to no rake).
|
||||
|
|
@ -15,8 +15,12 @@ num_hands = 10000
|
|||
# reset_bankroll_each_hand = false
|
||||
# bankroll_refill_threshold = 1000 # Refill when stack <= 1000
|
||||
|
||||
# Auto-rebuy: when enabled, players whose stack drops below half the
|
||||
# starting_chips are automatically topped back up to starting_chips.
|
||||
auto_rebuy = true
|
||||
|
||||
# Randomize seat assignments before each hand (optional, defaults to false).
|
||||
# randomize_seats = true
|
||||
randomize_seats = true
|
||||
|
||||
[game.bet_limit]
|
||||
type = "no_limit"
|
||||
|
|
|
|||
527
holdem_core/examples/configs/mtt_10_tables.toml
Normal file
527
holdem_core/examples/configs/mtt_10_tables.toml
Normal file
|
|
@ -0,0 +1,527 @@
|
|||
# MTT Tournament Series — 10 tables, 100 players, 100 tournaments
|
||||
#
|
||||
# Each of the 6 bot types appears multiple times to fill 100 seats.
|
||||
# Tables have 10 seats each; players are distributed round-robin
|
||||
# across tables by the tournament's register_player() logic.
|
||||
# As players bust out, tables will eventually consolidate
|
||||
# (last player standing wins).
|
||||
#
|
||||
# 100 tournaments are run with aggregate statistics tracked by player name.
|
||||
# Entry fee: 5 per tournament. Final table prizes: 200, 100, 50, 30, 20, 10, 10, 10, 10, 10.
|
||||
|
||||
[game]
|
||||
game_type = "MultiTableTournament"
|
||||
num_seats = 10
|
||||
num_tables = 10
|
||||
small_blind = 10
|
||||
big_blind = 20
|
||||
starting_chips = 1500
|
||||
buy_in = 5
|
||||
hands_per_level = 10
|
||||
num_blind_levels = 20
|
||||
randomize_seats = true
|
||||
num_tournaments = 100
|
||||
|
||||
[game.bet_limit]
|
||||
type = "no_limit"
|
||||
min_raise = 20
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Prize structure (100 players × $5 buy-in = $500 prize pool, top 10 paid)
|
||||
# ---------------------------------------------------------------------------
|
||||
prizes = [200, 100, 50, 30, 20, 10, 10, 10, 10, 10]
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Blind levels (extended to 12 levels)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
[[game.blind_levels]]
|
||||
small_blind = 10
|
||||
big_blind = 20
|
||||
ante = 0
|
||||
hands = 10
|
||||
|
||||
[[game.blind_levels]]
|
||||
small_blind = 15
|
||||
big_blind = 30
|
||||
ante = 0
|
||||
hands = 10
|
||||
|
||||
[[game.blind_levels]]
|
||||
small_blind = 25
|
||||
big_blind = 50
|
||||
ante = 5
|
||||
hands = 10
|
||||
|
||||
[[game.blind_levels]]
|
||||
small_blind = 50
|
||||
big_blind = 100
|
||||
ante = 10
|
||||
hands = 10
|
||||
|
||||
[[game.blind_levels]]
|
||||
small_blind = 75
|
||||
big_blind = 150
|
||||
ante = 15
|
||||
hands = 10
|
||||
|
||||
[[game.blind_levels]]
|
||||
small_blind = 100
|
||||
big_blind = 200
|
||||
ante = 20
|
||||
hands = 10
|
||||
|
||||
[[game.blind_levels]]
|
||||
small_blind = 150
|
||||
big_blind = 300
|
||||
ante = 25
|
||||
hands = 10
|
||||
|
||||
[[game.blind_levels]]
|
||||
small_blind = 200
|
||||
big_blind = 400
|
||||
ante = 50
|
||||
hands = 10
|
||||
|
||||
[[game.blind_levels]]
|
||||
small_blind = 300
|
||||
big_blind = 600
|
||||
ante = 75
|
||||
hands = 10
|
||||
|
||||
[[game.blind_levels]]
|
||||
small_blind = 400
|
||||
big_blind = 800
|
||||
ante = 100
|
||||
hands = 10
|
||||
|
||||
[[game.blind_levels]]
|
||||
small_blind = 600
|
||||
big_blind = 1200
|
||||
ante = 150
|
||||
hands = 10
|
||||
|
||||
[[game.blind_levels]]
|
||||
small_blind = 800
|
||||
big_blind = 1600
|
||||
ante = 200
|
||||
hands = 10
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Bots — 100 total (10 tables × 10 seats)
|
||||
# 17 FlockBot, 17 ChumpBot, 17 CallBot, 17 RaiseBot, 16 RandomBot, 16 FoldBot
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# FlockBot copies (17)
|
||||
[[game.bots]]
|
||||
bot_type = "flock_bot"
|
||||
name = "FlockBot-1"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "flock_bot"
|
||||
name = "FlockBot-2"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "flock_bot"
|
||||
name = "FlockBot-3"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "flock_bot"
|
||||
name = "FlockBot-4"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "flock_bot"
|
||||
name = "FlockBot-5"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "flock_bot"
|
||||
name = "FlockBot-6"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "flock_bot"
|
||||
name = "FlockBot-7"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "flock_bot"
|
||||
name = "FlockBot-8"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "flock_bot"
|
||||
name = "FlockBot-9"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "flock_bot"
|
||||
name = "FlockBot-10"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "flock_bot"
|
||||
name = "FlockBot-11"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "flock_bot"
|
||||
name = "FlockBot-12"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "flock_bot"
|
||||
name = "FlockBot-13"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "flock_bot"
|
||||
name = "FlockBot-14"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "flock_bot"
|
||||
name = "FlockBot-15"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "flock_bot"
|
||||
name = "FlockBot-16"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "flock_bot"
|
||||
name = "FlockBot-17"
|
||||
|
||||
# ChumpBot copies (17)
|
||||
[[game.bots]]
|
||||
bot_type = "chump_bot"
|
||||
name = "ChumpBot-1"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "chump_bot"
|
||||
name = "ChumpBot-2"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "chump_bot"
|
||||
name = "ChumpBot-3"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "chump_bot"
|
||||
name = "ChumpBot-4"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "chump_bot"
|
||||
name = "ChumpBot-5"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "chump_bot"
|
||||
name = "ChumpBot-6"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "chump_bot"
|
||||
name = "ChumpBot-7"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "chump_bot"
|
||||
name = "ChumpBot-8"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "chump_bot"
|
||||
name = "ChumpBot-9"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "chump_bot"
|
||||
name = "ChumpBot-10"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "chump_bot"
|
||||
name = "ChumpBot-11"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "chump_bot"
|
||||
name = "ChumpBot-12"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "chump_bot"
|
||||
name = "ChumpBot-13"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "chump_bot"
|
||||
name = "ChumpBot-14"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "chump_bot"
|
||||
name = "ChumpBot-15"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "chump_bot"
|
||||
name = "ChumpBot-16"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "chump_bot"
|
||||
name = "ChumpBot-17"
|
||||
|
||||
# CallBot copies (17)
|
||||
[[game.bots]]
|
||||
bot_type = "call_bot"
|
||||
name = "CallBot-1"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "call_bot"
|
||||
name = "CallBot-2"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "call_bot"
|
||||
name = "CallBot-3"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "call_bot"
|
||||
name = "CallBot-4"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "call_bot"
|
||||
name = "CallBot-5"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "call_bot"
|
||||
name = "CallBot-6"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "call_bot"
|
||||
name = "CallBot-7"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "call_bot"
|
||||
name = "CallBot-8"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "call_bot"
|
||||
name = "CallBot-9"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "call_bot"
|
||||
name = "CallBot-10"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "call_bot"
|
||||
name = "CallBot-11"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "call_bot"
|
||||
name = "CallBot-12"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "call_bot"
|
||||
name = "CallBot-13"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "call_bot"
|
||||
name = "CallBot-14"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "call_bot"
|
||||
name = "CallBot-15"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "call_bot"
|
||||
name = "CallBot-16"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "call_bot"
|
||||
name = "CallBot-17"
|
||||
|
||||
# RaiseBot copies (17)
|
||||
[[game.bots]]
|
||||
bot_type = "raise_bot"
|
||||
name = "RaiseBot-1"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "raise_bot"
|
||||
name = "RaiseBot-2"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "raise_bot"
|
||||
name = "RaiseBot-3"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "raise_bot"
|
||||
name = "RaiseBot-4"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "raise_bot"
|
||||
name = "RaiseBot-5"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "raise_bot"
|
||||
name = "RaiseBot-6"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "raise_bot"
|
||||
name = "RaiseBot-7"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "raise_bot"
|
||||
name = "RaiseBot-8"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "raise_bot"
|
||||
name = "RaiseBot-9"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "raise_bot"
|
||||
name = "RaiseBot-10"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "raise_bot"
|
||||
name = "RaiseBot-11"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "raise_bot"
|
||||
name = "RaiseBot-12"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "raise_bot"
|
||||
name = "RaiseBot-13"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "raise_bot"
|
||||
name = "RaiseBot-14"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "raise_bot"
|
||||
name = "RaiseBot-15"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "raise_bot"
|
||||
name = "RaiseBot-16"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "raise_bot"
|
||||
name = "RaiseBot-17"
|
||||
|
||||
# RandomBot copies (16)
|
||||
[[game.bots]]
|
||||
bot_type = "random_bot"
|
||||
name = "RandomBot-1"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "random_bot"
|
||||
name = "RandomBot-2"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "random_bot"
|
||||
name = "RandomBot-3"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "random_bot"
|
||||
name = "RandomBot-4"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "random_bot"
|
||||
name = "RandomBot-5"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "random_bot"
|
||||
name = "RandomBot-6"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "random_bot"
|
||||
name = "RandomBot-7"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "random_bot"
|
||||
name = "RandomBot-8"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "random_bot"
|
||||
name = "RandomBot-9"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "random_bot"
|
||||
name = "RandomBot-10"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "random_bot"
|
||||
name = "RandomBot-11"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "random_bot"
|
||||
name = "RandomBot-12"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "random_bot"
|
||||
name = "RandomBot-13"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "random_bot"
|
||||
name = "RandomBot-14"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "random_bot"
|
||||
name = "RandomBot-15"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "random_bot"
|
||||
name = "RandomBot-16"
|
||||
|
||||
# FoldBot copies (16)
|
||||
[[game.bots]]
|
||||
bot_type = "fold_bot"
|
||||
name = "FoldBot-1"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "fold_bot"
|
||||
name = "FoldBot-2"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "fold_bot"
|
||||
name = "FoldBot-3"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "fold_bot"
|
||||
name = "FoldBot-4"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "fold_bot"
|
||||
name = "FoldBot-5"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "fold_bot"
|
||||
name = "FoldBot-6"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "fold_bot"
|
||||
name = "FoldBot-7"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "fold_bot"
|
||||
name = "FoldBot-8"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "fold_bot"
|
||||
name = "FoldBot-9"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "fold_bot"
|
||||
name = "FoldBot-10"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "fold_bot"
|
||||
name = "FoldBot-11"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "fold_bot"
|
||||
name = "FoldBot-12"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "fold_bot"
|
||||
name = "FoldBot-13"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "fold_bot"
|
||||
name = "FoldBot-14"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "fold_bot"
|
||||
name = "FoldBot-15"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "fold_bot"
|
||||
name = "FoldBot-16"
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Output settings
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
[output]
|
||||
log_hands = false
|
||||
log_actions = false
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
[game]
|
||||
game_type = "MultiTableTournament"
|
||||
num_seats = 9
|
||||
num_tables = 3
|
||||
small_blind = 10
|
||||
big_blind = 20
|
||||
starting_chips = 10000
|
||||
buy_in = 5000
|
||||
hands_per_level = 10
|
||||
num_blind_levels = 20
|
||||
|
||||
[game.bet_limit]
|
||||
type = "no_limit"
|
||||
min_raise = 20
|
||||
|
||||
[output]
|
||||
log_hands = true
|
||||
log_actions = true
|
||||
|
|
@ -1,21 +1,107 @@
|
|||
[game]
|
||||
game_type = "SitAndGo"
|
||||
num_seats = 9
|
||||
small_blind = 10
|
||||
big_blind = 20
|
||||
starting_chips = 5000
|
||||
buy_in = 1000
|
||||
hands_per_level = 10
|
||||
num_blind_levels = 15
|
||||
num_seats = 10
|
||||
starting_chips = 1500
|
||||
buy_in = 11
|
||||
randomize_seats = true
|
||||
num_tournaments = 100
|
||||
|
||||
# Custom prize structure in chip amounts: 1st=5, 2nd=3, 3rd=2
|
||||
prizes = [50, 30, 20]
|
||||
|
||||
[game.bet_limit]
|
||||
type = "no_limit"
|
||||
min_raise = 20
|
||||
|
||||
# Explicit blind levels
|
||||
[[game.blind_levels]]
|
||||
small_blind = 10
|
||||
big_blind = 20
|
||||
ante = 0
|
||||
hands = 10
|
||||
|
||||
[[game.blind_levels]]
|
||||
small_blind = 15
|
||||
big_blind = 30
|
||||
ante = 0
|
||||
hands = 10
|
||||
|
||||
[[game.blind_levels]]
|
||||
small_blind = 25
|
||||
big_blind = 50
|
||||
ante = 5
|
||||
hands = 10
|
||||
|
||||
[[game.blind_levels]]
|
||||
small_blind = 50
|
||||
big_blind = 100
|
||||
ante = 10
|
||||
hands = 10
|
||||
|
||||
[[game.blind_levels]]
|
||||
small_blind = 75
|
||||
big_blind = 150
|
||||
ante = 15
|
||||
hands = 10
|
||||
|
||||
[[game.blind_levels]]
|
||||
small_blind = 100
|
||||
big_blind = 200
|
||||
ante = 20
|
||||
hands = 10
|
||||
|
||||
[[game.blind_levels]]
|
||||
small_blind = 150
|
||||
big_blind = 300
|
||||
ante = 25
|
||||
hands = 10
|
||||
|
||||
[[game.blind_levels]]
|
||||
small_blind = 200
|
||||
big_blind = 400
|
||||
ante = 50
|
||||
hands = 10
|
||||
|
||||
# 10 bots (all 6 bot types, with duplicates to fill the table)
|
||||
[[game.bots]]
|
||||
bot_type = "flock_bot"
|
||||
name = "FlockBot-1"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "chump_bot"
|
||||
name = "ChumpBot-1"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "call_bot"
|
||||
name = "Bot 1"
|
||||
name = "CallBot-1"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "raise_bot"
|
||||
name = "RaiseBot-1"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "random_bot"
|
||||
name = "RandomBot-1"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "fold_bot"
|
||||
name = "Bot 2"
|
||||
name = "FoldBot-1"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "flock_bot"
|
||||
name = "FlockBot-2"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "call_bot"
|
||||
name = "CallBot-2"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "raise_bot"
|
||||
name = "RaiseBot-2"
|
||||
|
||||
[[game.bots]]
|
||||
bot_type = "random_bot"
|
||||
name = "RandomBot-2"
|
||||
|
||||
[output]
|
||||
log_hands = true
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue