120 lines
3 KiB
JavaScript
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();
|
||
|
},
|
||
|
};
|
||
|
};
|