/** 再現可能な乱数 (mulberry32)。リプレイ／デバッグのためシード管理する。 */
export class Rng {
  private s: number;

  constructor(seed: number) {
    this.s = seed >>> 0;
  }

  /** 内部状態を復元してインスタンスを作る (セーブデータ用)。 */
  static fromState(rawState: number): Rng {
    const r = new Rng(0);
    r.s = rawState >>> 0;
    return r;
  }

  /** 内部状態を取り出す (セーブデータ用)。 */
  exportState(): number {
    return this.s;
  }

  next(): number {
    this.s = (this.s + 0x6d2b79f5) >>> 0;
    let t = this.s;
    t = Math.imul(t ^ (t >>> 15), t | 1);
    t ^= t + Math.imul(t ^ (t >>> 7), t | 61);
    return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
  }

  /** min以上max未満の実数 */
  range(min: number, max: number): number {
    return min + this.next() * (max - min);
  }

  /** min以上max以下の整数 */
  int(min: number, max: number): number {
    return Math.floor(this.range(min, max + 1));
  }

  /** 確率pでtrue */
  chance(p: number): boolean {
    return this.next() < p;
  }

  pick<T>(arr: readonly T[]): T {
    return arr[Math.floor(this.next() * arr.length)];
  }
}
