A rules-first, YAML-driven Craps simulator built for accurate accounting, clear audits, and repeatable strategy analysis.
Model Craps rules, describe strategies in YAML, audit individual rolls, and run complete session studies.
Created by Greg M. Krsak (greg.krsak@gmail.com)
with the GPT-5.5 High setting in ChatGPT Plus.
Universal Craps Engine is a single-file Python simulation engine designed to model casino Craps with explicit wager state, consistent settlement rules, and separate cash and equity accounting.
The engine combines:
- A strict object-oriented Model–View–Controller architecture
- Exact
Decimal-based money accounting - Immutable pre-roll snapshots
- A declarative, event-driven YAML strategy system
- Configurable casino rules
- Deterministic scenario testing
- Reproducible or nondeterministic random simulation
- Embedded unit tests
- Silent, audit, scenario, and Monte Carlo run modes
The same engine can produce a roll-by-roll audit or run thousands of complete sessions, with each wager settled through the same rules.
Important: No betting system changes the mathematical house advantage of a wager. This engine evaluates bankroll behavior and session outcomes under specified rules; it does not predict future dice.
Many Craps simulators begin with a dice loop and add wager rules afterward. Small state or accounting mistakes in that design can skew an entire study.
Universal Craps Engine starts with the accounting and state model:
- Cash is money available in the rack.
- Active stake is money currently reserved on the layout.
- Equity is cash plus active stake.
- Persistent wagers receive profit while their stake remains active.
- One-roll wagers resolve and leave the layout immediately.
- Contract wagers travel and retain their legal state.
- Odds are attached to specific parent contracts.
- Every wager resolves against the same immutable pre-roll table snapshot.
This prevents order-dependent settlements, orphaned odds, accidental double payments, free proposition retries, and the other subtle errors common in homegrown simulations.
The engine supports:
| Family | Wagers |
|---|---|
| Contract wagers | Pass Line, Don't Pass, Come, Don't Come |
| Odds | Take Odds, Lay Odds |
| Box-number wagers | Place, Buy, Lay |
| Even-money layout wagers | Big 6, Big 8 |
| Hardways | Hard 4, Hard 6, Hard 8, Hard 10 |
| One-roll propositions | Any Seven, Any Craps, Aces, Ace-Deuce, Yo, Boxcars |
| Split propositions | Horn, C & E, World / Whirl |
| Combination wagers | Exact unordered Hop combinations |
| Other | Field |
The YAML specification can define:
- Don't Pass / Don't Come bar number: 2 or 12
- Field payout on 2
- Field payout on 12
- Buy-bet vig rate
- Buy-bet vig timing: upfront or on win
- Buy-bet vig basis: wager or win
- Lay-bet vig rate
- Lay-bet vig timing
- Lay-bet vig basis
- Chip denomination
- Exact, floor, or nearest-chip payout rounding
- Per-wager minimums
- Per-wager legal increments
- Full point-specific odds limits
- Come-out working defaults for:
- Place bets
- Buy bets
- Lay bets
- Hardways
- Big 6 and Big 8
- Come odds
- Don't Come odds
Strategies react to table events rather than relying on fragile procedural scripts.
Supported triggers:
session_start
hand_start
before_roll
come_out
after_roll
point_established
point_made
seven_out
bet_win
bet_loss
Supported strategy actions:
place_bet
ensure_bet
take_odds
remove_bets
regress_bets
press_bet
set_working
stop_session
message
Supported conditions include phase, point, roll total, roll interval, hand limits, cash, equity, wager existence, and winning or losing wager type.
flowchart LR
YAML["YAML Configuration"] --> Loader["Strict YAML Loader"]
Loader --> Config["Immutable Engine Configuration"]
Config --> Session["CrapsSession"]
Session --> Strategy["YAML Strategy Controller"]
Session --> Controller["Craps Controller"]
Dice["DiceSource<br/>Random or Scripted"] --> Controller
Strategy --> Controller
Controller --> Resolver["Pure Bet Resolver"]
Controller --> Model["Table Model"]
Model --> Ledger["Bankroll Ledger"]
Model --> Bets["Active Wagers"]
Model --> Rules["Table Rules"]
Controller --> View["View"]
View --> Console["Console Audit"]
View --> Silent["Null View"]
Session --> Result["SessionResult"]
Result --> MonteCarlo["MonteCarloRunner"]
The model contains the table point, phase, hand and roll counters, wagers, rules, ledger, active stake, and equity.
ConsoleView produces a roll-by-roll audit trail. NullView keeps simulations and test runs silent.
CrapsController is the sole authority allowed to mutate table state. It validates wagers, reserves stakes, rolls the dice, applies settlements, moves the puck, manages odds, and emits events.
.
├── universal_craps_engine.py
├── uce_strategy_full_showcase.yaml
├── uce_strategy_100_across_with_hardways.yaml
├── requirements.txt
├── LICENSE
├── .gitignore
├── .github/workflows/tests.yml
└── README.md
| File | Purpose |
|---|---|
universal_craps_engine.py |
Complete engine, CLI, MVC implementation, YAML parser, scenario runner, Monte Carlo runner, and unit suite |
uce_strategy_full_showcase.yaml |
Full-surface reference configuration exercising the YAML specification |
uce_strategy_100_across_with_hardways.yaml |
Practical $100/$120-across strategy with $5 Hardways and regression management |
requirements.txt |
Runtime dependency declaration |
.github/workflows/tests.yml |
Automated tests on Python 3.10–3.12 |
README.md |
Project documentation |
LICENSE |
MIT License |
- Python 3.10 or newer
- PyYAML
No database, web service, or installation of Universal Craps Engine as a Python package is required. PyYAML is the only third-party runtime dependency.
git clone https://github.com/gregkrsak/universal_craps_engine.git
cd universal_craps_engine
python3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install -r requirements.txtOn Windows PowerShell:
.venv\Scripts\Activate.ps1
python -m pip install --upgrade pip
python -m pip install PyYAMLpython universal_craps_engine.py --run-testsExpected result:
Ran 43 tests
OK
python universal_craps_engine.py \
uce_strategy_full_showcase.yaml \
--run-scenariospython universal_craps_engine.py \
uce_strategy_100_across_with_hardways.yaml \
--simulatepython universal_craps_engine.py \
uce_strategy_100_across_with_hardways.yaml \
--auditpython universal_craps_engine.py \
uce_strategy_100_across_with_hardways.yaml \
--monte-carlo 10000The Monte Carlo summary reports:
- Trial count
- Number of target hits
- Target-hit rate
- Mean session net
- Median session net
- Mean rolls per session
usage: universal_craps_engine.py [-h]
[--simulate | --audit |
--run-scenarios |
--monte-carlo TRIALS |
--run-tests]
[strategy]
| Option | Description |
|---|---|
strategy |
Path to a version-1 YAML configuration |
--simulate |
Run one configured session silently and print the final summary |
--audit |
Print every roll, point transition, settlement, cash balance, and equity balance |
--run-scenarios |
Execute all deterministic scenarios embedded in the YAML file |
--monte-carlo TRIALS |
Run the requested number of complete sessions and aggregate results |
--run-tests |
Run the 43-test embedded unit suite |
Every configuration begins with six top-level sections:
version: 1
meta:
name: "Example Strategy"
description: "A concise explanation of the strategy."
session:
bankroll: 1000
target: 1200
stop_loss: 500
max_rolls: 500
max_hands: 100
seed: null
rules:
# Complete table-rule specification
strategy:
actions:
# Event-driven strategy actions
scenarios:
# Optional deterministic executable specificationsThe loader is strict by design. Unknown keys are rejected rather than silently ignored.
Use an integer for reproducible simulations:
seed: 20260709Use null, or omit the key, for fresh nondeterministic random sessions:
seed: nullWith an integer seed, Monte Carlo trials derive distinct deterministic trial seeds while remaining reproducible as a complete run.
strategy:
actions:
- id: maintain_pass_line
trigger: come_out
when:
cash_gte: 25
bet_not_exists:
kind: pass_line
do:
type: ensure_bet
kind: pass_line
amount: 25 - id: place_inside_after_point
trigger: point_established
when:
cash_gte: 240
do:
type: ensure_bet
kind: place
amount: 120
numbers: [6, 8] - id: regress_after_made_point
trigger: point_made
do:
type: regress_bets
kind: place
factor: 0.5
minimums:
4: 15
5: 15
6: 18
8: 18
9: 15
10: 15 - id: press_place_winners
trigger: bet_win
when:
winning_kind: place
do:
type: press_bet
kind: place
profit_fraction: 0.5For the complete schema, use uce_strategy_full_showcase.yaml as the canonical reference.
YAML scenarios function as executable rules documentation.
A scenario can:
- Set the table point
- Place wagers
- Attach odds
- Set working state
- Increase, reduce, remove, regress, or press wagers
- Supply an exact sequence of dice
- Assert final cash
- Assert final equity
- Assert point and phase
- Assert active wager count and wager types
- Assert hand and roll counters
Example:
scenarios:
- name: "Place 6 wins and remains active"
bankroll: 100
setup:
- type: set_point
point: 5
- type: place_bet
kind: place
amount: 12
number: 6
rolls:
- [3, 3]
expected:
cash: 102
equity: 114
point: 5
phase: point_on
active_count: 1
active_by_kind:
place: 1
roll_number: 1These scenarios are ideal for documenting table-rule variations, reproducing bugs, and protecting strategy behavior during refactoring.
The unit suite is embedded in the single Python source file and currently contains 43 passing tests.
Coverage includes:
- Dice validation and seeded reproducibility
- Separation of MVC components
- Pass Line and Don't Pass
- Bar-2 and Bar-12 behavior
- Come and Don't Come travel
- Taking and laying true odds
- Maximum-odds enforcement
- Come-odds working behavior
- Place, Buy, Lay, Big 6, Big 8, and Hardways
- Field payouts
- Every one-roll proposition family
- Correct split-stake Horn and World arithmetic
- Hop payouts
- Buy and Lay vig
- Upfront incremental vig when increasing a wager
- Pressing, reducing, removing, and regressing bets
- Bankroll-equity invariants
- Strict YAML rejection
- Full YAML action-surface coverage
- Deterministic scenario execution
- Monte Carlo aggregation
- Basic PEP 8 whitespace and line-length checks
- Exhaustive 36-combination expectation checks for selected wagers
Run them at any time:
python universal_craps_engine.py --run-testsAll money uses Decimal, never binary floating-point arithmetic.
Every active wager resolves from the same TableSnapshot, so one wager's settlement cannot alter another wager's interpretation of the roll.
Every debit and credit creates a chronological LedgerEntry containing:
- Roll number
- Amount
- Resulting cash balance
- Human-readable memo
Unknown YAML keys fail fast with a ConfigurationError.
The engine accepts either:
RandomDicefor simulationScriptedDicefor deterministic tests and audits
The entire Python implementation—including tests and CLI—lives in one auditable source file without sacrificing internal architectural separation.
uce_strategy_100_across_with_hardways.yaml defines this high-exposure six-number strategy:
| Wager | Amount |
|---|---|
| Pass Line | $25 |
| Place 4 | $100 |
| Place 5 | $100 |
| Place 6 | $120 |
| Place 8 | $120 |
| Place 9 | $100 |
| Place 10 | $100 |
| Hard 4 | $5 |
| Hard 6 | $5 |
| Hard 8 | $5 |
| Hard 10 | $5 |
The strategy:
- Builds the Place layout after a point is established
- Keeps persistent wagers active after wins
- Regresses Place wagers by half every fifth qualifying point-on roll
- Regresses after a made point
- Enforces configured regression floors
- Replaces Hardways after easy-way losses
- Rebuilds the intended layout for a new shooter
- Leaves Place bets and Hardways off during come-out rolls by default
In this strategy, “$100 across” means $100 on 4, 5, 9, and 10, with payout-clean $120 units on 6 and 8. The total Place exposure is $640.
Common extension points include:
- Add a new
BetKind. - Add its pure settlement method to
BetResolver. - Add minimum and increment rules to YAML.
- Add strategy parser support only when the wager needs new syntax.
- Add deterministic tests for every winning, losing, pushing, traveling, and off-state path.
- Add an exhaustive probability test when practical.
The architecture intentionally keeps wager settlement separate from strategy decisions, making extensions easier to review.
Potential future enhancements:
- Parallel Monte Carlo execution
- JSON and CSV session exports
- Per-wager win/loss and handle statistics
- Drawdown and risk-of-ruin analysis
- Confidence intervals
- Side-by-side strategy comparison
- Strategy parameter sweeps
- Session replay files
- Rich terminal tables and charts
- A lightweight desktop or web interface
- Additional regional and casino-specific rule presets
Created by Greg M. Krsak (greg.krsak@gmail.com) and the GPT-5.5 High setting in ChatGPT Plus.
The project should be reviewed like any other software contribution: through tests, code review, and verification against the applicable casino rules.
Craps is a negative-expectation casino game under standard rules. A strategy can change volatility, exposure, drawdown, session duration, and the probability of reaching a chosen target, but it cannot make independent fair dice remember prior outcomes.
Use the engine to understand rules and quantify risk—not to mistake a favorable simulation run for a predictive advantage.
Built to make every chip accountable.