id: 5f44523f72aa46e48eea0a2a729b5dd6
parent_id: f05e2b83e7c04401ac09b88f10930cd7
item_type: 1
item_id: 659da65d964344fc89e6b4eafac0098c
item_updated_time: 1781461563558
title_diff: "[]"
body_diff: "[{\"diffs\":[[0,\"ture\"],[-1,\"\\\nID: 659da65d964344fc89e6b4eafac0098c\\\nNotebook ID: 2c8da247905946c3aa19eb4936e16323\\\nCreated: 1780223822827\\\nUpdated: 1780223822827\\\nIs Todo: No\\\nTags: poker, project-plan, active-project\\\n\\\n---\"],[0,\"\\\n\\\nMo\"]],\"start1\":24,\"start2\":24,\"length1\":196,\"length2\":8},{\"diffs\":[[0,\"st `\"],[-1,\"rusty-\"],[1,\"super_\"],[0,\"marv\"]],\"start1\":81,\"start2\":81,\"length1\":14,\"length2\":14},{\"diffs\":[[0,\" + Gen 2\"],[1,\" + Gen 3\"],[0,\")\\\n│     \"]],\"start1\":1146,\"start2\":1146,\"length1\":16,\"length2\":24},{\"diffs\":[[0,\"ds, \"],[-1,\"17 determine_* method\"],[1,\"context helper\"],[0,\"s)\\\n│\"]],\"start1\":1230,\"start2\":1230,\"length1\":29,\"length2\":22},{\"diffs\":[[0,\"_v3.rs     #\"],[1,\" Gen 2 V3\"],[0,\" production \"]],\"start1\":1283,\"start2\":1283,\"length1\":24,\"length2\":33},{\"diffs\":[[0,\"duction \"],[-1,\"V3\"],[1,\"strategy\\\n│       │   ├── rollout_postflop_gen3.rs   # Gen 3 range-aware\"],[0,\" strateg\"]],\"start1\":1308,\"start2\":1308,\"length1\":18,\"length2\":87},{\"diffs\":[[0,\"ties\"],[-1,\" (hand_potential, etc.\"],[1,\"\\\n│           ├── hand_potential.rs          # EHS, MC multi-way engine, PotentialResult\\\n│           ├── hand_range.rs              # HandRange (2704-entry, weighted_union, sparse sampling)\\\n│           ├── hand_analyzer.rs           # board texture, draw detection\\\n│           └── player_model.rs            # opponent model (GameStage-based defaults\"],[0,\")\\\n├─\"]],\"start1\":1600,\"start2\":1600,\"length1\":30,\"length2\":357},{\"diffs\":[[0,\"\\\n    fn \"],[-1,\"act\"],[1,\"get_action\"],[0,\"(&self, \"]],\"start1\":2721,\"start2\":2721,\"length1\":19,\"length2\":26},{\"diffs\":[[0,\"Action;\\\n\"],[1,\"    fn consider_fold_as_not_applicable(&self) -> bool { false }\\\n    fn weight(&self) -> u32 { 1 }\\\n\"],[0,\"}\\\n```\\\n\\\n#\"]],\"start1\":2777,\"start2\":2777,\"length1\":16,\"length2\":114},{\"diffs\":[[0,\"callers`\"],[1,\", `num_active`\"],[0,\".\\\n\\\n---\\\n\\\n\"]],\"start1\":3449,\"start2\":3449,\"length1\":16,\"length2\":30},{\"diffs\":[[0,\"istry (1\"],[-1,\"4\"],[1,\"5\"],[0,\" types)\\\n\"]],\"start1\":3494,\"start2\":3494,\"length1\":17,\"length2\":17},{\"diffs\":[[0,\"ty) — **\"],[1,\"cash \"],[0,\"producti\"]],\"start1\":4421,\"start2\":4421,\"length1\":16,\"length2\":21},{\"diffs\":[[0,\"G |\\\n\"],[-1,\"\\\n---\\\n\\\n## Configurable Thresholds\"],[1,\"| `g3_postflop_rollout` | **Gen 3** | Range-aware postflop with MC multi-way equity, weighted decision scoring |\\\n\\\n**Note:** `chump_bot` and `flock_bot` are listed in the GUI API but were never implemented. Test opponents use Gen 1 rules or Gen 2 V3 as baselines.\\\n\\\n---\\\n\\\n## Gen 2 V3 — Production Cash Strategy\"],[0,\"\\\n\\\n`P\"]],\"start1\":4500,\"start2\":4500,\"length1\":40,\"length2\":315},{\"diffs\":[[0,\"g.\\\n\\\n\"],[-1,\"- **Defaults** in code via `Default` impl\\\n- **TOML overrides** via `from_config_map()` — accepts both integer and float TOML values\\\n- **Runtime sweeps** via `holdem_gui` — generates temp bot configs with inline overrides\"],[1,\"Uses `hp.compute()` — exhaustive enumeration against uniform opponent hands (no range weighting, no MC).\"],[0,\"\\\n\\\n##\"]],\"start1\":5104,\"start2\":5104,\"length1\":228,\"length2\":112},{\"diffs\":[[0,\".25)\"],[-1,\". Nut draws exempt. A/B tested at 0.15 (too aggressive, 1W/3L) and 0.25 (soft promote, 3W/1L).\\\n\\\nRejected: F2 (stack safeguard), F3 (OTB call clamp), F5 (draw_quality \"],[1,\"\\\n\\\n---\\\n\\\n## Gen 3 — Range-Aware Postflop Strategy\\\n\\\n**File:** `holdem_bots/src/cash/rollout_postflop_gen3.rs` (~1600 lines)\\\n\\\n### Equity Computation\\\n- **Heads-up (1 opponent):** `compute_vs_range` — exhaustive enumeration with trie optimization, range-weighted\\\n- **Multi-way (2+ opponents):** `compute_vs_range_multiway_shared` — Monte Carlo with range-weighted importance sampling, true multi-way equity against strongest opponent\\\n- **Config:** `mc_samples` (default 20,000, ±0.35% std error), `mc_seed` (default 42)\\\n\\\n### Opponent Range\\\nBuilt via `HandRange::init_opponent_range(eval, board, excluded, strong_hands_fraction, range_draw_weight)`:\\\n- **Strong made hands:** top `strong_hands_fraction` (default 0.20) by hand strength\\\n- **Strong draws:** flush draws, OESDs, overcards — scaled by `range_draw_weight` (default 1.0)\\\n- Combined via `weighted_union` (max of scaled weights)\\\n\\\n### Weighted Decision Scoring (OR-chain refactored)\\\nReplaces OR-chain call/raise logic with dynamic threshold adjustments. Each factor (draw quality, pot odds, commitment, bluff equity) subtracts from the base threshold, making every parameter effective:\\\n\\\n**`should_call(ctx, equity, model)`:**\\\n- Base threshold from `call_base` + bet size + model modifier\\\n- Lowered by: `call_w_draw` (draw quality), `call_w_pot_odds` (favorable odds, clamped 0.3), `call_w_commitment` (chips invested)\\\n- **Floor:** `threshold.max(required_equity * 0.5)` — prevents degenerate over-calling\\\n- Decision: `win_prob.powf(call_adj) > threshold`\\\n\\\n**`should_raise(ctx, equity, model)`:**\\\n- Base threshold from `raise_base` + bet size + model modifier\\\n- Lowered by: `raise_w_draw` (draw quality), `raise_w_bluff` (bluff equity)\\\n- Decision: `win_prob.powf(raise_adj) > threshold`\\\n\\\n### Gen3Config Parameters (29 total)\\\n\\\n| Category | Parameters |\\\n|----------|-----------|\\\n| Range | `strong_hands_fraction`, `bluff_factor`, `range_draw_weight` |\\\n| Equity | `mc_samples`, `mc_seed` |\\\n| Bet | `bet_flop_base`, `bet_turn_base` |\\\n| Raise | `raise_base`, `raise_cheap_flop`, `raise_ppot_base`, `raise_w_draw`, `raise_w_bluff` |\\\n| Call | `call_base`, `call_ppot_base`, `call_w_draw`, `call_w_pot_odds`, `call_w_commitment` |\\\n| Draws | `draw_call_ppot_thresh` |\\\n| Traps | `check_raise_flop`, `check_raise_turn`, `rope_a_dope_flop`, `rope_a_dope_turn` |\\\n| Bluffs | `semi_bluff_hs_base`, `semi_bluff_ppot_base`, `bluff_success_\"],[0,\"floor\"],[-1,\"), F6 (adj_ppot 0.3 floor)\"],[1,\"`, `conti_bet_fold_thresh` |\\\n| Runtime | `sweep_mode` (bool, default true — deterministic RNG for sweeps; false = system entropy for live) |\\\n\\\n### Deterministic Decision RNG\\\n`decision_rng()` seeds `StdRng` from `mc_seed + win_prob.to_bits() + pot_size + num_active`. When `sweep_mode = false`, mixes in `rand::random::<u64>()` for non-reproducible play.\\\n\\\n### Benchmark (10K hands, 6-max, seed 42)\\\n| Bot | Avg BB/Hand |\\\n|-----|-------------|\\\n| Gen 3 | **+2.53** |\\\n| Gen 2 V3 | +1.02 |\\\n| Gen 1 | -3.55 |\"],[0,\"\\\n\\\n--\"]],\"start1\":5603,\"start2\":5603,\"length1\":205,\"length2\":2884},{\"diffs\":[[0,\"on from \"],[-1,\"84 \"],[0,\"configur\"]],\"start1\":9051,\"start2\":9051,\"length1\":19,\"length2\":16},{\"diffs\":[[0,\"art\\\n\"],[-1,\"- Raw Output panel preserves open state across re-renders\\\n\\\n### API Endpoints\\\n| Endpoint | Method | Description |\\\n|----------|--------|-------------|\\\n| `/api/bots` | GET | List bot configs |\\\n| `/api/bots/{name}` | GET/POST | Get/save bot config |\\\n| `/api/sim-configs` | GET | List sim configs |\\\n| `/api/strategies` | GET | List registered strategies |\\\n| `/api/params` | GET | List configurable parameters (84 fields) |\\\n| `/api/experiments` | GET/POST | List/create experiments |\\\n| `/api/experiments/{id}` | GET | Get experiment details + results |\\\n| `/api/experiments/{id}/cancel` | POST | Cancel running experiment |\\\n\\\n---\\\n\\\n## Java → Rust Idiom Mapping\\\n\\\n| Java | Rust | Notes |\\\n|---|---|---|\\\n| `interface Strategy` | `trait Strategy` | `Send + Sync` bounds |\\\n| `ModularStrategy extends Strategy` | Struct implementing trait | Composition over inheritance |\\\n| `BigStackStrategy extends ModularStrategy` | `BigStackBot` implementing `Strategy` directly | Flat delegation |\\\n| `ModularStrategy implements HoldemPlayer` | `StrategyBot` wraps `Strategy` | Adapter pattern |\\\n| `HandAnalyzer` singleton | `HandAnalyzer` with `Arc<Evaluator>` | `OnceLock` singleton |\\\n| `null` | `Option<T>` | Idiomatic |\\\n\\\n---\\\n\\\n## Bot Factory: Plugin Registration Pattern\\\n\\\n1. `holdem_core` handles built-in bots directly in `create_bot()` — zero overhead\\\n2. `holdem_bots` exports `register_bots()` calling `register_bot_type()` for custom bots\\\n3. `--bot-dir` flag loads additional `.toml` bot definitions from a directory\\\n\\\nDependency flows correctly: `holdem_gui` → `holdem_bots` → `holdem_core`\\\n\\\n---\\\n\\\n## Public vs Private Separation\\\n\\\n**Public (holdem_core):** All traits, analysis tools, ModularStrategy, ActionRecorder, StrategyContext, StrategyBot, simple test bots, evaluator\\\n\\\n**Private (holdem_bots):** BigStackBot, ShortStackBot, preflop strategy tables, PostFlopStrategy, configurable thresholds\\\n\\\n**Tooling (holdem_gui):** Experiment GUI, parameter sweep engine, results visualization — depends on `holdem_bots` for config types and binary path\"],[1,\"\\\n---\\\n\\\n## Java → Rust Idiom Mapping\\\n\\\n| Java | Rust | Notes |\\\n|---|---|---|\\\n| `interface Strategy` | `trait Strategy` | `Send + Sync` bounds |\\\n| `ModularStrategy extends Strategy` | Struct implementing trait | Composition over inheritance |\\\n| `BigStackStrategy extends ModularStrategy` | `BigStackBot` implementing `Strategy` directly | Flat delegation |\\\n| `ModularStrategy implements HoldemPlayer` | `StrategyBot` wraps `Strategy` | Adapter pattern |\\\n| `HandAnalyzer` singleton | `HandAnalyzer` with `Arc<Evaluator>` | `OnceLock` singleton |\\\n| `null` | `Option<T>` | Idiomatic |\"],[0,\"\\\n\\\n--\"]],\"start1\":9368,\"start2\":9368,\"length1\":2032,\"length2\":585},{\"diffs\":[[0,\"ies.\"],[-1,\" No manual config file management needed.\"],[0,\"\\\n- *\"]],\"start1\":10773,\"start2\":10773,\"length1\":49,\"length2\":8},{\"diffs\":[[0,\"attacks.\"],[1,\"\\\n- **Weighted threshold scoring over OR-chains:** Gen 3 uses dynamic threshold adjustments instead of OR-chain conditions. Each parameter (draw weight, pot odds, commitment) shifts the call/fold boundary for all hands, making every parameter effective in parameter sweeps.\"]],\"start1\":10943,\"start2\":10943,\"length1\":8,\"length2\":280}]"
metadata_diff: {"new":{},"deleted":[]}
encryption_cipher_text: 
encryption_applied: 0
updated_time: 2026-06-14T18:26:51.069Z
created_time: 2026-06-14T18:26:51.069Z
type_: 13