UNPKG

boardgame.io

Version:
110 lines (97 loc) 2.88 kB
// Inlined version of Alea from https://github.com/davidbau/seedrandom. // Converted to Typescript October 2020. /* * Copyright 2015 David Bau. * * Permission is hereby granted, free of charge, * to any person obtaining a copy of this software * and associated documentation files (the "Software"), * to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the * Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall * be included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ export interface AleaState { c: number; s0: number; s1: number; s2: number; } class Alea { c: number; s0: number; s1: number; s2: number; constructor(seed: string | number) { const mash = Mash(); // Apply the seeding algorithm from Baagoe. this.c = 1; this.s0 = mash(' '); this.s1 = mash(' '); this.s2 = mash(' '); this.s0 -= mash(seed); if (this.s0 < 0) { this.s0 += 1; } this.s1 -= mash(seed); if (this.s1 < 0) { this.s1 += 1; } this.s2 -= mash(seed); if (this.s2 < 0) { this.s2 += 1; } } next() { const t = 2091639 * this.s0 + this.c * 2.3283064365386963e-10; // 2^-32 this.s0 = this.s1; this.s1 = this.s2; return (this.s2 = t - (this.c = Math.trunc(t))); } } function Mash() { let n = 0xefc8249d; const mash = function (data: string | number) { const str = data.toString(); for (let i = 0; i < str.length; i++) { n += str.charCodeAt(i); let h = 0.02519603282416938 * n; n = h >>> 0; h -= n; h *= n; n = h >>> 0; h -= n; n += h * 0x100000000; // 2^32 } return (n >>> 0) * 2.3283064365386963e-10; // 2^-32 }; return mash; } function copy(f: AleaState, t: Partial<AleaState>) { t.c = f.c; t.s0 = f.s0; t.s1 = f.s1; t.s2 = f.s2; return t as AleaState; } type PRNG = Alea['next'] & { state?: () => AleaState }; export function alea(seed: string | number, state?: AleaState): PRNG { const xg = new Alea(seed); const prng = xg.next.bind(xg) as PRNG; if (state) copy(state, xg); prng.state = () => copy(xg, {}); return prng; }