A high-performance, vectorized Poker River Solver built in Python.
This tool calculates Game Theory Optimal (GTO) strategies for No-Limit Texas Hold'em river scenarios. It was built to address common issues with LLM-generated solvers by ensuring mathematical correctness (handling blockers/pot odds), high performance (vectorized NumPy engine), and a clean, interactive visualization.
- Vectorized Engine: Uses NumPy memory arrays to solve full 52-card deck scenarios at ~7,000 iterations/second in pure Python (no C++ compilation required).
- Dynamic Solving: Input any board texture (e.g.,
"Ah Ks Qh Jh Th") to rebuild the game tree and re-solve on the fly. - Interactive Analysis: A heatmap visualization (
index.html) to study GTO ranges, bluffing frequencies, and value betting. - Play vs Bot: A real-time training mode (
play.html) where you can play hands against the solution you just generated. - Correct Logic: Properly handles card removal (blockers), pot odds, and polarized betting ranges.
- Install Python 3.8+
- Install dependencies:
(Dependencies:
pip install -r requirements.txt
numpy,fastapi,uvicorn,treys)
Run the backend server. This handles the heavy math and serves the API.
python main.pyYou will see Uvicorn running on http://0.0.0.0:8000.
Note: The server will:
- Auto-create
logs/directory for activity logs - Auto-create
strategy_cache/directory to cache solutions - Read configuration from
config.json(optional, falls back to defaults)
To modify settings, edit config.json and restart the server.
Open index.html in your web browser.
- Input Board: Type a board like
Ks Th 7s 4d 2sin the text box. - Click Solve: The engine will retrain for that specific board.
- Study: View the 13x4 grid to see exactly which hands to Bet (Red), Check/Call (Green), or Fold (Blue).
Open play.html in your web browser.
- The game automatically loads the board and strategy you solved in step 2.
- Play: You will be dealt a hand (that doesn't conflict with the board).
- Test: Try to bluff the bot or catch its bluffs. The bot plays according to the GTO probabilities calculated by the engine.
- Open index.html and solve a unique board, e.g., Ah Kh Qh Jh Th (All Hearts).
- Open play.html.
- Look at the Table: You should see A♥ K♥ Q♥ J♥ T♥ on the board.
- Look at the Deck: You should never be dealt a Heart (since they are all on the board).
- Game Logic: The solver maps the 52-card deck into integer arrays. It pre-calculates a Payoff Matrix (52x52) using the
treysevaluator to determine the winner of every possible showdown instantly. - Vectorized CFR: Instead of traversing a tree of objects (slow), the algorithm performs matrix operations on flat
NumPyarrays (fast). This allows it to simulate millions of poker hands in seconds. - API:
main.pyusesFastAPIto expose endpoints. When you change the board, the server rebuilds the game object and retrains the model from scratch. - Input Validation: All board inputs are validated for correct format, duplicates, and valid card values before solving.
- Error Handling: The API returns meaningful error messages with HTTP status codes for invalid inputs.
- Logging: All activity is logged to
logs/poker_solver_*.logfor debugging and monitoring. - Configuration: Customizable settings via
config.json(default iterations, pot sizes, API port, etc.). - Caching: Solved strategies are automatically saved to
strategy_cache/and reused on subsequent requests.
The bot in play.html is not random. It is connected directly to the solver's brain:
- Fetch: On load, it downloads the exact strategy matrix generated by
main.py. - Lookup: When it's the bot's turn, it looks up its specific hand (e.g.,
Q♥) in the strategy matrix. - Decision: It uses the calculated probabilities (e.g., "Call 20%, Fold 80%") to make a weighted random decision.
| Endpoint | Method | Description |
|---|---|---|
/train |
GET | Train solver on a board. Params: board, iters |
/solution |
GET | Get current solution and strategies |
/cache/list |
GET | List all cached board solutions |
/cache/clear |
DELETE | Clear the strategy cache |
/docs |
GET | Interactive API documentation (Swagger UI) |
Edit config.json to customize:
default_board- Starting board cardsdefault_iterations- Training iterations per solvemax_iterations- Safety limit (default: 1,000,000)log_level- DEBUG, INFO, WARNING, ERROR, CRITICALapi_port- Server port (default: 8000)cors_origins- Allowed CORS originspot_sizes- Customizable pot values by game node
Check logs:
tail -f logs/poker_solver_*.logInvalid inputs will return clear error messages:
# Duplicate cards
curl "http://localhost:8000/train?board=As+As+2s+3s+4s"
# Returns: {"detail": "Invalid board: Duplicate card 'As' in board"}
# Too many iterations
curl "http://localhost:8000/train?iters=2000000"
# Returns: {"detail": "Invalid iterations: Iterations must not exceed 1,000,000"}Verify caching is working:
# First call (trains)
curl "http://localhost:8000/train?board=Ks+Th+7s+4d+2s"
# Response includes: "cached": false
# Second call (loads from cache - should be instant)
curl "http://localhost:8000/train?board=Ks+Th+7s+4d+2s"
# Response includes: "cached": true- ✅ All inputs are validated before processing
- ✅ Meaningful error messages for debugging
- ✅ Comprehensive logging to file and console
- ✅ Strategy caching for performance
- ✅ Configuration-driven (no code changes needed for settings)
- ✅ Type hints and documentation for all code
- ✅ 100% backward compatible with existing applications
Built as an open-source improvement on existing lightweight river solvers, focusing on architectural modularity and vectorization speedups.