/** * @module prng */ import * as binary from '../binary.mjs' import { fromCharCode, fromCodePoint } from '../string.mjs' import { MAX_SAFE_INTEGER, MIN_SAFE_INTEGER } from '../number.mjs' import * as math from '../math.mjs' import { Xoroshiro128plus as DefaultPRNG } from './PRNG/Xoroshiro128plus.mjs' /** * Description of the function * @callback generatorNext * @return {number} A 32bit integer */ /** * A random type generator. * * @typedef {Object} PRNG * @property {generatorNext} next Generate new number */ /** * Create a Xoroshiro128plus Pseudo-Random-Number-Generator. * This is the fastest full-period generator passing BigCrush without systematic failures. * But there are more PRNGs available in ./PRNG/. * * @param {number} seed A positive 32bit integer. Do not use negative numbers. * @return {PRNG} */ export const createPRNG = seed => new DefaultPRNG(Math.floor(seed < 1 ? seed * binary.BITS32 : seed)) /** * Generates a single random bool. * * @param {PRNG} gen A random number generator. * @return {Boolean} A random boolean */ export const bool = gen => (gen.next() & 2) === 2 // brackets are non-optional! /** * Generates a random integer with 53 bit resolution. * * @param {PRNG} gen A random number generator. * @param {Number} [min = MIN_SAFE_INTEGER] The lower bound of the allowed return values (inclusive). * @param {Number} [max = MAX_SAFE_INTEGER] The upper bound of the allowed return values (inclusive). * @return {Number} A random integer on [min, max] */ export const int53 = (gen, min = MIN_SAFE_INTEGER, max = MAX_SAFE_INTEGER) => math.floor(real53(gen) * (max + 1 - min) + min) /** * Generates a random integer with 32 bit resolution. * * @param {PRNG} gen A random number generator. * @param {Number} [min = MIN_SAFE_INTEGER] The lower bound of the allowed return values (inclusive). * @param {Number} [max = MAX_SAFE_INTEGER] The upper bound of the allowed return values (inclusive). * @return {Number} A random integer on [min, max] */ export const int32 = (gen, min = MIN_SAFE_INTEGER, max = MAX_SAFE_INTEGER) => min + ((gen.next() >>> 0) % (max + 1 - min)) /** * Generates a random real on [0, 1) with 32 bit resolution. * * @param {PRNG} gen A random number generator. * @return {Number} A random real number on [0, 1). */ export const real32 = gen => (gen.next() >>> 0) / binary.BITS32 /** * Generates a random real on [0, 1) with 53 bit resolution. * * @param {PRNG} gen A random number generator. * @return {Number} A random real number on [0, 1). */ export const real53 = gen => (((gen.next() >>> 5) * binary.BIT26) + (gen.next() >>> 6)) / MAX_SAFE_INTEGER /** * Generates a random character from char code 32 - 126. I.e. Characters, Numbers, special characters, and Space: * * (Space)!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[/]^_`abcdefghijklmnopqrstuvwxyz{|}~ */ export const char = gen => fromCharCode(int32(gen, 32, 126)) /** * @param {PRNG} gen * @return {string} A single letter (a-z) */ export const letter = gen => fromCharCode(int32(gen, 97, 122)) /** * @param {PRNG} gen * @return {string} A random word without spaces consisting of letters (a-z) */ export const word = gen => { const len = int32(gen, 0, 20) let str = '' for (let i = 0; i < len; i++) { str += letter(gen) } return str } /** * TODO: this function produces invalid runes. Does not cover all of utf16!! */ export const utf16Rune = gen => { const codepoint = int32(gen, 0, 256) return fromCodePoint(codepoint) } /** * @param {PRNG} gen * @param {number} [maxlen = 20] */ export const utf16String = (gen, maxlen = 20) => { const len = int32(gen, 0, maxlen) let str = '' for (let i = 0; i < len; i++) { str += utf16Rune(gen) } return str } /** * Returns one element of a given array. * * @param {PRNG} gen A random number generator. * @param {Array} array Non empty Array of possible values. * @return {T} One of the values of the supplied Array. * @template T */ export const oneOf = (gen, array) => array[int32(gen, 0, array.length - 1)]