/** * Pseudo random number generator * using the xorshift32 method. */ export class Xorshift32 { /* @type {number} */ initialSeed; /** * State holds a single uint32. * It's useful for staying within modulo 2**32. * * @type {Uint32Array} */ state; /** @param {number} seed */ constructor(seed) { if (seed === undefined) { const maxInt32 = 2 ** 32; seed = Math.floor(Math.random() * (maxInt32 - 1)) + 1; } seed = seed | 0; this.state = Uint32Array.of(seed); } /** @protected Shuffle the internal state. */ shuffle() { this.state[0] ^= this.state[0] << 13; this.state[0] ^= this.state[0] >>> 17; this.state[0] ^= this.state[0] << 5; // We could also do something like this: // x ^= x << 13; // x ^= x >> 17; // x ^= x << 5; // return x; // But we'd have to xor the x with 2^32 after every op, // we get that "for free" by using the uint32array } /** * Get a random number and shuffle the internal state. * @returns {number} a pseudo-random positive integer. */ get() { this.shuffle(); return this.state[0]; } /** @param {number} x @returns {number} a positive integer lower than x */ lowerThan(x) { return this.get() % x; } /** @param {number} x @returns {number} a positive integer lower than or equal to x */ lowerThanOrEqual(x) { return this.get() % (x + 1); } /** * @template T * @param {T[]} arr - The array to pick from. * @returns {T} One element from the array. * @return {} */ randomElement(arr) { if (arr instanceof Set) { arr = [...arr]; } const idx = this.lowerThan(arr.length); return arr[idx]; } /** * @param {...} ... pick random function argument * @returns {} */ oneOf(...args) { const idx = this.lowerThan(args.length); return args[idx]; } /** * @param {number} lowerThanOrEqual a positive integer * @param {number} greaterThanOrEqual a positive integer greater than lowerThanOrEqual * @returns {number} a pseudo-random integer */ within(greaterThanOrEqual, lowerThanOrEqual) { const range = lowerThanOrEqual - greaterThanOrEqual; const num = this.lowerThanOrEqual(range); return num + greaterThanOrEqual; } } const rng = new Xorshift32(); console.log(rng.get());