/** * SeededRandom.js * A deterministic pseudo-random number generator using Mulberry32. * Essential for reproducible procedural generation. */ export class SeededRandom { constructor(seed) { // Hash the string seed to a number if necessary if (typeof seed === "string") { this.state = this.hashString(seed); } else { this.state = seed || Math.floor(Math.random() * 2147483647); } } hashString(str) { let hash = 1779033703 ^ str.length; for (let i = 0; i < str.length; i++) { hash = Math.imul(hash ^ str.charCodeAt(i), 3432918353); hash = (hash << 13) | (hash >>> 19); } // Perform the final mixing immediately and return the result hash = Math.imul(hash ^ (hash >>> 16), 2246822507); hash = Math.imul(hash ^ (hash >>> 13), 3266489909); return hash >>> 0; } // Mulberry32 Algorithm next() { let t = (this.state += 0x6d2b79f5); t = Math.imul(t ^ (t >>> 15), t | 1); t ^= t + Math.imul(t ^ (t >>> 7), t | 61); return ((t ^ (t >>> 14)) >>> 0) / 4294967296; } // Returns float between [min, max) range(min, max) { return min + this.next() * (max - min); } // Returns integer between [min, max] (inclusive) rangeInt(min, max) { return Math.floor(this.range(min, max + 1)); } // Returns true/false based on probability (0.0 - 1.0) chance(probability) { return this.next() < probability; } }