No-Bust 21st Century Blackjack — Monte Carlo + CDZ⁻ Solver

Simulation
Game Theory

A multi-process Python simulator with a Tkinter GUI for the California card-room variant No Bust 21st Century Blackjack. Built around exact composition-dependent (CDZ⁻) strategy solving plus Numba-JIT’d hand play. Includes the “no-bust comparison” rule, surrender at any decision point, split-aces special handling, DAS, and the buster side bet.

Published

March 25, 2026

In plain English

California has weird gambling laws. To get around the prohibition on banked house games, casinos invented variants of blackjack with twisted rules — the most famous of which is No Bust 21st Century Blackjack. It’s blackjack, but several rules are different in ways that look small and turn out to matter a lot.

The biggest change: busting (going over 21) doesn’t always lose. If both you and the dealer bust, the one closer to 21 wins; if you’re closer, you actually push (get your bet back) instead of losing. That single rule shift means hitting on a hand that would normally be a clear stand can suddenly be correct, because busting carries an option value that doesn’t exist in standard blackjack. Other tweaks — surrender legal at any decision point, special rules after splitting aces, an unusual dealer-bust side bet — pile on top.

If you walk into a California card room and play with the basic strategy you learned from a Vegas chart, you’re playing the wrong game. The chart is wrong. The right strategy depends not just on your hand and the dealer’s up-card but on the exact composition of cards left in the shoe (the technical term is CDZ⁻, “composition-dependent zero-memory”), and no published blackjack table covers this rule set.

I built two things: a Tkinter GUI Monte Carlo simulator that plays out millions of hands with multi-process workers, and a CDZ⁻ exact solver that derives the EV-optimal action for any (hand, dealer up-card, deck composition) combination by full subtree expansion. Together they let you see whether a given configuration of bet, deck count, penetration, and side-bet inclusion is actually +EV, in this game, and what the optimal play looks like at every decision point.

The game (rules)

  • No-bust comparison rule (the namesake): when both player and dealer bust, dealer-closer-to-21 wins, player-closer-to-21 pushes (player saves the bet), tied → dealer wins. So busting isn’t terminal in the usual sense.
  • Surrender legal at any decision point — initial 2-card, mid-hand after any number of hits, on split sub-hands, after split-and-hit. Costs half the bet. Not legal after doubling, not on a post-split-aces sub-hand.
  • Split aces special rule: each post-split-aces sub-hand receives exactly one draw card, then stands. If that draw card is also an ace and max_splits not reached and the chart action is “split,” the sub-hand is re-split.
  • Configurable max_splits (default 3 → up to 4 sub-hands; set to 1 for double-deck).
  • Double-after-split (DAS) hardcoded on for non-ace splits.
  • Buster side bet: pays on dealer-bust by card-count (3–4 cards 2:1, 5 cards 4:1, 6 cards 16:1, 7 cards 50:1, 8+ cards 200:1).

These rule shifts make stock blackjack basic strategy wrong, sometimes by several EV percentage points per hand. The simulator’s reason to exist is solving the right strategy for this game.

What it does

  • CDZ⁻ exact solver: composition-dependent strategy solving — for each (player hand composition, dealer up-card, deck composition), compute the EV-optimal action (hit / stand / double / split / surrender) by full subtree expansion. CDZ⁻ means we account for what’s left in the shoe but stand-on-the-current-hand-only (no peek at future cards).
  • Numba-JIT’d hand play for the simulation loop. Hand-by-hand replay through the solved chart at simulator throughput, not interpreter throughput.
  • Multi-process Monte Carlo with a configurable number of workers — each plays a fresh shoe, results aggregated for variance estimation.
  • Tkinter GUI for live experimentation: configure rules, deck count, bet sizing, splits, DAS, surrender, buster bet — see EV per hand, hourly EV at a chosen pace, ROR for given bankrolls.

Implementation notes

  • 8-deck shoe default, configurable down to 2-deck (forces max_splits = 1 to match house rules).
  • Penetration handling: shoe reshuffled at configurable penetration depth; the solver re-derives the chart at the post-penetration composition.
  • Surrender logic: separate code path because surrender’s legality interacts with double, split-aces, and the no-bust rule in non-obvious ways. Edge cases verified against published CDZ tables for non-California variants then extended.
  • Buster bet EV: computed analytically per dealer up-card from the conditional bust-card-count distribution. Exposed in the GUI alongside the main-bet EV so a player can see whether the side bet is +EV or −EV in their chosen composition.
  • One-click launchers (run_sim.bat / run_sim.sh) that auto-install dependencies on first run — the simulator ships to non-developer testers as a working binary, not a setup project.

Why this is worth doing

The standard published blackjack tables are wrong for this game. The no-bust rule alone changes the optimal stand-vs-hit threshold for stiff hands against high dealer cards, because busting carries a saved-bet option value. Surrender-at-any-decision-point creates a continuation-value calculation that doesn’t exist in standard rule sets. And the buster bet is a side-game with composition-sensitive EV that the casino doesn’t post.

Solving this isn’t a paper exercise — it’s the difference between playing the game at +EV (with proper composition-dependent strategy and selective buster betting in penetrated shoes) vs. the −EV outcome of stock-rule basic strategy.

Stack

  • Python 3.10+ — numpy, numba, matplotlib
  • Tkinter for the live GUI
  • Multi-process worker pool for Monte Carlo
  • Full memo (nobust21_sim.md) covering rules, GUI, every variable, and the variable/function index — written so a non-developer card-room player can use it

What it demonstrates

  • Composition-dependent solving from scratch (no off-the-shelf for this rule set)
  • Multi-process Monte Carlo with seedable RNG per worker
  • Numba JIT compilation of the inner play loop with measured speedup over pure Python
  • A shippable end-user tool (one-click launcher, GUI) — not just a research notebook