Game Platforms, RNG, and Testing
So you want to build a game building platform. You're cruising along and your test games have the usual randomness that adds a little spice to your games, usually combat scenarios. Then other things get a random kick. Then another. You ignore the orthogonal nature of randomness because hey, you can just create a new Random() any time and seed it with the DateTime() object.
I went so far to avoid normalizing Sharpee's RNG issues that I designed the testing capability around it.
# Enter troll room
> east
[OK: contains "Troll Room"]
[OK: contains "troll"]
# ===== Melee interceptor combat test =====
# RETRY handles player death from counter-attacks — restores and retries
# DO/UNTIL loops attack until troll death message or player death
# RNG: the troll can disarm us (unarmed attacks are blocked as suicide) or
# knock us out — recover the sword before each swing, and accept the
# disarm/knockout lines ("sword"/"hands"/"unconscious") as attack-turn output.
[RETRY: max=10]
[DO]
[WHILE: not inventory contains "elvish sword"]
> take sword
[SKIP]
[END WHILE]
> attack troll with sword
[OK: contains_any "troll" "staggering" "sword" "hands" "unconscious"]
[UNTIL "slumps to the floor dead" OR "removes his head" OR "He dies" OR "You are dead"]
[ENSURES: not entity "troll" alive]
[END RETRY]At the time (February - ish) I thought this was super clever and expanded these looped gates to "handle" RNG (random number generator) outcomes.
Fast-forward to this past week working on the IDE for Chord and wanting deterministic testing similar to Inform 7's Skein. No bueno.
So I had Claude go through the code to assess the situation. There were RNG entry points in multiple areas including base code and extensions. Double no bueno.
I had run out of my Fable 5 usage for the week so was using Opus 5 and I gotta tell ya the difference is significant. I iterated three ADRs for a day to try to get the changes and the sequence of changes correct and Opus 5 flat out failed and it even admitted it: "I have rewritten whole sections 4x and circled back to the same questions, so I think I need help."
This is the LLM asking ME for help. But I had already anticipated the Opus 5 fiasco and as soon as I got Fable 5 usage back I asked it to look at the problem, purely from code, ignore the Opus 5 research, and ignore Chord (which I mistakenly kept as a seam in the Opus 5 research).
Fable 5 came back with just an assessment. No ADR, no plan. I shared the assessment with Opus 5 and it loved it. We abandon two of the ADRs it had designed and wrote a new ADR. Two follow-ups with Fable 5 landed a completed and well-designed ADR to re-implement randomness in Sharpee that had a testing deterministic entry point that would cross save boundaries.
The implementation is in-progress and this is a very invasive orthogonal change to Sharpee, so it's likely going to be hours of Claude Fable 5 work. Once that's completed and thoroughly tested, the IDE will have its version of a Skein and blessed output with some extra capabilities like "search" where you can say, "Play until Troll dies" or "Play until Thief dies" and then run tests. Anything associated with alternate paths will be testable and the platform will know ahead of time where all of those paths sit because when it inflates the World Model, it builds a Map() of everything. And yes, it handles combinatorial explosion by gating each vortex of multiple outcomes. (The Troll is just dead. We never need to test Troll-Alive -> xxx or Troll-injured -> yyy).
So a little advice from your Uncle Dave. Make randomness a centralized service with a seeded escape hatch for deterministic testing. You'll thank me.