/**
* Детерминированный ГПСЧ (mulberry32) — генераторы моделей и мир зависят
* только от сида, не от порядка вызовов за его пределами. Чистая математика.
*/
export class Rng {
private state: number;
constructor(seed: number) {
if (!Number.isInteger(seed) || seed < 0) {
throw new Error(`Rng: сид должен быть неотрицательным целым, дано ${seed}`);
}
this.state = seed >>> 0;
}
/** [0, 2^32) как беззнаковое целое. */
nextUint(): number {
this.state = (this.state + 0x6d2b79f5) >>> 0;
let t = this.state;
t = Math.imul(t ^ (t >>> 15), t | 1);
t ^= t + Math.imul(t ^ (t >>> 7), t | 61);
return ((t ^ (t >>> 14)) >>> 0);
}
/** [0, 1). */
next(): number {
return this.nextUint() / 4294967296;
}
/** Целое в [0, n). */
int(n: number): number {
return Math.floor(this.next() * n);
}
/** Целое в [min, max] включительно. */
range(min: number, max: number): number {
return min + this.int(max - min + 1);
}
/** Логический выбор с вероятностью p. */
chance(p: number): boolean {
return this.next() < p;
}
/** Выбор случайного элемента массива. */
pick<T>(items: readonly T[]): T {
return items[this.int(items.length)];
}
}