nrrng_v2

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_v2 {
  /**
   * Produces non-repeating pseudorandom numbers between 0 and max-1 (incl.).
   *
   * @param {number} max
   */
  constructor(max, maxPageSizes) {
    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 (maxPageSizes && maxPageSizes.length) {
      assert(
        maxPageSizes.length === 2,
        "2 maxPageSizes are needed in this demo"
      );
      assert(
        maxPageSizes.every((maxPageSize) => maxPageSize > 1),
        "each maxPageSize must be > 1"
     ...