/* ===================================================================== 아바타 v3 엔진 전용 시드 난수 — mulberry32. 엔진은 순수 함수여야 하므로(결정문 §3) Math.random을 직접 쓰지 않고 이 모듈이 주입하는 rng를 통해서만 난수를 소비한다. ===================================================================== */ export interface Rng { /** [0,1) 균등 분포. */ next(): number; /** [a,b) 균등 분포. */ range(a: number, b: number): number; /** 배열에서 균등하게 하나 고른다. */ pick(arr: readonly T[]): T; } export function createRng(seed: number): Rng { let state = seed >>> 0; function next(): number { state = (state + 0x6d2b79f5) | 0; let t = state; t = Math.imul(t ^ (t >>> 15), t | 1); t ^= t + Math.imul(t ^ (t >>> 7), t | 61); return ((t ^ (t >>> 14)) >>> 0) / 4294967296; } return { next, range(a: number, b: number): number { return a + (b - a) * next(); }, pick(arr: readonly T[]): T { const idx = Math.min(arr.length - 1, Math.floor(next() * arr.length)); return arr[idx]; }, }; } /** FNV-1a 32bit 문자열 해시. */ export function hashString(text: string): number { let hash = 0x811c9dc5; for (let i = 0; i < text.length; i++) { hash ^= text.charCodeAt(i); hash = Math.imul(hash, 0x01000193); } return hash >>> 0; }