Basic interface required for Rng implementations.

Use this as an interface if you don't need all the advanced distributions

interface RngInterface {
    bin(val: number, bins: number, min: number, max: number): number;
    boxMuller(options?: {
        mean?: number;
        stddev?: number;
    }): number;
    boxMuller(mean?: number, stddev?: number): number;
    chance(n: number, chanceIn?: number): boolean;
    chanceTo(from: number, to: number): boolean;
    chancy(input: ChancyNumeric): number;
    chancy<T>(input: T[]): T;
    chancyInt(input: Chancy): number;
    chancyMax(input: Chancy): number;
    chancyMin(input: Chancy): number;
    choice<T>(array: T[]): null | T;
    clamp(number: number, lower: number, upper: number): number;
    dice(dice: string): number;
    dice(options: Partial<DiceInterface>): number;
    dice(options: number[]): number;
    dice(n: number, d?: number, plus?: number): number;
    diceExpanded(dice: string): DiceReturnInterface;
    diceExpanded(options: Partial<DiceInterface>): DiceReturnInterface;
    diceExpanded(dice: number[]): DiceReturnInterface;
    diceExpanded(n: number, d: number, plus: number): DiceReturnInterface;
    diceMax(n: string | number | DiceInterface, d?: number, plus?: number): number;
    diceMin(n: string | number | DiceInterface, d?: number, plus?: number): number;
    gaussian(options?: {
        mean?: number;
        skew?: number;
        stddev?: number;
    }): number;
    getSeed(): number;
    normal(options?: {
        max?: number;
        mean?: number;
        min?: number;
        skew?: number;
        stddev?: number;
    }, depth?: number): number;
    parseDiceString(string: string): DiceInterface;
    percentage(): number;
    pool<T>(entries?: T[]): Pool<T>;
    predictable(): RngInterface;
    predictable(seed: Seed): RngInterface;
    probability(): number;
    randBetween(): number;
    randBetween(from?: number): number;
    randBetween(from?: number, to?: number): number;
    randBetween(from: number, to: number, skew: number): number;
    randInt(): number;
    randInt(from?: number, to?: number): number;
    randInt(from?: number, to?: number, skew?: number): number;
    random(from?: number, to?: number, skew?: number): number;
    randomSource(func?: Randfunc): this;
    randomString(len?: number): string;
    sameAs(other: RngInterface): boolean;
    scale(number: number, from: number, to: number, min?: number, max?: number): number;
    scaleNorm(number: number, from: number, to: number): number;
    seed(seed: Seed): this;
    serialize(): any;
    shouldThrowOnMaxRecursionsReached(): boolean;
    shouldThrowOnMaxRecursionsReached(val: boolean): this;
    shuffle<T>(array: T[]): T[];
    support(input: Distribution): undefined | string;
    uniqid(prefix?: string): string;
    weightedChoice(data: any[] | Map<any, number> | Record<any, number>): any;
    weights(data: any[]): Map<any, number>;
}

Implemented by

Methods

  • Returns a Pool with the given entries based on this RNG.

    Pools allow you to draw (without replacement) from them.

    Type Parameters

    • T

    Parameters

    • Optionalentries: T[]

      An array of anything

    Returns Pool<T>

    const pool = rng.pool(['a', 'b', 'c', 'd']);

    pool.draw(); // 'b'
    pool.draw(); // 'c'
    pool.draw(); // 'a'
    pool.draw(); // 'd'
    pool.draw(); // PoolEmptyError('No more elements left to draw from in pool.')
  • Whether this is the same as another object interfacting RngInterface, i.e. they will generate the same next number.

    Parameters

    Returns boolean

  • Whether we are going to throw if max recursions is reached

    Returns boolean

  • Sets whether we should throw if max recursions is reached.

    Parameters

    • val: boolean

    Returns this

  • Outputs what the distribution supports in terms of output

    Parameters

    Returns undefined | string

Boolean Results

  • Results of an "n" in "chanceIn" chance of something happening.

    Parameters

    • n: number

      Numerator

    • OptionalchanceIn: number

      Denominator

    Returns boolean

    Success or not

    A "1 in 10" chance would be:

    rng.chance(1, 10);
    
  • Results of an "from" to "to" chance of something happening.

    Parameters

    • from: number

      Left hand side

    • to: number

      Right hand side

    Returns boolean

    Success or not

    A "500 to 1" chance would be:

    rng.chanceTo(500, 1);
    

Choices

  • Takes a random choice from an array of values, with equal weight.

    Type Parameters

    • T

    Parameters

    • array: T[]

    Returns null | T

    The random choice from the array

  • Takes a random key from an object with a key:number pattern

    Using a Map allows objects to be specified as keys, can be useful for choosing between concrete objects.

    Parameters

    • data: any[] | Map<any, number> | Record<any, number>

      The values to choose from

    Returns any

    The random choice from the array

    Will return:

    • 'a' 1/10 of the time
    • 'b' 2/10 of the time
    • 'c' 3/10 of the time
    • 'd' 3/10 of the time
    rng.weightedChoice({
    a: 1,
    b: 2,
    c: 3,
    d: 4
    });

    Will return:

    • diamond 1/111 of the time
    • ruby 10/111 of the time
    • pebble 100/111 of the time
    const diamond = new Item('diamond');
    const ruby = new Item('ruby');
    const pebble = new Item('pebble');

    const choices = new Map();
    choices.set(diamond, 1);
    choices.set(ruby, 10);
    choices.set(pebble, 100);

    rng.weightedChoice(choices);

Distributions

  • Generates a Gaussian normal value via Box–Muller transform

    There are two ways of calling, either with an object with mean and stddev as keys, or just with two params, the mean and stddev

    Support: [0, 1]

    Parameters

    • Optionaloptions: {
          mean?: number;
          stddev?: number;
      }
      • Optionalmean?: number

        The mean of the underlying normal distribution.

      • Optionalstddev?: number

        The standard deviation of the underlying normal distribution.

    Returns number

    A value from the Log-Normal distribution.

    rng.boxMuller({ mean: 0.5, stddev: 1 });
    rng.boxMuller(0.5, 1);

    NumberValidationError If the input parameters are not valid.

  • Generates a Gaussian normal value via Box–Muller transform

    There are two ways of calling, either with an object with mean and stddev as keys, or just with two params, the mean and stddev

    Support: [0, 1]

    Parameters

    • Optionalmean: number

      The mean of the underlying normal distribution.

    • Optionalstddev: number

      The standard deviation of the underlying normal distribution.

    Returns number

    A value from the Log-Normal distribution.

    rng.boxMuller({ mean: 0.5, stddev: 1 });
    rng.boxMuller(0.5, 1);

    NumberValidationError If the input parameters are not valid.

  • Generates a gaussian normal number, but with a special skewing procedure that is sometimes useful.

    Parameters

    • Optionaloptions: {
          mean?: number;
          skew?: number;
          stddev?: number;
      }
      • Optionalmean?: number
      • Optionalskew?: number
      • Optionalstddev?: number

        Must be > 0

    Returns number

    A normally distributed number

    rng.gaussian({ mean: 0.5, stddev: 0.5, skew: -1 });
    

    NumberValidationError If the input parameters are not valid.

Random Number Generation

  • The chancy function has a very flexible calling pattern.

    You can pass it a dice string, an object or a number.

    • If passed a dice string, it will do a roll of that dice.
    • If passed a number, it will return that number
    • If passed a config object, it will return a randomly generated number based on that object

    The purpose of this is to have easily serialised random signatures that you can pass to a single function easily.

    All chancy distribution functions (that is, when called with ChancyInterface) can be called with min and max parameters, however, it's highly advised to tune your parameters someway else.

    Basically, the function will just keep resampling until a figure inside the range is generated. This can quickly lead to large recursion depths for out of bounds inputs, at which point an error is thrown.

    Parameters

    Returns number

    A randomly generated number or an element from a passed array

    rng.chancy(1); // returns 1
    rng.chancy('1d6'); // returns an int between 1 and 6 [1, 6]
    rng.chancy({ min: 10 }); // Equivalent to calling rng.random(10, Number.MAX_SAFE_INTEGER)
    rng.chancy({ max: 10 }); // Equivalent to calling rng.random(0, 10)
    rng.chancy({ min: 0, max: 1 }); // Equivalent to calling rng.random(0, 1)
    rng.chancy({ type: 'integer', min: 10 }); // Equivalent to calling rng.randInt(10, Number.MAX_SAFE_INTEGER)
    rng.chancy({ type: 'integer', max: 10 }); // Equivalent to calling rng.randInt(0, 10)
    rng.chancy({ type: 'integer', min: 10, max: 20 }); // Equivalent to calling rng.randInt(10, 20)
    rng.chancy({ type: 'normal', ...args }); // Equivalent to calling rng.normal(args)
    rng.chancy({ type: 'normal_integer', ...args }); // Equivalent to calling Math.floor(rng.normal(args))
    // You can call any of the 'distribution' type functions with chancy as well.
    rng.chancy({ type: 'boxMuller', ...args }); // Equivalent to calling rng.boxMuller(args)
    rng.chancy({ type: 'bates', ...args }); // Equivalent to calling rng.bates(args)
    rng.chancy({ type: 'exponential', ...args }); // Equivalent to calling rng.exponential(args)

    This is your monster file monster.json:

    {
    "id": "monster",
    "hp": {"min": 1, "max": 6, "type": "integer"},
    "attack": "1d4"
    }

    How about a stronger monster, with normally distributed health strong_monster.json:

    {
    "id": "strong_monster",
    "hp": {"min": 10, "max": 20, "type": "normal_integer"},
    "attack": "1d6+1"
    }

    Or something like this for boss_monster.json which has a fixed HP:

    {
    "id": "boss_monster",
    "hp": 140,
    "attack": "2d10+4"
    }

    Then in your code:

    import {Rng, Chancy} from GameRng;

    const rng = new Rng();

    class Monster {
    hp = 10;
    id;
    attack = '1d4';
    constructor ({id, hp = 10, attack} : {id: string, hp: Chancy, attack: Chancy} = {}) {
    this.id = options.id;
    this.hp = rng.chancy(hp);
    if (attack) this.attack = attack;
    }
    attack () {
    return rng.chancy(this.attack);
    }
    }

    const spec = await fetch('strong_monster.json').then(a => a.json());
    const monster = new Monster(spec);
  • Type Parameters

    • T

    Parameters

    • input: T[]

    Returns T

  • Rounds the results of a chancy call so that it's always an integer.

    Not quite equivalent to Math.round(rng.chancy(input)) because it will also transform {type: 'random'} to {type: 'integer'} which aren't quite the same.

    'random' has a range of [min, max) whereas interger is [min, max] (inclusive of max).

    Parameters

    Returns number

    chancy

  • Given a string dice representation, roll it

    Parameters

    • dice: string

      e.g. 1d6+5

    Returns number

    A random roll on the dice

    rng.dice('1d6');
    rng.dice('3d6+10');
    rng.dice('1d20-1');
    rng.dice('d10');

    Error if the given input is invalid.

  • Given an object representation of a dice, roll it

    Parameters

    Returns number

    A random roll on the dice

    rng.dice({ d: 6 });
    rng.dice({ n: 3, d: 6, plus: 10 });
    rng.dice({ n: 1, d: 20, plus: -1 });
    rng.dice({ n: 1, d: 10 });

    Error if the given input is invalid.

  • Roll "n" x "d" sided dice and add "plus"

    Parameters

    • options: number[]

      [n, d, plus] format of dice roll

    Returns number

    A random roll on the dice

    Error if the given input is invalid.

  • Roll "n" x "d" sided dice and add "plus"

    Parameters

    • n: number

      The number of dice to roll

    • Optionald: number

      The number of faces on the dice

    • Optionalplus: number

      The number to add at the end

    Returns number

    A random roll on the dice

    Error if the given input is invalid.

  • Generates a normally distributed number, but with a special clamping and skewing procedure that is sometimes useful.

    Note that the results of this aren't strictly gaussian normal when min/max are present, but for our puposes they should suffice.

    Otherwise, without min and max and skew, the results are gaussian normal.

    Parameters

    • Optionaloptions: {
          max?: number;
          mean?: number;
          min?: number;
          skew?: number;
          stddev?: number;
      }
      • Optionalmax?: number

        Maximum value allowed for the output

      • Optionalmean?: number

        The mean value of the distribution

      • Optionalmin?: number

        Minimum value allowed for the output

      • Optionalskew?: number

        The skew to apply. -ve = left, +ve = right

      • Optionalstddev?: number

        Must be > 0 if present

    • Optionaldepth: number

      used internally to track the recursion depth

    Returns number

    A normally distributed number

    rng.normal({ min: 0, max: 1, stddev: 0.1 });
    rng.normal({ mean: 0.5, stddev: 0.5 });

    NumberValidationError If the input parameters are not valid.

  • Returns number

    A random number from [0, 1)

  • Parameters

    • Optionalfrom: number

      Lower bound, inclusive

    Returns number

    A random number from [from, from+1)

  • Note that from and to should be interchangeable.

    Parameters

    • Optionalfrom: number

      Lower bound, inclusive

    • Optionalto: number

      Upper bound, exclusive

    Returns number

    A random number from [from, to)

    rng.randBetween(0, 10);
    // is the same as
    rng.randBetween(10, 0);
  • Note that from and to should be interchangeable.

    Parameters

    • from: number

      Lower bound, inclusive

    • to: number

      Upper bound, exclusive

    • skew: number

      A number by which the numbers should skew. Negative skews towards from, and positive towards to.

    Returns number

    A random number from [from, to) skewed a bit skew direction

    rng.randBetween(0, 10, 0);
    // is the same as
    rng.randBetween(10, 0, 0);
  • Returns number

    A random integer from [0, 1]

  • Note that from and to should be interchangeable.

    Parameters

    • Optionalfrom: number

      Lower bound, inclusive

    • Optionalto: number

      Upper bound, inclusive

    Returns number

    A random integer from [from, to]

    rng.randInt(0, 10);
    // is the same as
    rng.randInt(10, 0);
  • Note that from and to should be interchangeable.

    Parameters

    • Optionalfrom: number

      Lower bound, inclusive

    • Optionalto: number

      Upper bound, inclusive

    • Optionalskew: number

      A number by which the numbers should skew. Negative skews towards from, and positive towards to.

    Returns number

    A random integer from [from, to] skewed a bit in skew direction

    rng.randInt(0, 10, 1);
    // is the same as
    rng.randInt(10, 0, 1);
  • Alias of randBetween

    Parameters

    • Optionalfrom: number
    • Optionalto: number
    • Optionalskew: number

    Returns number

Result Prediction

  • Determines the maximum value a Chancy input can take.

    Parameters

    Returns number

    Maximum value a call to chancy with these args can take

  • Determines the minimum value a Chancy input can take.

    Parameters

    Returns number

    Minimum value a call to chancy with these args can take

  • Gives the maximum result of a call to dice with these arguments

    Parameters

    • n: string | number | DiceInterface
    • Optionald: number
    • Optionalplus: number

    Returns number

    dice

  • Gives the minimum result of a call to dice with these arguments

    Parameters

    • n: string | number | DiceInterface
    • Optionald: number
    • Optionalplus: number

    Returns number

    dice

Seeding

  • Get the current seed.

    Note this may not be the same as the set seed if numbers have been generated since its inception. Also, strings are usually transformed to numbers.

    Returns number

    The current seed

  • Pass a function that will return uniform random numbers as the source of this rng's randomness.

    Supersedes and seed setting.

    Parameters

    • Optionalfunc: Randfunc

      The random function

    Returns this

    const rng = new Rng();
    rng.randomSource(() => 1);

    assert(rng.random() === 1); // true
  • Seed the random number generator with the given seed.

    Parameters

    • seed: Seed

      Can be a string or a number

    Returns this

Serialization

  • A serialized, storable version of this RNG that can be unserialized with unserialize

    Returns any

Utilities

  • Gets the bin "val" sits in when between "min" and "max" is separated by "bins" number of bins

    This is right aligning, so .5 rounds up

    This is useful when wanting only a discrete number values between two endpoints

    Parameters

    • val: number

      The value to bin

    • bins: number

      The number of bins

    • min: number

      Minimum value

    • max: number

      Maximum value

    Returns number

    The corresponding bin (left aligned)

    rng.bin(1.3, 11, 0, 10); // 1
    rng.bin(4.9, 11, 0, 10); // 5
    rng.bin(9.9, 11, 0, 10); // 10
    rng.bin(0.45, 11, 0, 10); // 0
    rng.bin(0.50, 11, 0, 10); // 1
  • Clamps a number to lower and upper bounds, inclusive

    Parameters

    • number: number
    • lower: number
    • upper: number

    Returns number

    rng.clamp(5, 0, 1); // 1
    rng.clamp(-1, 0, 1); // 0
    rng.clamp(0.5, 0, 1); // 0.5
  • Parses a string representation of a dice and gives the object representation {n, d, plus}

    Parameters

    • string: string

      String dice representation, e.g. '1d6'

    Returns DiceInterface

    The dice representation object

    Error if the given input is invalid.

  • Returns a unique string of length len

    Parameters

    • Optionallen: number

      Length of the string to generate

    Returns string

    A string of length "len"

  • Scales a number from [min, max] to [from, to].

    Some might call this linear interpolation.

    Min and max default to 0 and 1 respectively

    Parameters

    • number: number

      The number - must be 0 <= number <= 1

    • from: number

      The min number to scale to. When number === min, will return from

    • to: number

      The max number to scale to. When number === max, will return to

    • Optionalmin: number

      The minimum number can take, default 0

    • Optionalmax: number

      The maximum number can take, default 1

    Returns number

    A number scaled to the interval [from, to]

    rng.scale(0.5, 100, 200); // 150
    rng.scale(0, 100, 200); // 100
    rng.scale(1, 100, 200); // 200
    rng.scale(5, 100, 200, 0, 10); // 150
  • Scales a number from [0, 1] to [from, to].

    Some might call this linear interpolation

    Parameters

    • number: number

      The number - must be 0 <= number <= 1

    • from: number

      The min number to scale to. When number === 0, will return from

    • to: number

      The max number to scale to. When number === 1, will return to

    Returns number

    A normal number scaled to the interval [from, to]

    rng.scaleNorm(0.5, 100, 200); // 150
    rng.scaleNorm(0, 100, 200); // 100
    rng.scaleNorm(1, 100, 200); // 200
  • Shuffle a given array using the in build RNG

    Type Parameters

    • T

    Parameters

    • array: T[]

    Returns T[]

    the shuffled array.

  • Returns a unique 14 character string.

    Highly collision resistant, and strictly incrementing

    Useful for using as object IDs or HTML ids (with prefix).

    Parameters

    • Optionalprefix: string

      A prefix to include on the output

    Returns string

    a 14 character string

  • Given an array, gives a key:weight Map of entries in the array based on how many times they appear in the array.

    Parameters

    • data: any[]

      The values to choose from

    Returns Map<any, number>

    The weights of the array

    const weights = rng.weights(['a', 'b', 'c', 'a']);
    assert(weights['a'] === 2);
    assert(weights['b'] === 1);
    assert(weights['c'] === 1);