Epic 27 & 28#94
Merged
Merged
Conversation
- src/bot/exploit.rs — new: ExploitConfig, scale_percentage, largest_active_opponent, adjust_profile with 8 deviation rules (fold-to-cbet, calling station, loose-passive sizing, nit, aggro calldown, high-WTSD, 3-bet%) - src/bot/exploitative_decider.rs — new: ExploitativeDecider<D: BotDecider> wrapper with wrap / wrap_with_config constructors and BotDecider impl - src/bot/table_snapshot.rs — SeatInfo gains pub id: Uuid populated from player.id Tests - src/bot/exploit.rs — 5 unit tests: identity (no stats), high fold-to-cbet fires, calling-station reduces bluff, thin sample no-op, clamp to valid percentage - src/bot/exploitative_decider.rs — 2 unit tests: empty-registry parity with bare decider, hot-stats diverge in ≥1 seed - src/analysis/player_stats.rs — StatsRegistry::insert_for_test helper under #[cfg(test)] Config/Docs - src/bot/mod.rs — wired exploit and exploitative_decider under #[cfg(feature = "player-stats")] - src/prelude.rs — re-exported ExploitConfig and ExploitativeDecider under player-stats gate - docs/EPIC-27_Exploitative_Decider.md — status rows flipped to ✅ for phases 0–2 and regression check; phases 3–4 remain pending - data/hands/pkarena0-session_neverends.yaml — hand history data file added (committed)
…ecider::wrap(RuleBasedDecider(TAG)) vs RuleBasedDecider(LP) integration guard using SimTable::run_n_hands.
…Maniac, 1,000 hands each. Per-rule firing counters via Arc<TelemetryDecider> + SharedTelemetry newtype (orphan rule workaround). Prints chip deltas and a rule-activity table per matchup — the output shows different rules firing for each opponent archetype (fold-to-cbet + nit vs LP, nit-only vs TP, AF + 3-bet rules vs Maniac).
New feature gate — bot-training in Cargo.toml (requires player-stats + bot-profiles, adds serde_yaml_bw for YAML output, no external optimizer dependency). src/bot/training/ module — 4 files: - encoding.rs — encode/decode between ExploitConfig and [f64; 16], bounds constants, 5 unit tests - evaluator.rs — evaluate runs SimTable::new_with_registry sessions and returns mean BB/100; default_field() returns all 8 archetypes; 3 unit tests - trainer.rs — ExploitTrainer with (1+λ)-ES (isotropic Gaussian mutation, 1/5 success rule sigma adaptation, Box-Muller N(0,1)); TrainingConfig/TrainingResult/GenerationRecord; 4 unit tests - mod.rs — clean re-exports Optimizer choice — (1+λ)-ES implemented internally (~60 lines). No external nalgebra/cmaes dependency. Fully deterministic via seeded SmallRng. Pluggable if a proper CMA-ES is wanted later. examples/train_exploit_config.rs — end-to-end demo with --output, --generations, --hands flags; prints per-generation table; saves trained config as YAML. tests/training_integration.rs — smoke test (fast) + 200-generation validation test (marked #[ignore]).
…14 total headings. The EPIC-28 doc now has a callout block at the top linking to it. Here's what the tutorial covers: ┌─────────┬───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ Section │ Content │ ├─────────┼───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤ │ §1 │ Problem formulation — what we're optimising, why it's black-box and bounded │ ├─────────┼───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤ │ §2 │ ES overview — μ/λ notation, (1+λ) vs (μ,λ), history │ ├─────────┼───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤ │ §3 │ The (1+λ)-ES algorithm — pseudocode matched line-for-line to trainer.rs │ ├─────────┼───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤ │ §4 │ 1/5 success rule — Rechenberg's derivation, self-consistency condition, the constants 1.22/0.90 │ ├─────────┼───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤ │ §5 │ Box-Muller transform — proof sketch, edge-case handling, Ziggurat alternative │ ├─────────┼───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤ │ §6 │ Bounds and encoding — why range-scaling makes σ dimensionless, continuous relaxation of integer gates │ ├─────────┼───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤ │ §7 │ BB/100 — definition, why 1B-chip stacks were wrong, bounded-stack design │ ├─────────┼───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤ │ §8 │ Noisy optimisation — why variance is a fundamental challenge, paired comparisons, replicates │ ├─────────┼───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤ │ §9 │ CMA-ES relation — what it adds (covariance matrix, evolution paths), when isotropic is sufficient, how to plug in the cmaes crate │ ├─────────┼───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤ │ §10 │ References — 8 primary sources (Rechenberg 1973, Box-Muller 1958, Hansen 2016, etc.) + accessible web links │ └─────────┴───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
- [[example]] exploitative_play — required-features = ["bot-profiles", "player-stats"] - [[test]] exploitative_play_smoke — required-features = ["bot-profiles", "player-stats"] Both were being compiled unconditionally by Cargo (no entry = attempt with whatever features are active), which caused the gated imports to fail under --no-default-features. The required-features field tells Cargo to skip them entirely when the listed features aren't enabled, which is the correct behavior for the CI no-default-features job.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Features
loose-passive sizing, nit, aggro calldown, WTSD, 3-bet%)
Config/Docs
Tests/Examples
newtype