nrrng_v1
by burki
JavaScript
/**
* Shuffle array in place (Fisher/Yates/Durstenfeld/Knuth)
*
* @param {[*]} a
*/
function shuffleInPlace(a) {
var j, x, i;
for (i = a.length; i > 1; ) {
j = Math.trunc(Math.random() * i); // or Math.floor
x = a[--i];
a[i] = a[j];
a[j] = x;
}
}
function assert(condition, message) {
if (!condition) {
throw new Error(message);
}
}
class Slicer {
/**
* A Slicer subdivides an array [0...n] into disjunct pages,
* each page not containing more than maxPageSize elements.
*
* @param {number} n
* @param {number} maxPageSize
*/
constructor(n, maxPageSize) {
assert(n >= 0, "max:" + n + " is < 0");
assert(maxPageSize > 0, "maxPageSize: " + maxPageSize + " is <= 0");
this.n = n;
this.maxPage = Math.trunc(n / maxPageSize);
}
/**
* Retrieves the given page.
*
* @param {number} page
* @returns {[number]}
*/
getPage(page) {
assert(
0 <= page && page <= this.maxPage,
"page: " + page + " is < 0 or > " + this.maxPage
);
const add = this.maxPage + 1;
let count = Math.trunc((this.n - page) / add) + 1;
const values = [];
for (let i = page; i <= this.n; i += add) {
values.push(i);
--count;
}
assert(count === 0, "mathematics is broken"); // should never happen ;-)
return values;
}
}
class NonRepeatingRandom_v1 {
/**
* Produces non-repeating pseudorandom numbers between 0 and max-1 (incl.).
*
* @param {number} max
* @param {number} maxPageSize
*/
constructor(max, maxPageSize) {
assert(max > 0, "max must be > 0");
assert(
max <= Number.MAX_SAFE_INTEGER,
"max must be <= " +
Number.MAX_SAFE_INTEGER +
" ( = Number.MAX_SAFE_INTEGER)"
);
if (maxPageSize == undefined) {
console.info("setting default maxPageSize = 2");
maxPageSize = 2;
} else {
assert(maxPageSize > 1, "maxPageSize must be > 1");
}
this.slicer = new Slicer(max - 1, maxPageSize);
...