Each series is a best-of-7. Games are simulated possession by possession from each player's best-three-season averages on Basketball Reference — not a coin flip on overall ratings. Player overall is used for draft salary and lineup building only; it is never read during the sim.
Game structure
Regulation runs 200 total possessions (both teams combined), mapped to a 48-minute clock. Team box-score minutes always sum to 240 in regulation (five players × 48 minutes), scaling up in overtime. Each shot, turnover, or free-throw trip counts as one possession toward that budget.
If the score is tied after 200 possessions, the game continues in overtime (extra possessions until someone leads). A series ends when one side reaches four wins (maximum seven games). Each game uses a deterministic seed derived from the series seed.
On every possession, both teams may substitute, then all ten on-court players accumulate wear. Offensive rebounds keep the ball but still burn another possession — so glass teams get more shot attempts inside the same game length.
Player ratings
Stats come from each player's three best seasons (by production), averaged. From those inputs the engine builds per-game ratings:
Offense = pts×1.0 + ast×1.4 + ts_pct×8 (true shooting falls back to FG% when missing).
Defense = stl×2.2 + blk×2.0 + drb×0.35 + orb×0.15. Team defense on a possession is the average of the five defenders on the floor.
Usage decides who shoots — weighted random on usg_pct, or max(fga, pts, 4) when usage is missing.
Three-point rate = fg3a / fga, clamped to [0.02, 0.60]. Position defaults when attempt data is thin: PG/SG 38%, SF 32%, PF 18%, C 8%.
Turnover rate = tov / (fga + 0.44×fta + tov), clamped to [0.04, 0.28].
Free-throw draw rate = fta / (fga + fta), clamped to [0.05, 0.45].
Shooting clamps — 2P% [0.28, 0.72], 3P% [0.15, 0.50], FT% [0.40, 0.95].
Rebound splits use career ORB/DRB when available. Otherwise ORB share by position: C 38%, PF 34%, SF 27%, SG 22%, PG 18% of total rebounds.
Lineup shape
The sim does not read draft slots during play — only who is on the floor and their position tags (parsed from Basketball Reference strings).
Each on-court player is counted as perimeter if their position includes PG, SG, or SF; as a big if they include PF or C without a guard/wing tag. Dual-position wings (e.g. SF/PF) count as perimeter only, not both.
From those headcounts the engine derives three scores each possession:
- spacing (offense) — from perimeter count:
fitScore = min(perimeter / 2, 1). Two or more guards/wings = 1.0; one = 0.5; zero = 0.0. - paintD (defense) — from big count, same formula. Protects the rim on opponent twos.
- periD (defense) — from perimeter count. Affects opponent three-point volume and accuracy.
Offensive bigs do not directly help spacing; only perimeter bodies on offense open the floor.
Spacing penalties (offense)
Penalties scale linearly between 0 and 0.5 spacing and hit zero at full spacing (1.0):
- Turnovers:
max(0, 0.08 − 0.10×spacing)— +8% at spacing 0, +3% at 0.5. - 2P make:
max(0, 0.14 − 0.18×spacing)— −14% at 0, −5% at 0.5. - 3P make:
max(0, 0.06 − 0.08×spacing)— −6% at 0, −2% at 0.5. - 3P attempt rate:
shooter.threeRate × (0.6 + 0.4×spacing)— ×0.6 at 0, ×0.8 at 0.5, ×1.0 at full spacing. - Assist chance:
0.25 + 0.40×spacing— 25% clogged vs 65% balanced.
Mono-big offenses (spacing 0) pay heavily in turnovers and interior misses. Mono-guard defenses (paintD 0) give up +10% on opponent two-pointers ((1 − paintD) × 0.10).
Examples
- Balanced (PG, SG, SF, PF, C): spacing 1.0, paintD 1.0 when this five defends.
- All centers on offense: spacing 0 — full spacing penalties; no perimeter creation.
- All guards on defense: paintD 0 — opponent twos get +10%; periD 1.0 on the perimeter.
- One guard + four centers: spacing 0.5 — half the spacing penalties above.
In balance tests, balanced lineups beat mono-position stacks. All-guard lineups now edge all-center lineups despite center rebounding edges, because clogged spacing costs more than glass gains.
Possession flow
Each possession picks a shooter (by usage), optional passer (assist chance × passer AST), and defender (by defense rating). Resolution order:
1. Defensive foul — see Fouls below. 2. Turnover — base rate + fatigue + spacing + defense mismatch + short-handed penalty. 3. Offensive foul draw → free throws (ftaRate × 0.35; 25% chance of three attempts). 4. Field goal — three vs two from adjusted three-rate; block check; make check. 5. Miss → rebound contest; offensive rebound retains the ball.
Make chance = base shooting % plus (shooter.offense − teamDefense) × 0.0075, minus spacing and fatigue penalties, plus soft paint/perimeter defense bonuses for the offense, minus short-handed penalties. Clamped to [0.12, 0.78].
Blocks: clamp(0.03 + blk×0.025, 0.02, 0.12) per shot. After blocks, defensive rebound weight is ×2.4 (vs ×1.25 on normal misses).
Turnover → steal credited: 45% of live-ball turnovers.
Short-handed (fewer than five on court): +2.5% TOV per missing player, −4% make per missing player on offense; +3.5% make for opponent per missing defender.
Rebounding
On misses and blocks, the five on-court players contest the ball:
- Team weights:
sum(ORB)^1.2vssum(DRB)^1.2(minimum 0.05 per side). - Individual rebounder:
ORB^1.35orDRB^1.35weighted pick.
Glass changes how many shots a team gets within the 200-possession budget, not just box-score counting stats.
Fatigue
Every possession on the floor adds wear: 0.0012 + usage × 0.00008. Fatigue does not reset on the bench — sitting only stops it from rising.
Penalties apply to the shooter on that possession:
- Make penalty:
min(0.30, fatigue × 0.25) - Turnover boost:
min(0.24, fatigue × 0.20)
Fatigue at common minute marks (no substitutions)
Examples assume a starter who never leaves the floor and plays every team possession. Box minutes map to on-court ticks at 48 min = 200 possessions (full regulation share).
| Minutes | Player | Fatigue | Make penalty | TOV boost |
|---|---|---|---|---|
| 10 | High usage (35% USG) | 0.17 | −4.2% | +3.3% |
| 10 | Role player (15% USG) | 0.10 | −2.5% | +2.0% |
| 20 | High usage (35% USG) | 0.33 | −8.3% | +6.7% |
| 20 | Role player (15% USG) | 0.20 | −5.0% | +4.0% |
| 30 | High usage (35% USG) | 0.50 | −12.5% | +10.0% |
| 30 | Role player (15% USG) | 0.30 | −7.5% | +6.0% |
| 40 | High usage (35% USG) | 0.67 | −16.7% | +13.3% |
| 40 | Role player (15% USG) | 0.40 | −10.0% | +8.0% |
Wear per possession is 0.0012 + USG × 0.00008, so the star accumulates fatigue about 67% faster than the role player at the same minutes. In real games, substitutions limit exposure — see below.
Substitutions
Subs run at the start of every possession for both teams. There is no position matching — any eligible bench player can replace any on-court player.
Forced: players with 6 fouls must leave (out for the rest of the game). If no bench is available, the team plays short-handed.
Foul trouble / fatigue: first player with 5+ fouls or fatigue > 0.6 is targeted after possession 30 (or 35% random chance earlier). Incoming player weighted by offense + defense + (1−fatigue)×5; swap only if meaningfully fresher (0.08 fatigue gap) or the starter has 5 fouls.
Light rotation: after possession 50, 8% chance per possession to sub the most tired player if a bench player is at least 0.05 less fatigued. Bench weight: offense + defense + (1−fatigue)×4.
Fouls
Foul rate uses career PF/G when scraped:
clamp(0.05 + pf×0.072, 0.055, 0.33) per possession when that defender is selected.
Fallback when PF is missing: clamp(0.055 + stl×0.038 + blk×0.028, 0.05, 0.30).
40% of fouls become free throws (2 attempts); 60% are dead-ball fouls that end the possession without FTs. Box scores show PF per player; 6 fouls displays in red.
Starters, bench, and draft
You choose five starters before the series; everyone else starts on the bench. Draft uses overall-based salary (floor $6M, shared cap) and max roster size 12. After the draft, salary no longer applies — trades only respect roster size.
Finals MVP
Chosen from the winning team only. Stats from series wins count ×1.12 toward the internal MVP score.
Weights: PTS ×1.0, REB ×1.2, AST ×1.55, STL ×2.6, BLK ×2.1, 3PM ×0.4, +/- ×0.5, minus TOV ×1.15, missed FG ×0.3, missed FT ×0.2.
What we test
Automated balance runs (hundreds of games on fixed rosters) check that: better teams win more often; balanced fives beat mono-position stacks; high-rebound teams get more boards and possessions; turnover and shooting stats propagate; deeper benches survive foul trouble and fatigue better than thin five-man rosters; identical rosters stay near 50/50 with no seat bias.