/**
 * The sim's only source of randomness. mulberry32: small, fast, fully seedable.
 * Nothing in the sim may call Math.random() or read the clock — same seed plus the
 * same command sequence must reproduce the same world forever.
 */

export interface Rng {
  /** float in [0, 1) */
  next(): number;
  /** integer in [0, maxExclusive) */
  int(maxExclusive: number): number;
  /** current internal state, for save() */
  state(): number;
  /** restore a state() value, for load() */
  restore(state: number): void;
}

export function makeRng(seed: number): Rng {
  let a = seed >>> 0;
  const next = (): number => {
    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;
  };
  return {
    next,
    int: (maxExclusive: number) => Math.floor(next() * maxExclusive),
    state: () => a,
    restore: (state: number) => { a = state >>> 0; },
  };
}
