You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
134 lines
3.0 KiB
134 lines
3.0 KiB
4 years ago
|
import { Math_random } from "./builtins";
|
||
|
|
||
|
// ALEA RNG
|
||
|
|
||
|
function Mash() {
|
||
|
var n = 0xefc8249d;
|
||
|
return function (data) {
|
||
|
data = data.toString();
|
||
|
for (var i = 0; i < data.length; i++) {
|
||
|
n += data.charCodeAt(i);
|
||
|
var 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
|
||
|
};
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param {number|string} seed
|
||
|
*/
|
||
|
function makeNewRng(seed) {
|
||
|
// Johannes Baagøe <baagoe@baagoe.com>, 2010
|
||
|
var c = 1;
|
||
|
var mash = Mash();
|
||
|
let s0 = mash(" ");
|
||
|
let s1 = mash(" ");
|
||
|
let s2 = mash(" ");
|
||
|
|
||
|
s0 -= mash(seed);
|
||
|
if (s0 < 0) {
|
||
|
s0 += 1;
|
||
|
}
|
||
|
s1 -= mash(seed);
|
||
|
if (s1 < 0) {
|
||
|
s1 += 1;
|
||
|
}
|
||
|
s2 -= mash(seed);
|
||
|
if (s2 < 0) {
|
||
|
s2 += 1;
|
||
|
}
|
||
|
mash = null;
|
||
|
|
||
|
var random = function () {
|
||
|
var t = 2091639 * s0 + c * 2.3283064365386963e-10; // 2^-32
|
||
|
s0 = s1;
|
||
|
s1 = s2;
|
||
|
return (s2 = t - (c = t | 0));
|
||
|
};
|
||
|
|
||
|
random.exportState = function () {
|
||
|
return [s0, s1, s2, c];
|
||
|
};
|
||
|
|
||
|
random.importState = function (i) {
|
||
|
s0 = +i[0] || 0;
|
||
|
s1 = +i[1] || 0;
|
||
|
s2 = +i[2] || 0;
|
||
|
c = +i[3] || 0;
|
||
|
};
|
||
|
|
||
|
return random;
|
||
|
}
|
||
|
|
||
|
export class RandomNumberGenerator {
|
||
|
/**
|
||
|
*
|
||
|
* @param {number|string=} seed
|
||
|
*/
|
||
|
constructor(seed) {
|
||
|
this.internalRng = makeNewRng(seed || Math_random());
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Re-seeds the generator
|
||
|
* @param {number|string} seed
|
||
|
*/
|
||
|
reseed(seed) {
|
||
|
this.internalRng = makeNewRng(seed || Math_random());
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @returns {number} between 0 and 1
|
||
|
*/
|
||
|
next() {
|
||
|
return this.internalRng();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param {number} min
|
||
|
* @param {number} max
|
||
|
* @returns {number} Integer in range [min, max[
|
||
|
*/
|
||
|
nextIntRange(min, max) {
|
||
|
assert(Number.isFinite(min), "Minimum is no integer");
|
||
|
assert(Number.isFinite(max), "Maximum is no integer");
|
||
|
assert(max > min, "rng: max <= min");
|
||
|
return Math.floor(this.next() * (max - min) + min);
|
||
|
}
|
||
|
/**
|
||
|
* @param {number} min
|
||
|
* @param {number} max
|
||
|
* @returns {number} Integer in range [min, max]
|
||
|
*/
|
||
|
nextIntRangeInclusive(min, max) {
|
||
|
assert(Number.isFinite(min), "Minimum is no integer");
|
||
|
assert(Number.isFinite(max), "Maximum is no integer");
|
||
|
assert(max > min, "rng: max <= min");
|
||
|
return Math.round(this.next() * (max - min) + min);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param {number} min
|
||
|
* @param {number} max
|
||
|
* @returns {number} Number in range [min, max[
|
||
|
*/
|
||
|
nextRange(min, max) {
|
||
|
assert(max > min, "rng: max <= min");
|
||
|
return this.next() * (max - min) + min;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Updates the seed
|
||
|
* @param {number} seed
|
||
|
*/
|
||
|
setSeed(seed) {
|
||
|
this.internalRng = makeNewRng(seed);
|
||
|
}
|
||
|
}
|