id: b0490e35837a4abc86c00d773005b5f5
parent_id: 
item_type: 1
item_id: 0f0e106e3da94b75a2223dd2b22aafca
item_updated_time: 1782797468948
title_diff: "[{\"diffs\":[[1,\"Gen 3 — Range-Aware Equity (State of the Art)\"]],\"start1\":0,\"start2\":0,\"length1\":0,\"length2\":45}]"
body_diff: "[{\"diffs\":[[1,\"# Gen 3 — Range-Aware Equity\\\n\\\n> **Current state, 2026-06-30.** Core postflop engine used by all production configs. Gen 4 wraps Gen 3 and feeds it better ranges and adaptive thresholds.\\\n\\\n## Role in the Framework\\\n\\\nGen 3 is the postflop engine used by **all production configs**. Both `cash_nl.toml` (Gen 3 baseline) and `cash_nl_g4_live.toml` (Gen 4 production) use the Gen 3 postflop strategy — Gen 4 wraps Gen 3 and feeds it better ranges.\\\n\\\nThe `RolloutPostFlopGen3` struct is the most important file in the codebase for postflop decisions.\\\n\\\n## Preflop Maneuver\\\n\\\n**Identical to Gen 2** — uses the same shared components:\\\n\\\n| Priority | Strategy | When |\\\n|---|---|---|\\\n| 1 | `g2_ke_hu_nash` | HU, 15-25 BB |\\\n| 2 | `g1_short_stack_preflop` | ≤25 BB |\\\n| 3 | `ng_preflop` | >25 BB |\\\n\\\n## Postflop Maneuver\\\n\\\n### Gen 3 Postflop: `g3_postflop_rollout`\\\n\\\nThe key innovation: **range-aware equity**. Instead of computing equity vs random opponent hands, Gen 3 predicts a range of likely opponent holdings and computes equity against that range.\\\n\\\n**Decision flow:**\\\n1. **Range prediction**: Use a static `PlayerModel` (26 probability fields: preflop_open_raise, flop_bet, flop_fold_to_bet, etc.) to predict the opponent's range width\\\n2. **Range construction**: Build a weighted range of hands consistent with the opponent's actions so far this hand\\\n3. **Equity computation**: Monte Carlo using only hands within the predicted range (not all 1326 hands)\\\n4. **Decision**: Same threshold-based logic as Gen 2 (calls use `win_prob`, bets/raises use `hs`)\\\n\\\n> **Note**: The `range_tightness_scale` threshold discount was **removed** (2026-06-29). It double-counted range narrowing — once in equity (narrower ranges → lower hs/win_prob), once in the threshold. Removing it fixed the 88-shove bug where thresholds went negative.\\\n\\\n### The `Gen3Equity` Struct\\\n\\\n```rust\\\npub struct Gen3Equity {\\\n    hs: f64,           // Hand strength vs predicted range\\\n    ppot: f64,         // Positive potential\\\n    npot: f64,         // Negative potential\\\n    nutpot: f64,       // Nut potential\\\n    rpot: f64,         // Robustness\\\n    win_prob: f64,     // EHS = hs*(1-npot) + (1-hs)*ppot\\\n    range_width: f64,  // Effective range width (1.0 = full, <1.0 = narrowed)\\\n}\\\n```\\\n\\\n### Pot Odds Gate\\\n\\\n`should_raise()` includes:\\\n1. **Large bet penalty**: facing bet >30% pot → threshold increases proportionally\\\n2. **SPR penalty**: SPR >2 → threshold increases by up to 0.18\\\n3. **Hard equity gate**: hs <0.60 + committing >100% pot → threshold ≥0.65\\\n\\\n### Bet Sizing\\\n\\\nConfigurable bet fractions by street (current **live** values after post-discount sweep):\\\n- **Flop**: `bet_flop_base = 0.15`\\\n- **Turn**: `bet_turn_base = 0.40`\\\n- **Value bets**: fraction based on hand strength above threshold\\\n- **Protection bets**: smaller bets with vulnerable made hands\\\n- **Bluffs**: `bluff_hs_max = 0.05` (only bluff with hs < 0.05)\\\n\\\n## Configs\\\n\\\n| Config | Chain | Notes |\\\n|---|---|---|\\\n| `cash_nl.toml` | ke_hu → short_stack → ng_preflop → g3_postflop_rollout | Gen 3 baseline (non-adaptive) |\\\n| `cash_nl_normal.toml` | same chain, different thresholds | Tuned for normal VPIP tables |\\\n| `cash_nl_loose.toml` | same chain, looser thresholds | Tuned for loose tables |\\\n| `cash_nl_tight.toml` | same chain, tighter thresholds | Tuned for tight tables |\\\n\\\n## Key Thresholds (current live values)\\\n\\\n```\\\n# Call decisions\\\ncall_base = 0.45\\\ncall_ppot_base = 0.25\\\ncall_w_draw = 0.75\\\ncall_w_pot_odds = 0.70\\\n\\\n# Bet decisions (post-discount sweep)\\\nbet_flop_base = 0.15\\\nbet_turn_base = 0.40\\\n\\\n# Raise decisions\\\nraise_base = 0.80\\\nraise_w_protection = 0.35\\\nraise_w_draw = 0.50\\\n\\\n# Bluff safety\\\nbluff_hs_max = 0.05\\\nsemi_bluff_max_bet_ratio = 0.30\\\n\\\n# Range construction (weight map)\\\nnarrow_center_offset = 0.2\\\nstrong_hands_fraction = 0.30\\\nscurve_steepness_mult = 0.3\\\n```\\\n\\\n## Key Files\\\n\\\n| File | Content |\\\n|---|---|\\\n| `holdem_bots/src/cash/rollout_postflop_gen3.rs` | Gen 3 strategy + Gen3Config + Gen3Equity |\\\n| `holdem_bots/src/cash/thresholds.rs` | PostflopThresholds (80+ fields, Default, from_config_map) |\\\n| `holdem_bots/src/common/player_model.rs` | Static PlayerModel (26 probability fields) |\\\n\\\n## Open Issues\\\n\\\n- **Static player model**: The `PlayerModel` uses fixed default frequencies — it doesn't adapt to specific opponents. **Addressed by Gen 4** (dynamic observer replaces static model).\\\n- **Cold-start problem**: First decisions against unknown opponents use default ranges that may be inaccurate. **Addressed by Gen 4** (profile persistence + three-tier blend).\\\n- **Single range**: Gen 3 predicts ONE range per opponent. Multi-way pots need separate ranges per active opponent. **Partially addressed by Gen 4** (per-opponent ranges in multiway).\\\n\\\n## Where This Goes Next\\\n\\\nGen 4 wraps Gen 3 and replaces the static `PlayerModel` with a **dynamic observer** that tracks real opponent stats (VPIP, PFR, AF, bet frequencies) via EMA, then uses those stats to build more accurate ranges and adapt thresholds. Gen 5 will eventually replace the heuristic decision logic with a neural network.\"]],\"start1\":0,\"start2\":0,\"length1\":0,\"length2\":5024}]"
metadata_diff: {"new":{"id":"0f0e106e3da94b75a2223dd2b22aafca","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":1782623778613,"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-30T05:37:45.244Z
created_time: 2026-06-30T05:37:45.244Z
type_: 13