mami/src/mami.js/rng.js

120 lines
3 KiB
JavaScript

// Reimplementation of https://source.dot.net/#System.Private.CoreLib/Random.cs,bb77e610694e64ca
const MamiRNG = function(seed) {
const MBIG = 0x7FFFFFFF;
const MSEED = 161803398;
if((typeof seed).toLowerCase() !== 'number')
seed = Math.round(Date.now() / 1000);
const seedArray = new Int32Array(56);
const vars = new Int32Array(2);
const mjVal = 0, mkVal = 1;
let ii = 0;
vars[mjVal] = seed;
vars[mjVal] = (vars[mjVal] === -0x80000000) ? 0x7FFFFFFF : Math.abs(vars[mjVal]);
vars[mjVal] = MSEED - vars[mjVal];
seedArray[55] = vars[mjVal];
vars[mkVal] = 1;
for(let i = 1; i < 55; i++) {
if((ii += 21) >= 55)
ii -= 55;
seedArray[ii] = vars[mkVal];
vars[mkVal] = vars[mjVal] - vars[mkVal];
if(vars[mkVal] < 0)
vars[mkVal] += MBIG;
vars[mjVal] = seedArray[ii];
}
for(let k = 1; k < 5; k++) {
for(let i = 0; i < 56; i++) {
let n = i + 30;
if(n >= 55)
n -= 55;
seedArray[i] -= seedArray[1 + n];
if(seedArray[i] < 0)
seedArray[i] += MBIG;
}
}
let inext = 0,
inextp = 21;
const internalSample = function() {
const retVal = new Int32Array(1);
let locINext = inext,
locINextp = inextp;
if(++locINext >= 56)
locINext = 1;
if(++locINextp >= 56)
locINextp = 1;
retVal[0] = seedArray[locINext];
retVal[0] -= seedArray[locINextp];
if(retVal[0] == MBIG)
retVal[0]--;
if(retVal[0] < 0)
retVal[0] += MBIG;
seedArray[locINext] = retVal[0];
inext = locINext;
inextp = locINextp;
return retVal[0];
};
const sample = function() {
return internalSample() * (1.0 / MBIG);
};
return {
sample: sample,
next: function(minValue, maxValue) {
let hasMinVal = (typeof minValue).toLowerCase() === 'number',
hasMaxVal = (typeof maxValue).toLowerCase() === 'number';
const vars = new Int32Array(3),
minVal = 0, maxVal = 1, retVal = 2;
if(hasMinVal) {
if(!hasMaxVal) {
hasMinVal = false;
hasMaxVal = true;
vars[maxVal] = minValue;
} else {
vars[minVal] = minValue;
vars[maxVal] = maxValue;
}
}
if(hasMaxVal) {
if(hasMinVal) {
if(vars[minVal] > vars[maxVal])
throw 'Argument out of range.';
const range = vars[maxVal] - vars[minVal];
vars[retVal] = sample() * range;
vars[retVal] += vars[minVal];
return vars[retVal];
}
vars[retVal] = sample() * vars[maxVal];
return vars[retVal];
}
return internalSample();
},
};
};