prando
Version:
Deterministic pseudo-random number generator for JavaScript and TypeScript
174 lines (172 loc) • 7.59 kB
JavaScript
var Prando = /** @class */ (function () {
// ================================================================================================================
// CONSTRUCTOR ----------------------------------------------------------------------------------------------------
/**
* Generate a new Prando pseudo-random number generator.
*
* @param seed - A number or string seed that determines which pseudo-random number sequence will be created. Defaults to a random seed based on `Math.random()`.
*/
function Prando(seed) {
this._value = NaN;
if (typeof seed === "string") {
// String seed
this._seed = this.hashCode(seed);
}
else if (typeof seed === "number") {
// Numeric seed
this._seed = this.getSafeSeed(seed);
}
else {
// Pseudo-random seed
this._seed = this.getSafeSeed(Prando.MIN + Math.floor((Prando.MAX - Prando.MIN) * Math.random()));
}
this.reset();
}
// ================================================================================================================
// PUBLIC INTERFACE -----------------------------------------------------------------------------------------------
/**
* Generates a pseudo-random number between a lower (inclusive) and a higher (exclusive) bounds.
*
* @param min - The minimum number that can be randomly generated.
* @param pseudoMax - The maximum number that can be randomly generated (exclusive).
* @return The generated pseudo-random number.
*/
Prando.prototype.next = function (min, pseudoMax) {
if (min === void 0) { min = 0; }
if (pseudoMax === void 0) { pseudoMax = 1; }
this.recalculate();
return this.map(this._value, Prando.MIN, Prando.MAX, min, pseudoMax);
};
/**
* Generates a pseudo-random integer number in a range (inclusive).
*
* @param min - The minimum number that can be randomly generated.
* @param max - The maximum number that can be randomly generated.
* @return The generated pseudo-random number.
*/
Prando.prototype.nextInt = function (min, max) {
if (min === void 0) { min = 10; }
if (max === void 0) { max = 100; }
this.recalculate();
return Math.floor(this.map(this._value, Prando.MIN, Prando.MAX, min, max + 1));
};
/**
* Generates a pseudo-random string sequence of a particular length from a specific character range.
*
* Note: keep in mind that creating a random string sequence does not guarantee uniqueness; there is always a
* 1 in (char_length^string_length) chance of collision. For real unique string ids, always check for
* pre-existing ids, or employ a robust GUID/UUID generator.
*
* @param length - Length of the string to be generated.
* @param chars - Characters that are used when creating the random string. Defaults to all alphanumeric chars (A-Z, a-z, 0-9).
* @return The generated string sequence.
*/
Prando.prototype.nextString = function (length, chars) {
if (length === void 0) { length = 16; }
if (chars === void 0) { chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; }
var str = "";
while (str.length < length) {
str += this.nextChar(chars);
}
return str;
};
/**
* Generates a pseudo-random string of 1 character specific character range.
*
* @param chars - Characters that are used when creating the random string. Defaults to all alphanumeric chars (A-Z, a-z, 0-9).
* @return The generated character.
*/
Prando.prototype.nextChar = function (chars) {
if (chars === void 0) { chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; }
return chars.substr(this.nextInt(0, chars.length - 1), 1);
};
/**
* Picks a pseudo-random item from an array. The array is left unmodified.
*
* Note: keep in mind that while the returned item will be random enough, picking one item from the array at a time
* does not guarantee nor imply that a sequence of random non-repeating items will be picked. If you want to
* *pick items in a random order* from an array, instead of *pick one random item from an array*, it's best to
* apply a *shuffle* transformation to the array instead, then read it linearly.
*
* @param array - Array of any type containing one or more candidates for random picking.
* @return An item from the array.
*/
Prando.prototype.nextArrayItem = function (array) {
return array[this.nextInt(0, array.length - 1)];
};
/**
* Generates a pseudo-random boolean.
*
* @return A value of true or false.
*/
Prando.prototype.nextBoolean = function () {
this.recalculate();
return this._value > 0.5;
};
/**
* Skips ahead in the sequence of numbers that are being generated. This is equivalent to
* calling next() a specified number of times, but faster since it doesn't need to map the
* new random numbers to a range and return it.
*
* @param iterations - The number of items to skip ahead.
*/
Prando.prototype.skip = function (iterations) {
if (iterations === void 0) { iterations = 1; }
while (iterations-- > 0) {
this.recalculate();
}
};
/**
* Reset the pseudo-random number sequence back to its starting seed. Further calls to next()
* will then produce the same sequence of numbers it had produced before. This is equivalent to
* creating a new Prando instance with the same seed as another Prando instance.
*
* Example:
* let rng = new Prando(12345678);
* console.log(rng.next()); // 0.6177754114889017
* console.log(rng.next()); // 0.5784605181725837
* rng.reset();
* console.log(rng.next()); // 0.6177754114889017 again
* console.log(rng.next()); // 0.5784605181725837 again
*/
Prando.prototype.reset = function () {
this._value = this._seed;
};
// ================================================================================================================
// PRIVATE INTERFACE ----------------------------------------------------------------------------------------------
Prando.prototype.recalculate = function () {
this._value = this.xorshift(this._value);
};
Prando.prototype.xorshift = function (value) {
// Xorshift*32
// Based on George Marsaglia's work: http://www.jstatsoft.org/v08/i14/paper
value ^= value << 13;
value ^= value >> 17;
value ^= value << 5;
return value;
};
Prando.prototype.map = function (val, minFrom, maxFrom, minTo, maxTo) {
return ((val - minFrom) / (maxFrom - minFrom)) * (maxTo - minTo) + minTo;
};
Prando.prototype.hashCode = function (str) {
var hash = 0;
if (str) {
var l = str.length;
for (var i = 0; i < l; i++) {
hash = (hash << 5) - hash + str.charCodeAt(i);
hash |= 0;
hash = this.xorshift(hash);
}
}
return this.getSafeSeed(hash);
};
Prando.prototype.getSafeSeed = function (seed) {
if (seed === 0)
return 1;
return seed;
};
Prando.MIN = -2147483648; // Int32 min
Prando.MAX = 2147483647; // Int32 max
return Prando;
}());
export default Prando;