atriusmaps-node-sdk
Version:
This project provides an API to Atrius Personal Wayfinder maps within a Node environment. See the README.md for more information
125 lines (109 loc) • 4.17 kB
JavaScript
;
// Simple seedable random number generator - NOT cryptographicaly secure!
function mulberry32 (seed) {
return function () {
let t = seed += 0x6D2B79F5;
t = Math.imul(t ^ (t >>> 15), t | 1);
t ^= t + Math.imul(t ^ (t >>> 7), t | 61);
return ((t ^ (t >>> 14)) >>> 0) / 4294967296
}
}
// ONLY use this for making tests deterministic - otherwise its a bad practice
const isCypress = typeof window !== 'undefined' && window.Cypress;
const random = isCypress ? mulberry32(12345678) : Math.random;
/**
* Returns a random integer between the min and max values. Can also
* be called with a single value which becomes the max and min is set to 0.
* @param {integer} min minimum integer value to return (inclusive)
* @param {integer} max maximum integer value to return (exclusive)
* @returns random integer between min and max.
*/
const rand = (min, max) => {
if (max == null) {
max = min;
min = 0;
}
return Math.floor(random() * (max - min) + min)
};
/**
* Returns a random list of length `size` with unique integers from 0 to `max` - 1.
*
* No number will repeat. If `size > max`, it is clamped to `max`.
* If `max` is not provided, it defaults to `size`, resulting in a random shuffle of [0..size-1].
*
* This is useful for randomly selecting a subset of indices or shuffling a range.
*
* For example:
* randomSet(3, 5) → [3, 2, 0]
* randomSet(5) → [1, 4, 0, 3, 2] // full shuffle of 0..4
*
* @param {number} size - Number of unique values to return
* @param {number} [max] - Range upper bound (exclusive); defaults to `size`
* @returns {number[]} An array of unique random integers from 0 to max-1
*/
function randomSet (size, max) {
if (!max) max = size;
if (size > max) size = max;
const result = [];
// Threshold for choosing sparse vs dense algorithm
// If we're selecting less than 30% of the range, collisions are rare
const SPARSITY_THRESHOLD = 0.3;
const isSparse = (size / max) < SPARSITY_THRESHOLD;
if (isSparse) {
// Sparse strategy: randomly generate values and skip duplicates
// Fast when the number of needed values is small relative to the range
const seen = new Set();
while (result.length < size) {
const i = rand(max);
if (!seen.has(i)) {
seen.add(i);
result.push(i);
}
}
} else {
// Dense strategy: partial in-place Fisher-Yates shuffle
// More efficient when selecting a large portion of the range
const source = Array.from({ length: max }, (_, i) => i);
for (let i = 0; i < size; i++) {
// Select a random index in the shrinking source array
const index = rand(max - i);
// Add the selected value to the result
result.push(source[index]);
// Move the last unchosen item into the chosen spot to "remove" it
source[index] = source[max - i - 1];
}
}
return result
}
/**
* Given a source array and an array of indices, return a new array
* containing the source elements at the specified indices.
*
* @param {Array} array - The source array
* @param {number[]} map - Array of indices to pull from the source
* @returns {Array} - Mapped array
*/
const getMappedArray = (array, map) => map.map(i => array[i]);
/**
* Returns a new array containing the elements of the input array in random order.
* Original array is not modified.
*
* @param {Array} array - The array to shuffle
* @returns {Array} - A new randomized array
*/
const randomizeArray = array => getMappedArray(array, randomSet(array.length));
/**
* Returns a random selection of `num` elements from the array, in random order.
* Original array is not modified. If `num` is not specified, returns a single random item.
* If `num > array.length`, it is clamped to the array length.
*
* @param {Array} array - The array to sample from
* @param {number} [num=1] - Number of items to pick
* @returns {Array} - Randomly selected items
*/
const arrayPick = (array, num = 1) =>
getMappedArray(array, randomSet(num, array.length));
exports.arrayPick = arrayPick;
exports.rand = rand;
exports.randomSet = randomSet;
exports.randomizeArray = randomizeArray;