DEEPFALL: a tabletop game mashing up 9 loved games (SmashUp, Dragon Rampage, Blood Rage, Catan, EverQuest, Daggerfall, Eye of the Beholder, Quarriors, SmallWorld). Core fusion = SmallWorld decline + Blood Rage glorious death -> three exits (Cash Out / Press On / Worthy End) under a rising Maw that collapses a reikhelm dungeon floor-by-floor. - deepfall-core: pure deterministic engine (vendored ChaCha8, 11 tests) - deepfall-sim: balance-by-bot sweeps -> CSV/JSON - analysis/analyze.py: stdlib ASCII heatmap (no deps) - DESIGN.md (rules + post-critique revisions), FINDINGS.md (9-iteration balance journey), README.md - reikhelm-core/examples/sample_dungeon.rs: dumps a real generated board Method: adversarial design critics -> build -> simulate -> tune. 9 iterations compressed combo spread 77.8 -> 32.5 pts (all 36 combos viable). Fixed deep-content lockout (value rises with the Maw), the multi-collapse feel-bad (1 collapse/round cap; feel-bad now 0.00/game), and dead combos. Open finding: Cash-Out and Worthy-End are substitutes for a glory-maximizing bot. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
157 lines
8.3 KiB
Markdown
157 lines
8.3 KiB
Markdown
# 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.
|