SALZ is equity-based. Each decision runs on three mechanisms.

Equity estimate. It computes its probability of winning the hand by Monte Carlo: deal out the unknown cards many times, score each with the evaluator, count the wins. That probability is then priced against the pot. Call when equity beats the pot odds, raise when it is well ahead, fold otherwise.

Best-of-k opponent model. The usual bot estimates equity against a random hand, which overvalues your holding the moment an opponent bets, because a betting opponent no longer holds a random hand. SALZ instead estimates equity against the best of k candidate hands. The max of k random hands sits near the top of the range, so k is a tightness dial: k=1 is a random opponent, higher k is a stronger range.

Live k inference. k is set from the opponent’s own betting. The more often they bet a given size, the wider that range is, so k falls; a player who rarely bets is modeled as stronger, so k rises. A confirmed over-bettor is pinned to k=1, since a maniac’s bets carry no information.

Around this sits the game-specific calibration: preflop logic tuned to Short Deck’s compressed equities and inverted rankings, and sample counts paced against the time bank so the bot never runs its clock empty.

The Zoo is our opponent field for testing. It works on three mechanisms.

Composition. It holds a spread of opponent bots grouped into families: generated bots covering common styles, basic and broken bots, exam bots written to resemble real competition entries, and an exploiter. Each family carries a weight reflecting how much it matters to the real tournament.

The train/held-out split. We tune only against the generated and basic families. The exam and exploiter families are held out: the tuner never sees them. A change has to improve the weighted score on the training families and hold up on the held-out ones. If it gains on training but not held-out, it is overfitting, and we drop it. This split is what lets us trust an improvement instead of hoping for it.

The arena. Every match runs through an in-process harness that calls the official judge’s own logic directly, so results match the tournament exactly while running far faster. Matches use the duplicate format, both bots play the same deals with seats swapped, which cancels most of the card luck and lets us read a real edge from a modest sample.

overall training summary: Matches Hands fastarena field and swarm runs 31,111 18.1 M Overnight optimizer (estimated from its log) 13,523 5.4 M tune.py runs and sweeps 1,821 2.8 M Databricks exports (every decision recorded) 3,339 1.7 M Replays and stress tests ~175 0.2 M Total ~50,000 ~28 M

Built With

  • agent
  • backtesting
  • bluff-detection
  • confidence-intervals
  • databricks
  • docker
  • equity-calculation
  • expected-value
  • fastapi
  • game-theory
  • heads-up
  • monte-carlo
  • numpy
  • opponent-modeling
  • parameter-tuning
  • poker
  • poker-bot
  • pot-limit-omaha
  • pot-odds
  • python
  • range-modeling
  • short-deck
  • simulation
  • statistical-significance
  • uvicorn
Share this project:

Updates

Submission history