|
rng/ is the load-bearing primitive for simulation determinism
(ARCHITECTURE.md §26). All gameplay randomness routes through
createRNG; Math.random is forbidden in gameplay code by ESLint.
rng/derive.ts xmur3 string hash + deriveSeed(parentSeed, label),
stable across processes and runs
rng/seeded.ts SeededRNG interface, mulberry32 implementation,
next / nextInt / nextBool / pick / weightedPick / sub
rng/index.ts public re-exports
Sub-RNG derivation is the key technical move: seeding a child with
hash(parent_seed + label) lets NPCs' trajectories be regenerated
deterministically from their identity tuple alone — which is how
Tier 3 NPCs stay off-disk until the player needs them.
29 determinism tests in tests/determinism/rng.test.ts cover: same
seed → same sequence, sub-RNG independence from parent consumption,
sub-order matters, input validation, and a byte-level inline
snapshot that locks the PRNG output for seed "hollowdark". The
snapshot is load-bearing — if mulberry32 or xmur3 changes, every
existing save diverges, so treat a snapshot break as a migration
concern, not an update-the-snapshot fix.
|