id: 478a9f5dd5684e94a5566d49adbe57c2
parent_id: 
item_type: 1
item_id: 8469c381b4d14e03a2252a4423aae956
item_updated_time: 1781507807575
title_diff: "[{\"diffs\":[[1,\"Gen 2 V4 — Monte Carlo Multi-Way Implementation\"]],\"start1\":0,\"start2\":0,\"length1\":0,\"length2\":47}]"
body_diff: "[{\"diffs\":[[1,\"# Gen 2 V4 — Monte Carlo Multi-Way Implementation\\\n\\\n**Date:** 2026-06-15\\\n**Status:** ✅ COMPLETE\\\n\\\n## Summary\\\n\\\nImplemented Gen 2 V4: V3 production strategy with Monte Carlo multi-way equity engine. Dropped Gen 2 V2 (replaced by V4 in the registry — V4 supersedes both V2 and V3 conceptually, though V3 remains as the exact-equity baseline).\\\n\\\n## Design\\\n\\\nV3 and V4 share **identical decision logic**. The only difference is equity computation:\\\n\\\n| | V3 | V4 |\\\n|---|---|---|\\\n| HU equity | Exhaustive enumeration (exact) | Exhaustive enumeration (exact) |\\\n| Multi-way equity | Exhaustive enumeration (single-opp approximation) | Monte Carlo — true multi-way (vs strongest opp) |\\\n| Decision logic | V3 F1+F4+F7 fixes | Identical (shared via base) |\\\n\\\n### Refactor: Shared Decision Logic\\\nMoved V3's decision methods (`get_first_in_action`, `would_check_first_in`, `get_raised_pot_action`, `draw_quality`, `adjusted_ppot`, etc.) into `RolloutPostFlopBase` as `pub(crate)` methods. V3 and V4 are now thin wrappers (~100 lines each) that compute equity differently then delegate to `base.get_first_in_action_v3()` / `base.get_raised_pot_action_v3()`.\\\n\\\n## MC Equity Dispatch\\\n\\\n`RolloutPostFlopBase::compute_potential_mc(ctx)`:\\\n```\\\nif num_opponents <= 1:\\\n    hp.compute(hole, board)                  // exhaustive (exact)\\\nelse:\\\n    hp.compute_multiway_uniform(hole, board, num_opps, mc_samples, mc_seed)\\\n```\\\n\\\nUses `HandPotential::compute_multiway_uniform` — a specialized fast path that deals random cards from a shuffled deck (partial Fisher-Yates). No `HandRange` or weight-map machinery needed since every opponent hand is equally likely.\\\n\\\n### Initial Approach (slow) → Fast Path\\\nThe initial implementation used `compute_vs_range_multiway_shared` with `HandRange::init_all(1.0)`. This was 20× **slower** than V3 because the sparse-pair MC machinery (designed for Gen 3's narrow ranges) scans all ~990 candidate pairs per opponent per sample — with a uniform range there's no sparsity benefit.\\\n\\\n**Fix:** Added `compute_multiway_uniform` which skips the `HandRange`/`sample_sparse` machinery entirely and just does partial Fisher-Yates + sequential dealing. Per-sample cost dropped from O(opps × pairs) to O(cards_needed).\\\n\\\n## Changes\\\n\\\n### New Files\\\n- `holdem_bots/src/cash/rollout_postflop_v4.rs` — V4 strategy (~100 lines, thin wrapper)\\\n- `configs/bots/cash_gen2_v4.toml` — V4 bot config\\\n\\\n### Modified Files\\\n- `holdem_bots/src/cash/thresholds.rs` — Added `mc_samples` (default 20,000) and `mc_seed` (default 42) to `PostflopThresholds` (now 82 fields)\\\n- `holdem_bots/src/cash/rollout_postflop_base.rs` — Moved V3 decision logic here. Added `compute_potential_mc()` using fast uniform path.\\\n- `holdem_bots/src/cash/rollout_postflop_v3.rs` — Simplified to thin wrapper delegating to base\\\n- `holdem_bots/src/common/hand_potential.rs` — Added `compute_multiway_uniform()` fast path + 5 tests\\\n- `holdem_bots/src/cash/mod.rs` — Removed V2 module/re-export, added V4\\\n- `holdem_bots/src/assembly/registrations.rs` — Removed `g2_postflop_rollout_v2`, added `g2_postflop_rollout_v4`\\\n- `holdem_gui/src/api.rs` — Updated strategy list (removed V2, added V4) + added MC params\\\n- `README.md` — Updated strategy variants table and bot assemblies\\\n\\\n### Deleted Files\\\n- `holdem_bots/src/cash/rollout_postflop_v2.rs` — V2 strategy (superseded by V4)\\\n\\\n## Test Results\\\n- **All 345 tests pass** (5 new uniform MC tests + 24 range MC tests + 13 Gen 3 strategy tests)\\\n- Clean build, 0 warnings\\\n\\\n## Performance (10-max, 1000 hands, release build)\\\n\\\n| Config | Wall time |\\\n|--------|-----------|\\\n| 10× V3 (exhaustive) | **2.3s** |\\\n| 10× V4 (uniform MC, 20K samples) | **2.6s** |\\\n\\\nV4 is now performance-competitive with V3 (~10% slower). Initial implementation with sparse-pair MC was 50.6s — the fast path gave a **20× speedup**.\\\n\\\n## Play Quality (5v5 V3 vs V4, 10 seeds × 1000 hands)\\\n\\\nV4 wins **7 of 10 seeds** with an average edge of **+1.05 BB/hand per seat**.\\\n\\\n| Seed | V4 edge/seat | Winner |\\\n|------|:-:|:-:|\\\n| 42 | +1.93 | V4 |\\\n| 1337 | -0.20 | V3 |\\\n| 9999 | +1.12 | V4 |\\\n| 7777 | -0.25 | V3 |\\\n| 2024 | +1.85 | V4 |\\\n| 555 | +0.31 | V4 |\\\n| 314 | +0.71 | V4 |\\\n| 271 | +2.00 | V4 |\\\n| 8675 | +3.10 | V4 |\\\n| 11 | -0.01 | tie |\\\n\\\nV4's edge comes from true multi-way equity (evaluating vs the strongest opponent), while V3's exhaustive `compute()` evaluates single-opponent equity and approximates multi-way with threshold exponents.\\\n\\\n## Next Steps\\\n1. Consider V4 as new production baseline (better play quality, comparable speed)\\\n2. Parameter sweep `mc_samples` — could reduce to 10K for ~2× speedup with ±0.5% SE\\\n3. SNG-specific parameter tuning\"]],\"start1\":0,\"start2\":0,\"length1\":0,\"length2\":4605}]"
metadata_diff: {"new":{"id":"8469c381b4d14e03a2252a4423aae956","parent_id":"1246bbc3bb4948fc8329079b84b4ae3d","latitude":"0.00000000","longitude":"0.00000000","altitude":"0.0000","author":"","source_url":"","is_todo":0,"todo_due":0,"todo_completed":0,"source":"joplin-desktop","source_application":"net.cozic.joplin-desktop","application_data":"","order":1781505680114,"markup_language":1,"is_shared":0,"share_id":"","conflict_original_id":"","master_key_id":"","user_data":"","deleted_time":0},"deleted":[]}
encryption_cipher_text: 
encryption_applied: 0
updated_time: 2026-06-15T07:16:54.429Z
created_time: 2026-06-15T07:16:54.429Z
type_: 13