2025-12-19 05:19:22 +00:00
|
|
|
/**
|
|
|
|
|
* 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);
|
2025-12-17 19:26:42 +00:00
|
|
|
}
|
2025-12-19 05:19:22 +00:00
|
|
|
}
|
2025-12-17 19:26:42 +00:00
|
|
|
|
2025-12-19 05:19:22 +00:00
|
|
|
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);
|
2025-12-17 19:26:42 +00:00
|
|
|
}
|
|
|
|
|
|
2025-12-19 05:19:22 +00:00
|
|
|
// 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;
|
|
|
|
|
}
|
|
|
|
|
}
|