id: 334a2b23dd604b3b801ada1299fed481
parent_id: 
item_type: 1
item_id: e7960a975c4f4d45b9472754cab5112c
item_updated_time: 1782143672732
title_diff: "[{\"diffs\":[[1,\"Gen 3 Baseline — Implementation Plan\"]],\"start1\":0,\"start2\":0,\"length1\":0,\"length2\":36}]"
body_diff: "[{\"diffs\":[[1,\"# Gen 3 Baseline — Port NGPostFlopStrategyV3 to Rust\\\n\\\n## Goal\\\nPort the Java Gen 3 postflop strategy (`NGPostFlopStrategyV3`) to Rust as a new\\\nstrategy `g3_postflop_rollout`. The key Gen 3 innovation: equity is computed\\\nagainst **predicted opponent card holdings (weighted maps)** instead of uniform\\\nrandom hands. Additionally, integrate rpot/nutpot considerations from the\\\nexisting Rust nut-aware infrastructure.\\\n\\\n## Source Files (Java)\\\n- `sng/supersonic/development/NGPostFlopStrategyV3.java` — 1358 lines (main strategy)\\\n- `sng/supersonic/development/NGShortHandedPostFlopStrategyV3.java` — 53 lines (override)\\\n- `common/supersonic/RangePredictor.java` — 477 lines (range tracking)\\\n- `common/supersonic/HandRange.java` — 290 lines (weighted range)\\\n- `common/supersonic/PlayerModelV3.java` — 966 lines (opponent statistics)\\\n\\\n## Target Files (Rust) — 7 new/modified files\\\n\\\n### Phase 1: Weighted Range Infrastructure\\\n**NEW: `holdem_bots/src/common/hand_range.rs`**\\\n\\\nPort `HandRange` from Java. A weighted map of all possible 2-card holdings.\\\n\\\n```rust\\\npub struct HandRange {\\\n    weights: [[f64; 52]; 52],  // weights[card_a][card_b] = weight\\\n}\\\n```\\\n\\\nMethods to implement:\\\n- `new()` — all zeros\\\n- `init_all(weight)` — set all pairs to `weight`\\\n- `clear_card(card)` — zero out all pairs containing `card`\\\n- `init_strong_hands(board_cards, hole, top_fraction)` — top X% by hs on board\\\n- `init_strong_draws(board_cards, hole)` — flush draws + OESDs + two overcards\\\n- `init_top_preflop_hands(remaining, fraction)` — top X% by preflop ranking\\\n- `unset_low_ranking_postflop_hands(board, remaining, top_fraction)` — filter weak\\\n- `set_pocket_pairs(remaining, fraction)`\\\n- `set_suited_aces(remaining, fraction)`\\\n- `set_suited_connectors(remaining, fraction)`\\\n- `get_weight(c1, c2) -> f64`\\\n- `set_weight(c1, c2, w)`\\\n- `sum() -> f64`\\\n- `is_empty() -> bool`\\\n\\\nDependencies:\\\n- Needs `HandPotential::compute_hs_for_cards()` to evaluate hs for each pair (for init_strong_hands)\\\n- Needs hand classification helpers (is_flush_draw, is_oesd, is_two_overcards) for init_strong_draws\\\n\\\n### Phase 2: Weighted Equity Computation\\\n**MODIFY: `holdem_bots/src/common/hand_potential.rs`**\\\n\\\nAdd weighted computation methods:\\\n\\\n```rust\\\nimpl HandPotential {\\\n    /// Compute hs/ppot/npot/nutpot/rpot weighted by an opponent HandRange.\\\n    pub fn compute_vs_range(\\\n        &self, hole: &[Card; 2], board_cards: &[Card], range: &HandRange,\\\n    ) -> PotentialResult { ... }\\\n\\\n    /// Compute hs for a specific pair of cards (used by HandRange::init_strong_hands).\\\n    pub fn hs_for_cards(\\\n        &self, c1: Card, c2: Card, board_cards: &[Card],\\\n    ) -> f64 { ... }\\\n}\\\n```\\\n\\\nThe `compute_vs_range` method is structurally identical to the existing\\\n`compute_flop`/`compute_turn`, but each opponent pair (i,j) is weighted by\\\n`range.get_weight(remaining[i], remaining[j])` instead of 1.0. This affects:\\\n- The HP[][] transition matrix (weighted counts)\\\n- The nutpot/rpot accumulators (weighted completion tracking)\\\n- The hs computation (weighted ahead/tied/behind counts)\\\n\\\nPerformance: ~3× the Gen 2 cost. With incremental trie + rayon, ~15-20ms/decision.\\\n\\\n### Phase 3: Default Player Model\\\n**NEW: `holdem_bots/src/common/player_model.rs`**\\\n\\\nPort `PlayerModelV3` default reference values and methods.\\\n\\\n```rust\\\npub struct PlayerModel {\\\n    // Preflop stats\\\n    preflop_open_raise: f64,      // 0.104\\\n    preflop_raise_limpers: f64,   // 0.095\\\n    preflop_3bet: f64,            // 0.045\\\n    preflop_4bet: f64,            // 0.053\\\n    // Flop stats (8 fields)\\\n    flop_conti_bet: f64,          // 0.729\\\n    flop_bet: f64,                // 0.305\\\n    flop_raise_cbet: f64,         // 0.162\\\n    flop_raise: f64,              // 0.097\\\n    flop_3bet: f64,               // 0.081\\\n    flop_4bet: f64,               // 0.294\\\n    flop_fold_to_conti_bet: f64,  // 0.654\\\n    flop_fold_to_bet: f64,        // 0.756\\\n    // Turn stats (7 fields)\\\n    // River stats (7 fields)\\\n}\\\n```\\\n\\\nMethods:\\\n- `default_reference() -> Self` — early-stage defaults\\\n- `default_short() -> Self` — short-handed stage defaults\\\n- `default_hu() -> Self` — HU stage defaults\\\n- `model_modifier(ctx, aggressor_seat) -> f64` — 0.75–1.33, sqrt-clamped\\\n- `all_fold_to_conti_bet(ctx) -> f64` — compound fold probability\\\n- `all_fold_to_bet(ctx) -> f64` — compound fold probability\\\n- `someone_bets(ctx) -> f64` — probability of facing a bet\\\n\\\nAll use `ctx` for player/position info. Initial baseline uses default reference\\\nvalues (no per-opponent tracking — that's Gen 4 territory).\\\n\\\n### Phase 4: Gen 3 Postflop Strategy\\\n**NEW: `holdem_bots/src/cash/rollout_postflop_gen3.rs`**\\\n\\\nPort `NGPostFlopStrategyV3` decision logic (~800 lines).\\\n\\\n```rust\\\npub struct RolloutPostFlopGen3 {\\\n    base: RolloutPostFlopBase,\\\n    model: PlayerModel,\\\n    config: Gen3Config,\\\n}\\\n\\\npub struct Gen3PotentialResult {\\\n    hs: f64,                    // Raw hand strength (uniform)\\\n    ppot_vs_ranges: f64,        // ppot vs strong hands (top 20%)\\\n    npot_vs_ranges: f64,        // npot vs strong draws\\\n    nutpot_vs_ranges: f64,      // nutpot vs strong hands (RUST ENHANCEMENT)\\\n    rpot_vs_ranges: f64,        // rpot vs strong hands (RUST ENHANCEMENT)\\\n    win_prob_vs_ranges: f64,    // EHS with range-aware ppot/npot\\\n    win_prob_nut_aware: f64,    // Nut-aware EHS (RUST ENHANCEMENT)\\\n}\\\n```\\\n\\\nDecision flow (matching Java NGPostFlopStrategyV3):\\\n\\\n```\\\nget_action(ctx):\\\n  equity = compute_gen3_equity(ctx)\\\n  strength = max(hs, win_prob_vs_ranges)\\\n  if first_in (to_call == 0 && num_raises == 0):\\\n    get_first_in_action(ctx, equity)\\\n  else:\\\n    get_raised_pot_action(ctx, equity)\\\n\\\nget_first_in_action():\\\n  1. Check-raise trap?\\\n     strength^cr_adjustment > cr_threshold && random < cr_chance\\\n  2. Conti-bet?\\\n     i_am_preflop_aggressor && fold_prob > threshold && ppot < cap\\\n  3. Semi-bluff?\\\n     hs + ppot conditions + fold probability\\\n  4. Luring bet?\\\n     monster hand (hs ~0.98), small bet to induce\\\n  5. Bluff bet?\\\n     strength < bluff_threshold && fold_prob > 0.4\\\n  6. Regular bet?\\\n     strength^bet_adjustment > bet_threshold\\\n  7. Check\\\n\\\nget_raised_pot_action():\\\n  1. Conti-bet defense?\\\n     facing cbet from preflop aggressor, flop, heads-up\\\n  2. Semi-bluff raise?\\\n     same conditions as semi-bluff but as raise\\\n  3. Rope-a-dope?\\\n     monster, call to trap (strength^adj > threshold, random < chance)\\\n  4. Raise?\\\n     strength^raise_adj > raise_threshold\\\n     || ppot > raise_ppot_threshold && num_active <= 3\\\n     || raise_bluff_profitable()\\\n  5. Call?\\\n     strength^call_adj > call_threshold\\\n     || ppot > call_ppot_threshold\\\n     || pot_odds_good_enough\\\n     || committed (push_when_calling)\\\n  6. Fold\\\n```\\\n\\\nThreshold functions (all dynamic, using effective_m, board texture, player model):\\\n- `determine_bet_threshold()` — Java L700-745\\\n- `determine_raise_threshold()` — Java L768-805\\\n- `determine_call_threshold()` — Java L848-882\\\n- `determine_check_raise_threshold()` — Java L896-915\\\n- `determine_check_raise_chance()` — Java L917-939\\\n- `determine_rope_a_dope_threshold()` — Java L959-968\\\n- `determine_rope_a_dope_chance()` — Java L970-979\\\n- `determine_bluff_bet_threshold()` — Java L662-698\\\n\\\nBluff/deception tactics:\\\n- `conti_bet()` + `get_conti_bet_action()` — Java L462-482\\\n- `conti_bet_defense()` + `get_conti_bet_defense_action()` — Java L487-515\\\n- `semi_bluff()` + `get_semi_bluff_action()` — Java L520-573\\\n- `luring_bet()` + `get_luring_bet_action()` — Java L619-632\\\n- `back_alley_mug()` + `get_back_alley_mug_action()` — Java L578-614\\\n- `post_oak_bluff()` — Java L637-641\\\n- `raise_bluff_profitable()` — Java L359-385\\\n\\\nUtility methods:\\\n- `scare_card_hit()` — Java L328-357 (compares strong hand ranges)\\\n- `is_dangerous_board()` — npotVsRanges > threshold\\\n- `amount_modification()` — Java L391-424 (round raises, handle near-allin)\\\n- `push_when_calling()` — Java L1035-1046\\\n- `pot_odds_good_enough_for_call()` — Java L832-846\\\n\\\nNUT-AWARE ENHANCEMENTS (Rust-specific, per user request):\\\n- Draw quality: `nutpot_vs_ranges / (nutpot_vs_ranges + rpot_vs_ranges + epsilon)`\\\n- Adjusted ppot: `ppot_vs_ranges * (base_weight + quality_weight * draw_quality)`\\\n- Nut-aware win_prob: `win_prob + (1-win_prob)*nutpot*0.5 - win_prob*rpot*0.5`\\\n- Raise safety gate: block non-nut draws when npot > ceiling (from V3 F7)\\\n- Use `max(hs, win_prob_nut_aware)` as the primary strength metric\\\n\\\n### Phase 5: Config & Registration\\\n**MODIFY: `holdem_bots/src/cash/mod.rs`** — add `rollout_postflop_gen3` module + re-export\\\n**MODIFY: `holdem_bots/src/common/mod.rs`** — add `hand_range` + `player_model` modules\\\n**MODIFY: `holdem_bots/src/assembly/registrations.rs`** — register `g3_postflop_rollout`\\\n**NEW: `configs/bots/cash_gen3.toml`** — Gen 3 cash bot config\\\n\\\nGen3Config parameters (extracted from Java hardcoded values, sweepable):\\\n```rust\\\npub struct Gen3Config {\\\n    // Range construction\\\n    pub strong_hands_fraction: f64,     // 0.20\\\n    // Bluff parameters\\\n    pub bluff_factor: f64,              // 2.0\\\n    pub turn_conti_factor: f64,         // 1.0\\\n    // Base thresholds (before effective_m / model adjustment)\\\n    pub bet_flop_base: f64,             // 0.6\\\n    pub bet_turn_base: f64,             // 0.83\\\n    pub bet_river_base: f64,            // 0.9\\\n    pub raise_base: f64,                // 0.93\\\n    pub call_base: f64,                 // 0.75\\\n    pub check_raise_base: f64,          // 0.95\\\n    pub rope_a_dope_base: f64,          // 0.96\\\n    // PPot thresholds\\\n    pub raise_ppot_base: f64,           // 0.42\\\n    pub call_ppot_base: f64,            // 0.38\\\n    pub call_ppot_floor: f64,           // 0.20\\\n    // Conti-bet parameters\\\n    pub conti_bet_fold_threshold: f64,  // 0.315\\\n    pub conti_bet_ppot_cap: f64,        // 0.35\\\n    // Model modifier bounds\\\n    pub model_modifier_min: f64,        // 0.75\\\n    pub model_modifier_max: f64,        // 1.33\\\n    // Nut-aware weights (Rust enhancement)\\\n    pub nut_bonus_weight: f64,          // 0.5\\\n    pub rpot_discount_weight: f64,      // 0.5\\\n    pub draw_quality_epsilon: f64,      // 0.001\\\n    pub npot_raise_ceiling: f64,        // 0.25\\\n    // ... more as identified during implementation\\\n}\\\n```\\\n\\\n### Phase 6: Verify\\\n1. `cargo build --release`\\\n2. Unit tests for HandRange, weighted equity, player model\\\n3. Run: `./target/release/holdem_bots --config configs/bots/cash_gen3.toml --hands 10000`\\\n4. Compare Gen 3 vs Gen 2 V3 win rates\\\n5. Register in GUI for parameter sweeps\\\n\\\n## Implementation Order\\\n1. Phase 1: hand_range.rs (can test independently)\\\n2. Phase 2: hand_potential.rs weighted methods (test vs known values)\\\n3. Phase 3: player_model.rs (test default values)\\\n4. Phase 4: rollout_postflop_gen3.rs (the big one)\\\n5. Phase 5: registration + config\\\n6. Phase 6: verify\\\n\\\n## Estimated Effort\\\n- Phase 1: ~300 lines, 2-3 hours\\\n- Phase 2: ~200 lines, 2-3 hours (performance-sensitive)\\\n- Phase 3: ~250 lines, 1-2 hours\\\n- Phase 4: ~800 lines, 4-6 hours\\\n- Phase 5: ~100 lines, 1 hour\\\n- Phase 6: testing, 1-2 hours\\\n- Total: ~1650 lines, ~12-17 hours\\\n\\\n## Notes\\\n- Keep Gen 2 V3 as-is — Gen 3 is additive\\\n- Initial baseline uses default reference player model (no tracking)\\\n- Nut-aware enhancements are Rust-specific improvements over the Java original\\\n- All Java hardcoded constants extracted to Gen3Config for sweeping\\\n- After baseline is working, apply structural improvements one-by-one\"]],\"start1\":0,\"start2\":0,\"length1\":0,\"length2\":11226}]"
metadata_diff: {"new":{"id":"e7960a975c4f4d45b9472754cab5112c","parent_id":"abc167de888d41bf9391c373e90dec8d","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":1781267569767,"user_updated_time":1781267569767,"markup_language":1,"is_shared":0,"share_id":"","conflict_original_id":"","master_key_id":"","user_data":"","deleted_time":1782143672732},"deleted":[]}
encryption_cipher_text: 
encryption_applied: 0
updated_time: 2026-06-22T15:57:19.169Z
created_time: 2026-06-22T15:57:19.169Z
type_: 13