/* ============================================================ rng.js — deterministic seeding & sampling Every stochastic decision in the generator draws from a salted sub-stream so that changing one parameter does not reshuffle unrelated parts of the scene. ============================================================ */ /* cyrb53 — fast 53-bit string hash. Stable across runs/machines. */ export function cyrb53(str, seed = 0) { let h1 = 0xdeadbeef ^ seed, h2 = 0x41c6ce57 ^ seed; for (let i = 0; i < str.length; i++) { const ch = str.charCodeAt(i); h1 = Math.imul(h1 ^ ch, 2654435761); h2 = Math.imul(h2 ^ ch, 1597334677); } h1 = Math.imul(h1 ^ (h1 >>> 16), 2246822507) ^ Math.imul(h2 ^ (h2 >>> 13), 3266489909); h2 = Math.imul(h2 ^ (h2 >>> 16), 2246822507) ^ Math.imul(h1 ^ (h1 >>> 13), 3266489909); return (4294967296 * (2097151 & h2) + (h1 >>> 0)).toString(16).padStart(13, '0'); } /* mulberry32 — tiny fast PRNG, returns [0,1). */ export function mulberry32(seed) { let a = seed >>> 0; return function () { a = (a + 0x6D2B79F5) >>> 0; let t = a; t = Math.imul(t ^ (t >>> 15), t | 1); t ^= t + Math.imul(t ^ (t >>> 7), t | 61); return ((t ^ (t >>> 14)) >>> 0) / 4294967296; }; } /* makeRng — seed string + salt → independent PRNG stream. */ export function makeRng(seedStr, salt = '') { const h = cyrb53(seedStr + '::' + salt); return mulberry32(parseInt(h.slice(0, 8), 16)); } /* ---------- Distributions ---------- */ /* Standard normal via Box-Muller. */ export function gauss(rng) { const u = 1 - rng(), v = rng(); return Math.sqrt(-2 * Math.log(u)) * Math.cos(2 * Math.PI * v); } /* Log-normal — heavy-tailed positive sample. */ export function logNormal(rng, mu, sigma) { return Math.exp(mu + sigma * gauss(rng)); } /* Uniform in [lo, hi). */ export function range(rng, lo, hi) { return lo + (hi - lo) * rng(); } /* Random int in [lo, hi]. */ export function randInt(rng, lo, hi) { return lo + Math.floor(rng() * (hi - lo + 1)); } /* Pick one element. */ export function pick(rng, arr) { return arr[Math.floor(rng() * arr.length)]; } /* Bernoulli. */ export function chance(rng, p) { return rng() < p; }