{"slug": "i-build-an-efficient-and-lean-poker-bot-with-ai", "title": "I build an efficient and lean Poker bot with AI", "summary": "Developer aeneassoft released QuantPlay, a 6-max poker trainer whose Python engine (~1.5 MB) runs locally in the browser via WebAssembly and Pyodide, after a three-month attempt to rank in the top 5 of the GTO Wizard AI leaderboard fell short. The trainer offers six modes — GTO, Exploit, Arena, Punishment, Tournament and Match — against profiled bots, with bot decisions made locally and no LLM involved in play; measured in Node plus Pyodide, import takes 0.9 s, five full graded hands run in 0.32 s, and the slowest single request is 0.11 s (0.35 s in tournament mode). The heads-up bot Prince lost against opponents measured over 2,992 paired decks, and the UI is in German.", "body_md": "**Play it now: [quantplay.io](https://quantplay.io)** — no account, no server, nothing to install.\nThe whole engine (Python, ~1.5 MB) is downloaded once and runs on *your* machine via WebAssembly.\nYour hands never leave your browser.\n\nQuantPlay grew out of a three-month attempt to build a heads-up bot that could rank in the top 5 of the\nGTO Wizard AI leaderboard. That goal was **not** reached (the honest balance sheet is\n[`!_PROJEKT_BILANZ_2026-09-10.md`](https://github.com/aeneassoft/QuantPlay/blob/poker-core/!_PROJEKT_BILANZ_2026-09-10.md)). What came out of it, and what this\nrepository is about, is a 6-max trainer you cannot buy anywhere, a bot with every number measured and\nsourced, and a measurement discipline that refuted more ideas than it confirmed.\n\nSix modes, all against a league of profiled bots (TAG, LAG, nit, station, maniac, whale …) whose play was tuned in paired self-play and gated against regressions:\n\n| Mode | What it trains | \n|---|---|\n| **GTO** | The bots play their baseline straight. Every decision you make is graded against the engine's own line within the hand, with a written explanation. | \n| **Exploit** | The bots learn *you* live and attack your leaks. You experience your own exploitability. | \n| **Arena** | Rotating, adaptive opponent types across all stack depths. A stress test for staying disciplined. | \n| **Punishment** | Five hunters, each built from a leak that was actually measured in human play (sheriff, iso-hammer, value press, trap nit, blind fighter). | \n| **Tournament** | A 60-player MTT (6 tables × 10) with rising blinds, antes, table balancing, a final table and a top-9 payout. ICM hints appear once the bubble factor bites. Exact Malmuth-Harville ICM, tested against independent enumeration. | \n| **Match** | Same opponents, no coaching, no distractions. Everything is recorded and graded for review afterwards. | \n\nPlus: pre-fold while others still act (the hand is played out in the background and chips move correctly),\nhand replay with per-decision grades, an opponent panel showing what the bots have learned about you, a\nsession analysis after ~100 hands, and a 61-entry poker glossary whose formulas are the audited ones in\n[`knowledge_base/math/formulas.py`](https://github.com/aeneassoft/QuantPlay/blob/poker-core/knowledge_base/math/formulas.py). The UI is in German.\n\n```\npip install -r requirements.txt\npython -m pokerbot.web.six_server --open --trainer\n```\n\nWindows / PowerShell, Python 3.12, run from the repo root. The trainer is at `http://127.0.0.1:8000/training`.\nBot decisions are local, instant and free; no LLM is involved in play.\n\n[`web/`](https://github.com/aeneassoft/QuantPlay/blob/poker-core/web) turns the *same* trainer into a static site. [`web/build.py`](https://github.com/aeneassoft/QuantPlay/blob/poker-core/web/build.py) zips the Python\npackage plus the knowledge files it reads at runtime; [`web/src/worker.js`](https://github.com/aeneassoft/QuantPlay/blob/poker-core/web/src/worker.js) boots\n[Pyodide](https://pyodide.org) in a Web Worker, installs five pure-Python wheels and imports the trainer;\n[`web/src/bridge.js`](https://github.com/aeneassoft/QuantPlay/blob/poker-core/web/src/bridge.js) replaces `fetch('/api/…')` so the unchanged front-end talks to\nthe worker instead of a server. The route dispatcher is\n[`pokerbot/web/browser_bridge.py`](https://github.com/aeneassoft/QuantPlay/blob/poker-core/pokerbot/web/browser_bridge.py), which calls the FastAPI endpoints\ndirectly (Pyodide has no threads for the ASGI threadpool). Tested under CPython in\n[`tests/test_browser_bridge.py`](https://github.com/aeneassoft/QuantPlay/blob/poker-core/tests/test_browser_bridge.py). Measured in Node + Pyodide: import 0.9 s,\nfive full hands with grading in 0.32 s, slowest single request 0.11 s (tournament mode 0.35 s).\n\n``` php\npython web/build.py                          # -> web/dist (deterministic, content-hashed)\npython -m http.server 8765 --directory web/dist\n```\n\nThe site is deployed from `web/` to Vercel. Prince (the heads-up bot) does not take over heads-up pots in\nthe trainer: measured in 2,992 paired decks it *lost* against the league core, so it is off by default and\nthe browser build ships without its neural advisors.\n\nA heuristic engine (preflop blueprint from CFR push/fold + solver-distilled tables, postflop equity /\npot odds / MDF with solver-frequency advisors) wrapped in a chain of measured guards, a bounded exploit\noverlay, and optional real-time re-solving (TexasSolver) at river/turn nodes. Every number below has a\nsource in [`docs/MESSKATALOG.md`](https://github.com/aeneassoft/QuantPlay/blob/poker-core/docs/MESSKATALOG.md); the channel decides what a number means.\n\n| Measurement | Result | Channel / n | Meaning | \n|---|---|---|---|\n| Heads-up vs **GTO Wizard AI** (the only true GTO anchor) | **−21.1 ± 9.4 bb/100** (v4, AIVAT) | live API, n = 979 | 95 % band ≈ [−39.5, −2.7]. Leaderboard top: private bots at −3.1; best frontier LLM −9.2. The current champion (v5) was never anchored. | \n| v5 vs its own base | +30.6 bb/100 | paired self-play mirror | A non-regression bound, **not** strength. Individual guard gains (~+53) did not add up. | \n| Tournament risk premium (proportional bubble factor) | **+10.0 ± 5.0 pp ROI** | paired SNG arena, n = 1,500 | The full bubble factor was refuted (−8 pp); the proportional one validated. | \n| vs **PokerSnowie** via the screen bridge | +3.2 bb/100 [−37, +44] | 3,114 clean hands of 3,651 | Break-even; the automation errors, not the bot, cost the account. | \n| Kaggle Game Arena heads-up (LLM field, 100 bb) | −0.7 ± 2.5 bb/100 vs champion | paired, 150 decks | A cheap volume channel, not a GTO anchor. | \n| Opponents who are not GTO | +300 … +700 bb/100 | local benchmark bots | The exploit layer works against exploitable play. | \n\nWhat was learned the hard way is in the balance sheet: guards around a heuristic engine hit an asymptote\n(≈ −10 predicted, never reached); self-play gains do not transfer to a re-solver; the per-hand standard\ndeviation is 294 bb, so a ±4 bb/100 answer costs ~5,400 hands; and a well-prompted frontier LLM plays\nheads-up better than this bot. Ideas that were **refuted** by measurement are listed explicitly in\n[`docs/MODULKATALOG.md`](https://github.com/aeneassoft/QuantPlay/blob/poker-core/docs/MODULKATALOG.md) — for anyone rebuilding, that is the most valuable part.\n\n| Path | What | \n|---|---|\n| [`pokerbot/engine/`](https://github.com/aeneassoft/QuantPlay/blob/poker-core/pokerbot/engine) | cards, evaluator (treys), Monte-Carlo equity, the N-player table (2–10 seats, side pots) | \n| [`pokerbot/strategy/`](https://github.com/aeneassoft/QuantPlay/blob/poker-core/pokerbot/strategy) | preflop blueprint, range tracker, postflop math, advisors, exploit model, ICM, tournament doctrine, the guard chain ( `auslese.py` ) | \n| [`pokerbot/arena/`](https://github.com/aeneassoft/QuantPlay/blob/poker-core/pokerbot/arena) | the opponent league ( `sixmax.py` ), MTT director, tournament arena | \n| [`pokerbot/web/`](https://github.com/aeneassoft/QuantPlay/blob/poker-core/pokerbot/web) | the trainer server ( `six_server.py` ), the UI (`static/training.html` ), the browser bridge | \n| [`pokerbot/coach/`](https://github.com/aeneassoft/QuantPlay/blob/poker-core/pokerbot/coach) | decision capture, grading oracle, feedback templates, replay, opponent panel, glossary | \n| [`pokerbot/autogym/`](https://github.com/aeneassoft/QuantPlay/blob/poker-core/pokerbot/autogym) | the self-improving loop: math oracle, paired gyms, gates, journal | \n| [`pokerbot/benchmark/`](https://github.com/aeneassoft/QuantPlay/blob/poker-core/pokerbot/benchmark) | GTO Wizard, Slumbot, Kaggle Game Arena harnesses, duplicate/paired evaluation | \n| [`pokerbot/vision/`](https://github.com/aeneassoft/QuantPlay/blob/poker-core/pokerbot/vision) | the PokerSnowie screen bridge (template matching, state gates, marathon guard) | \n| [`knowledge_base/`](https://github.com/aeneassoft/QuantPlay/blob/poker-core/knowledge_base) | extracted, structured knowledge: audited formulas, ranges, concepts, exploit playbook | \n| [`docs/`](https://github.com/aeneassoft/QuantPlay/blob/poker-core/docs) | [` STATE.md`](https://github.com/aeneassoft/QuantPlay/blob/poker-core/docs/STATE.md) (live state),[`MODULKATALOG.md`](https://github.com/aeneassoft/QuantPlay/blob/poker-core/docs/MODULKATALOG.md) (272 modules),[`MESSKATALOG.md`](https://github.com/aeneassoft/QuantPlay/blob/poker-core/docs/MESSKATALOG.md) (every measurement), plans and consults | \n| [`web/`](https://github.com/aeneassoft/QuantPlay/blob/poker-core/web) | the static browser build of the trainer (quantplay.io) | \n| [`tests/`](https://github.com/aeneassoft/QuantPlay/blob/poker-core/tests) | `python -m tests.test_table` ,`test_bot` ,`test_icm` ,`test_tournament` ,`test_prefold` ,`test_browser_bridge` … | \n\n`CLAUDE.md` holds the working conventions for AI-assisted sessions, including the measurement doctrine\n(paired decks, A/A null test must be exactly 0, pre-registered expectations, three-run rule).\n\n**[PolyForm Noncommercial 1.0.0](https://github.com/aeneassoft/QuantPlay/blob/poker-core/LICENSE.md).** You may use, copy, modify and share everything here for\nnoncommercial purposes: personal study, research, teaching, hobby projects, and use by noncommercial\norganizations. **Any commercial use — selling, running as a paid service, using the bot, trainer, ranges,\nknowledge base or measurements inside a commercial product or to make money at the tables for a business —\nrequires written permission.** Ask via a GitHub issue or the contact on the organization page. Keep the\n[`NOTICE`](https://github.com/aeneassoft/QuantPlay/blob/poker-core/NOTICE) file (the `Required Notice:` line) with every copy.\n\nClosed on 2026-09-10, reopened only to publish. Large artifacts (solver caches, trained nets, LLM checkpoints, hand histories) are not in the repository. The books the knowledge base was extracted from are not included either.", "url": "https://wpnews.pro/news/i-build-an-efficient-and-lean-poker-bot-with-ai", "canonical_source": "https://github.com/aeneassoft/QuantPlay", "published_at": "2026-09-24 12:20:06+00:00", "updated_at": "2026-09-24 12:30:09.478410+00:00", "lang": "en", "topics": ["artificial-intelligence", "ai-products", "ai-tools", "developer-tools"], "entities": ["QuantPlay", "aeneassoft", "GTO Wizard", "Pyodide", "Prince", "Vercel", "Python", "WebAssembly"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/i-build-an-efficient-and-lean-poker-bot-with-ai", "markdown": "https://wpnews.pro/news/i-build-an-efficient-and-lean-poker-bot-with-ai.md", "text": "https://wpnews.pro/news/i-build-an-efficient-and-lean-poker-bot-with-ai.txt", "jsonld": "https://wpnews.pro/news/i-build-an-efficient-and-lean-poker-bot-with-ai.jsonld"}}