Dice

npm version

"Not only does God play dice, but... he sometimes throws them where they cannot be seen." — Stephen Hawking

Description

This package controls everything related to rolling dice. It provides a base class called Die which implements a pRNG to return numbers in a given range (according to the amount of faces of the die).

Installation

With npm:

npm install @xethya/dice

With yarn:

yarn add @xethya/dice

Usage

Via instantiation

import { Die } from '@xethya/dice';

const die = new Die(6);
die.roll(); // returns a number between 1 and 6

Via static invocation

import { Die } from '@xethya/dice';

Die.rollD(6); // returns a number between 1 and 6

Listening to events

Every time the roll() function is called, two events are triggered:

Event name

Parameters

Description

before:roll

Event triggered before generating a pseudo-random number (a.k.a. actually rolling the die).

roll

rolled: number

Event triggered after rolling the die.

You can use the following methods to subscribe to these events:

Method

Parameters

onBeforeRoll

A callback with no parameters.

onRoll

A callback receiving a rolled: number argument.

onNextRoll

Same as onRoll, but only triggered for the next immediate invocation of roll.

For example:

import { Die } from `@xethya/dice`;

const die = new Die(6);
die.onNextRoll((rolled: number) => {
  if (rolled === 6) {
    // Do something with other system component.
    // Events are useful to composing functionality
    // across different game modules.
  }
});
const roll = die.roll();
// Do something else local to this module.

Presets

The component includes a series of predefined dice, which you can use instead of creating an instance of Die with a given number of faces:

Preset

Range

CoinFlip

1 - 2

D4

1 - 4

D6

1 - 6

D8

1 - 8

D10

1 - 10

D12

1 - 12

D20

1 - 20

D100

1 - 100

Any preset can be used importing the proper class from the package root or from the Presets namespace:

import { D12 } from '@xethya/dice';
import { presetDice } from '@xethya/dice';

const d12 = new D12();
// or...
const d12 = new presetDice.D12();

Customizing the randomizer

Dice rolls are calculated by default using an implementation of the Blum Blum Shub generator. You can implement any other algorithm of your choice, by passing an instance of it into the settings:

import MyPRNG from './my-prng';
import Die from '@xethya/dice';

const customDie = new Die(10, { randomizer: new MyPRNG() });
customDie.roll();

Any randomizer must implement the IPseudoRandomNumberGenerator interface, implementing a generateRandom() function. In order to use this interface in TypeScript, you'll need to install the @xethya/random-core package:

import { IPseudoRandomNumberGenerator } from '@xethya/random-core';

class MyPRNG implements IPseudoRandomNumberGenerator {
  generateRandom(): number {
    return Math.random();
  }
}

Rolling multiple dice at once

Although you can instantiate multiple dice in separate variables, it can be somewhat impractical to execute the roll() method on each instance. To simplify this use case, there is a DiceThrow class available.

import { DiceThrow } from '@xethya/dice';

const diceThrow = new DiceThrow({
  diceCount: 6,   // How many dice to roll?
  faces: 6,       // How many faces a die has?
});

// Unlike Die#roll(), instead of a single number, you'll get
// an instance of DiceThrowResult, containing an array of numbers; 
// each number represents a die roll.
diceThrow.roll();   // { rolled: [1, 6, 3, 5, 1, 2] }

// You can also get a sum of all the numbers
// using the getRollSum() function.
const totalPoints = diceThrow.roll().getRollSum(); // 18

You can also pass a randomizer property into the settings with an instance of IPseudoRandomNumberGenerator to replace the default Blum Blum Shub algorithm.

Calculating success with dice

There's a special kind of dice throw called a chance throw (represented by the ChanceThrow class). This throw uses a D100 and reports on the success the roll was. A typical use case for this kind of throw is to determine, for example, if a stab or a punch produce critical damage to an opponent.

import { ChanceThrow, DiceThrowTypes } from '@xethya/dice';

const chanceThrow = new ChanceThrow();

// The roll() function returns a single rolled number between
// 1 and 100 and a property "throwType" to determine if the
// throw was a failure, a success or a critical success.
const result = chanceThrow.roll();

if (result.throwType === DiceThrowTypes.FAILURE) {
  console.log('Boo-hoo, you missed!');
} else {
  console.log('Nicely done!');
}

The property throwType uses an enumerable called DiceThrowType . By default, the property's value is determined with these value ranges:

Range

Resulting throw type

Consequence example

1 - 20

DiceThrowType.FAILURE

A character tried to open a lock with a key, but acted clumsily and broke the key.

21 - 90

DiceThrowType.SUCCESS

A character tried to shoot down a bird with and arrow, and succeeded.

91 - 100

DiceThrowType.CRITICAL_SUCCESS

A character tried to persuade an enemy to not sound the alarm upon being seen, and not only achieved that, but turned the enemy into a friend.

The value ranges can be customized by supplying a chanceRanges property in the configuration object that is passed to the constructor. You'll need to use the Range class provided in the @xethya/utils package to set the values:

import { ChanceThrow } from '@xethya/dice';
import { Range } from '@xethya/utils';

const chanceThrow = new ChanceThrow({
  chanceRanges: {
    failureRange: new Range(1, 80),
    successRange: new Range(81, 95),
    critialSuccessRange: new Range(96, 100),
  }
});

Last updated

Was this helpful?