← All work

Case study · Poker AI · 2026

Winning by testing what not to ship.

An adaptive six-player no-limit hold'em agent built through reproducible simulation, opponent modelling, and deliberate rejection of strategies that failed under pressure.

10M+simulated hands
100+agent variants
30+opponent models
5thinternational final

01 · The brief

Build for a field, not a textbook.

The Fullhouse competition used six-player no-limit hold’em. A bot had to accumulate chips across unfamiliar opponents, stay within the action interface, and make decisions quickly enough to survive the tournament infrastructure.

The difficult part was not producing plausible poker logic. It was distinguishing an improvement from noise when most variants made the same choice on most hands and a small number of large pots could dominate an average.

The governing question

Does this change improve the bot across repeated seeds and difficult opponent panels without creating a dangerous new floor?


02 · The system

An experimentation pipeline around the agent.

The bot sat inside a reproducible backtesting system: deterministic hand generation, fixed opponent panels, paired candidate-versus-baseline runs, progress reporting, and a dashboard for batching presets and independent seed ranges.

  1. Paired A/B: candidate and baseline received identical seeded hands.
  2. Seed replication: confidence came from independent seed bases, not one very long match.
  3. Floor rule: a higher mean was insufficient if an important control field regressed.
  4. Determinism check: identical instances had to produce exactly zero paired chip difference.
  5. One change per candidate: late-stage ideas were isolated so the result stayed interpretable.

That machinery mattered more than any one poker heuristic. It made rare branches observable and showed when a theoretically attractive idea did nothing—or made the agent worse.


03 · Experiments

Narrow corrections survived. Broad cleverness did not.

Kept

Postflop position fix

A correctness change that removed seat-order skew and survived repeated fields.

Kept

Nut-region value sizing

Extra pressure only with full houses, nut flushes, and safe low-SPR sets.

Kept

Premium squeeze C

A rare AA/KK/QQ/AKs branch with a small directional gain and clean controls.

Rejected

Board-aware narrowing

Theoretically appealing, but repeatedly harmful against fields that were not balanced enough.

Rejected

Broad anti-bust filters

They reacted to memorable losses but damaged too many ordinary profitable spots.

Rejected

Generic pressure packages

More activity created larger non-nut pots without enough additional fold equity.

The consistent strategic finding was that the bot’s edge came from fast, value-heavy chip accumulation—not simply avoiding elimination. The final agent stayed close to the validated core.


04 · Ship decision

Small edge, clean fallback controls.

The final confirmation sweep ran 25 jobs and 625 matches per bot across five presets with zero errors. The selected v16_squeeze_C_metacap candidate clearly beat the live qualifier baseline while remaining close to the simplest accepted upgrade.

Why this version shipped

It improved on the known baseline, did not lose the wall-balanced or barrel-heavy control fields, and kept every previously rejected broad overlay disabled.

A full fallback hierarchy was retained: the clean position-and-value fix, the original live baseline, and an older ultra-safe agent. Shipping included syntax, import, action-validity, time-budget, and backtest-error checks—not only a leaderboard number.


05 · Reflection

The experiment log became the real project.

Poker made variance impossible to ignore. Shared seeds, independent replication, control fields, and rejected branches turned subjective strategy debates into decisions that could be audited later.

Fifth place was the public result. The more durable result was a workflow for making high-variance decisions without confusing a compelling story for evidence.

Try it yourself

Play a heads-up browser adaptation.

The real competition strategy and a pure-Python game engine run locally through WebAssembly after you choose to load them.