/randy

node.js module inspired by Python's module "random".

Primary LanguageJavaScript

Randy.js

Randy is a utility module inspired by Python's standard module "random".

By default it bases all its functions on Math.random(), but this can be overridden.

Quick Examples

> randy.randInt(100)
42

> randy.shuffle(["J spades", "K hearts", "10 hearts"]);
[ "K hearts", "J spades", "10 hearts" ]

> randy.choice("heads", "tails")
"heads"

Documentation

Module Functions

Module Initialization (optional)

Another PRNG than Math.random() can be supplied during initialization, resulting in a version of the module where all the functions are based on that PRNG instead.

The given PRNG must take no parameters and return a floating point number in the range 0.0 inclusive to 1.0 exclusive.

> var dilbertRng = function () { return 0.9; };
> var randy = require("randy")(dilbertRng);
> randy.random();
0.9
> randy.random();
0.9
> randy.random();
0.9

Module Functions

### randInt ([min], max)

Returns a random integer i such that min < i < max.

Arguments

  • min - default=0. Returned integer will be min or greater.
  • max - Returned integer will be less than max.

Example

console.log("Rolling the dice:");
var d1 = randy.randInt(1, 7);
var d2 = randy.randInt(1, 7);
console.log(d1 + " + " + d2 + " = " + (d1 + d2));
if (d1 + d2 == 2)
    console.log("Snake eyes!");

### choice (arr)

Returns a randomly chosen element from the array arr.

Throws an exception if arr is empty.

Arguments

  • arr - Array of elements of any type. Length > 0. Return value will be an element of arr.

Example

var breakfast = random.choice(["whisky", "bacon", "panic"]);
console.log("Good morning!  Enjoy some " + breakfast + "!");

// Set direction vector for a ghost from Pac-Man.
ghost.currentDirection = random.choice([
    {x:0, y:-1}, {x:1, y:0}, {x:0, y:1}, {x:-1, y:0}
]);

### shuffle (arr)

Returns a shuffled copy of arr. Returned array contains the exact same elements as arr, and equally many elements, but in a new order.

Uses the Fisher-Yates algorithm, aka the Knuth Shuffle.

Arguments

  • arr - Array of elements of any type.

Example

var runners = ["Andy", "Bob", "Clarence", "David"];
var startingOrder = randy.shuffle(runners);

### shuffleInplace (arr)

Shuffles the array arr. A more memory-efficient version of shuffle.

Uses the Fisher-Yates algorithm, aka the Knuth Shuffle.

Arguments

  • arr - Array of elements of any type. Will be modified.

Example

// Reorder elements at random until they happen to be sorted.
def bogosort (arr) {
    while (true) {
        randy.shuffleInplace(arr);

        var sorted = true;
        for (var i=0; i<arr.length-1; i++)
            sorted = sorted && (arr[i] < arr[i+1]);
        if (sorted)
            return;
    }
}

// Create new draw deck from card discard pile.
if (deck.length == 0) {
    deck = discardPile.splice(0);
    randy.shuffle(deck);
}

### sample (population, count)

Returns an array of length count, containing unique elements chosen from the array population. Like a raffle draw.

Mathematically equivalent to shuffle(population).slice(0, count), but more efficient. Catches fire if count > population.length.

Arguments

  • population - Array of elements of any type.
  • count - How many elements to pick from array population.

Example

// Raffle draw for 3 bottles of wine.  Cindy has bought 2 tickets.
var raffleTickets = ["Alice", "Beatrice", "Cindy", "Cindy", "Donna"];

var winners = randy.sample(raffleTickets, 3);

console.log("The winners are: " + winners.join(", "));

### uniform ([min], max)

Returns a floating point number n, such that min <= n < max.

Arguments

  • min - Default=0.0. Returned value will be equal to or larger than this.
  • max - Returned value will be less than this.

Example

// Torpedo guidance system.
var heading = randy.uniform(360.0);

// Random event repeating every 1-5 minutes.
function flashLightning () {
    flash();
    var delayNext = randy.uniform(60.0, 300.0);
    setTimeout(flashLightning, delayNexy);
}

### random ()

Returns a floating point number n such that 0.0 <= n < 1.0.

Goes directly to the underlying PRNG. By default this is the Math.random() function. Supplied for convenience.

Example

var opacity = randy.random();

### triangular ([min], [max], [mode])

The triangular distribution is typically used as a subjective description of a population for which there is only limited sample data, and especially in cases where the relationship between variables is known but data is scarce (possibly because of the high cost of collection). It is based on a knowledge of the minimum and maximum and an "inspired guess" as to the modal value.

Wikipedia article

Arguments

  • min - Default=0.0. Returned value will be equal to or larger than this.
  • max - Default=1.0. Returned value will be less than this.
  • mode - Default is average of min and max. Returned values are likely to be close to this value.

Example

// Generate customer test data.  Customers are aged 18 to 40, but
// most of them are in their twenties.  Their income is between
// 40000-150000 Hyrulean Rupees per year, but typically around
// 60000.
for (i=0; i<1000; i++) {
    db.insertCustomer({
        name: "Bruce",
        birthYear: Math.floor( randy.triangular(1972, 1990, 1983) ),
        income: randy.triangular(40000, 150000, 60000)
    });
}

Future

Math.random() is implementation-dependent and frequently crappy. Even the V8 engine's decent PRNG is insufficient for many tasks as it has a period of 2^32, making it mathematically impossible to generate all permutations of a deck of cards larger than 12 cards.

I'm hoping to implement the Mersenne twister as default PRNG for this module, as it has a period of 2^19937 − 1. Also, working directly with random bits makes the integer based random functions simpler.

Notes

Due to floating point rounding, returned values may extremely rarely tangent the upper bound. The integer based random functions are guarded against this, but there is no good way to do this for floating point values.