47 lines
1.5 KiB
JavaScript
47 lines
1.5 KiB
JavaScript
// PROCITY core PRNG — the only randomness source in generation code (CITY_SPEC law).
|
|
// Same citySeed ⇒ byte-identical city. Math.random() is banned outside cosmetic-only FX.
|
|
|
|
export function xmur3(str) {
|
|
let h = 1779033703 ^ str.length;
|
|
for (let i = 0; i < str.length; i++) {
|
|
h = Math.imul(h ^ str.charCodeAt(i), 3432918353);
|
|
h = (h << 13) | (h >>> 19);
|
|
}
|
|
return function () {
|
|
h = Math.imul(h ^ (h >>> 16), 2246822507);
|
|
h = Math.imul(h ^ (h >>> 13), 3266489909);
|
|
return (h ^= h >>> 16) >>> 0;
|
|
};
|
|
}
|
|
|
|
export function mulberry32(a) {
|
|
return function () {
|
|
a |= 0; a = (a + 0x6D2B79F5) | 0;
|
|
let t = Math.imul(a ^ (a >>> 15), 1 | a);
|
|
t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;
|
|
return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
|
|
};
|
|
}
|
|
|
|
// Stable uint32 for an entity: seedFor(citySeed, 'shop', 42)
|
|
export function seedFor(citySeed, kind, id) {
|
|
return xmur3(`${citySeed}:${kind}:${id}`)();
|
|
}
|
|
|
|
// Seeded stream for an entity: const r = rng(citySeed,'shop',42); r() → [0,1)
|
|
export function rng(citySeed, kind, id) {
|
|
return mulberry32(seedFor(citySeed, kind, id));
|
|
}
|
|
|
|
// Helpers over a stream r
|
|
export const pick = (r, arr) => arr[(r() * arr.length) | 0];
|
|
export const irange = (r, lo, hi) => lo + ((r() * (hi - lo + 1)) | 0); // inclusive ints
|
|
export const frange = (r, lo, hi) => lo + r() * (hi - lo);
|
|
export function shuffle(r, arr) { // in-place Fisher-Yates
|
|
for (let i = arr.length - 1; i > 0; i--) {
|
|
const j = (r() * (i + 1)) | 0;
|
|
[arr[i], arr[j]] = [arr[j], arr[i]];
|
|
}
|
|
return arr;
|
|
}
|