# DEEPFALL — Simulation Findings What the balance-by-bot rig actually said, after 9 tuning iterations over ~thousands of seeded games per sweep. This is the honest post-mortem: what the design got right, what the sim broke, what I fixed, and what's still open. The deliverable was never "a perfectly balanced game." It was: **design a mashup, then let a simulator tell me the truth about it.** It did. --- ## 1. The headline Final config (`configs/default.json`), 2000 seeds × 24 seat-permutations per strategy sweep, 2000 games per combo: | Metric | Result | Verdict | |---|---|---| | **Game length** | 10.9 rounds (10–11) | ✅ in the 8–14 target band; the Maw ends it cleanly, every time | | **Victory margin** | 13.7% of winner's score | ✅ tight — **no runaway leader** | | **Feel-bad rate** (Taken w/o Last Stand) | **0.00 / game** | ✅ the one true feel-bad is fully designed out | | **Deep content reachability** | only **6.5%** of deep-floor claims by round-1 parties | ✅ the deep game is *not* decided at game start | | **Combo spread** (best − worst of 36) | **32.5 pts** (8.1%–40.6%) | 🟡 every combo viable; still a soft Lineage/Calling tilt | | **Strategy band** | WorthyEnd 46.7 / PressOn 25.8 / Balanced 24.8 / CashOut 2.8 | 🟡 aggression is the strongest line; pure passivity is weak | Three of the design's central promises held up under simulation — **no runaway, no elimination feel-bad, and a living deep game**. Two things stayed stubborn — the draft has a soft power tilt, and the four play-styles aren't a flat band. Both are understood (below), not mysterious. --- ## 2. The three biggest things the sim caught (and the fixes) ### A. Value and time were correlated → the arc fizzled and the back half ran away Room glory was `base × depth` and the Maw eats deepest-first, so the richest rooms scored *earliest*; the game crescendo'd in the middle and ended on its cheapest floors, and the Worthy-End catch-up valve closed once the deep floors were gone. Both critics flagged it before a line of code ran. **Fix (the single best rule in the game):** on collapse, a fraction of each room's *unclaimed* value **rises to the floor above** as "refugee plunder." The Maw's frontier is now always the swelling hot zone, all the way to Floor 1. The data confirms it: the claim distribution is **non-monotonic** — Floor 4 (162k claims) draws *more* than Floor 3 (96k), because value pools wherever the frontier sits, and Floor 1 draws the most of all as everyone converges for the finale. The endgame crescendos instead of fizzling, and margins stayed tight (13.7%). ### B. The deep game was nearly a game-start-only contest A fresh party from the Cash-Out loop entered at Floor 1 and physically could not reach the deep live floor before it collapsed (the balance critic walked the move-math). So the Decline loop would have fed you parties that could only farm shallow rooms. **Fix:** re-entering parties insert at `max(1, frontier − 1)`. Result: only **6.5%** of deep-floor claims come from round-1 parties — i.e. **93.5% of the deep game is played by later-drafted crews.** The Decline loop stays relevant the whole game. ### C. The multi-collapse feel-bad `while accum ≥ 1.0` could eat two floors in one round late-game and Take a "flee next turn" party with no Last Stand. **Fix:** cap one collapse per round (carry the remainder). The feel-bad rate is a flat **0.00** across every config tested since. --- ## 3. The balance-by-bot trajectory Each row is a tuning pass; the simulator drove every decision. Regressions are left in on purpose — they're the method working (a change that *looked* good and the data vetoed). | Iter | Lever changed | Combo spread | Weakest combo | WorthyEnd / CashOut strat | |---|---|---:|---:|---| | 1 | initial design | 77.8 | 0.5% | 41.6 / 1.8 | | 2 | sub-linear depth; neuter `ignore_threat`; mixed combo field | 59.8 | — | 44.8 / 0.0 | | 3 | Champion-recruit Wardancer; Cautious plays the frontier | 46.5 | — | 44.8 / 3.1 | | 4 | half-strength Fallen markers | **56.2** ⚠ | — | 44.0 / 3.5 | | 5 | revert Fallen; cap marker overflow; raise dividend | 47.2 | — | 37.0 / 5.0 | | 6 | bots compare worthy-vs-bank payouts | **55.5** ⚠ | — | 38.5 / 4.2 | | 7 | Wardancer +1 marker strength; revert dividend | 43.4 | 4.9% | 46.1 / 2.8 | | 8 | Dvergar −1 Cunning; Wisp gets a Warrior | 35.9 | 5.0% | 45.4 / 2.8 | | 9 | Dvergar −1 Faith (gentler); trim Reaver | **32.5** | **8.1%** | 46.7 / 2.8 | Net: combo spread **−58%** (77.8 → 32.5), weakest combo **×16** (0.5% → 8.1%), and the dead cells (Sylphid ~1%, Wardancer ~0.3%) all revived into the playable band. The two ⚠ regressions taught real lessons: half-strength Fallen markers (iter 4) handed Warden's ×2 markers an immortal hold and spiked it to 56%; and making bots *compare* exit payouts (iter 6) — correct in itself — exposed that Wardancer's whole value was a rare conditional, which is what forced the iter-7 fix. --- ## 4. Final combo heatmap (focal combo as Balanced vs. a mixed random field) ``` Reaver Lorekeeper Wardancer Hierophant Warden Prospector Dvergar 40.6% 33.7% 18.4% 32.5% 30.9% 31.6% Wisp 20.6% 15.9% 11.9% 14.5% 14.4% 14.2% Revenant 17.3% 13.9% 8.9% 12.2% 12.7% 11.7% Gnoll 31.7% 28.7% 9.6% 23.9% 24.4% 24.8% Sylphid 23.3% 18.8% 12.4% 15.0% 15.3% 14.6% GolemBorn24.9% 20.4% 8.1% 19.6% 19.1% 32.0% Lineage avg : Dvergar 31.2 Gnoll 23.9 GolemBorn 20.7 Sylphid 16.6 Wisp 15.3 Revenant 12.8 Calling avg : Reaver 26.4 Lorekeeper 21.9 Prospector 21.5 Hierophant 19.6 Warden 19.5 Wardancer 11.6 ``` (Mean focal win-rate sits below 25% because the focal always plays the generalist Balanced bot while the field includes the more aggressive WorthyEnd/PressOn strategies — so read the *vs-mean* column in `combo_winrates.csv`, not the raw 25% line.) --- ## 5. What's still open (and why) ### The Cash-Out vs. Worthy-End substitution (the deepest finding) The strategy band stays lopsided (WorthyEnd 46.7%, CashOut 2.8%) for a structural reason the sim made undeniable: **for a glory-maximizing agent, Cash-Out and Worthy-End are substitutes** — both convert a doomed party into points. So *every* lever that helps the safe banker (e.g. the depth dividend) directly nerfs the martyr, and vice-versa. They sat on a trade-off frontier across iterations 5–10: I could balance the *strategies* or the *Wardancer calling*, but not both with the same `worthy_factor`. The intended differentiator — Worthy-End's **denial** (the Maw salts your held rooms so no rival inherits them) — is real in the rules but **invisible to the bots**, because a win-rate maximizer doesn't model the opponent's loss, and you mostly salt rooms you were soloing anyway. *This is the headline design lesson:* the two exits only become a true triangle (not a binary) when denial is made to **matter to your own score** — e.g. score denial explicitly (gain a cut of the value you deny), or make Worthy-End pay on *cumulative* depth dived across the whole game (rewarding a play-pattern banking can't copy). That's the first thing I'd prototype next. ### The soft draft tilt Dvergar (threat-reduction is just broadly useful) and Reaver (loot-on-claim is a flywheel) sit on top; Revenant and Wardancer sit low. No combo is dead (worst is 8.1%), so the draft is *spicy, not solved* — acceptable for a Small-World-style game where some combos are stronger — but a shipping version would want Dvergar's hook costed harder and Revenant's Dread-to-Mettle made to actually pay. ### Pacing variance is too tight Game length is 10–11 rounds with almost no spread. Real push-your-luck wants more variance in *when* the Maw breaks through. The `maw_dread_push` and `press_dread_push` knobs are the levers; I'd widen them and accept a 9–14 spread. --- ## 6. Reproduce ```bash cd deepfall cargo test # 11 tests: determinism, pacing, no-double-count cargo run --release -p deepfall-sim -- --out out --seeds 2000 python3 analysis/analyze.py out # the heatmap above, no dependencies ``` Every number here is a pure function of `(configs/default.json, seed)` — same input, same output, on any machine.