npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@airjp73/dice-notation

v2.2.2

Published

A js library for parsing dice notation

Downloads

91

Readme

@airjp73/dice-notation

A flexible and pluggable js library for parsing dice notation. It has:

  • Fully typed with Typescript
  • No-fuss use for simple use-cases
  • High level of customization
  • Ability to inspect the individual tokens in the notation -- not just calculate the result.

Installation

npm install --save @airjp73/dice-notation

Simple Usage

If all you want to do is parse some dice notation and get the result you can import roll and pass in the notation.

import { roll } from '@airjp73/dice-notation';

const { result } = roll('1d6 + 3');

It is recommended to use an IDE or text editor that can show you the Typescript types for more in-depth documentation.

Inspecting individual rolls

If you want to get the results of individual dice rolls or more info about the notation itself, you can use these functions. The roll function from the Simple Usage section is essentially just a wrapper for these 4 functions.

import {
  tokenize,
  rollDice,
  tallyRolls,
  calculateFinalResult,
} from '@airjp73/dice-notation';

// Gets the tokens from the lexer
// Example: [DiceRollToken, OperatorToken, DiceRollToken]
const tokens = tokenize('2d6 + 3d4');

// Rolls any dice roll tokens and returns all the individual rolls.
// rolls[i] contains all the rolls for the DiceRollToken at tokens[i]
// Example: [[3, 1], null, [1, 3, 2]]
const rolls = rollDice(tokens);

// Takes the rolls and totals them
// Example: [4, null, 6]
const rollTotals = tallyRolls(tokens, rolls);

// Get the final result of the roll
// Example: 10
const result = calculateFinalResult(tokens, rollTotals);

It's broken up this way to allow as much flexibility as possible for how you want to display the information and what kind of custom dice rules you might want.

Custom dice rules

The default roll function only supports basic dice notation. If you want to support something more than that, you need a custom dice rule.

Custom dice rule implementation

Let's say we want to add a rule to allow us to use d% instead of d100. We can create our rule like this:

// A convenience function for rolling a dice. You can use something else if you want
const myRule = {
  // Regex to pass to the parser
  regex: /\d+d%/,

  // A unique string for our token
  typeConstant: 'MyRule',

  // Takes the raw string value of the custom dice roll
  // and returns data about that role -- it can be whatever you want it to be
  // in this case we only care about how many d100s we need to roll
  tokenize: (raw) => ({ numDice: parseInt(raw.split('d')[0]) }),

  // Takes the data returned from `tokenize` and returns an array of rolls
  // this is so we can see what every individual dice roll was if we want
  // Here we're using a helper to auto-generate the rolls (see helper section below)
  roll: ({ numDice }, { generateRolls }) => generateRolls(numDice, 100),

  // Takes the token returned from `tokenize` and the rolls returned from `roll`
  // and returns the total value
  // Here we're just summing all the rolls, but you can do special logic here if you want
  calculateValue: (token, rolls) => rolls.reduce((agg, num) => agg + num, 0),
};

Type definition

The full type definition of a custom rule is:

interface DiceRule<T> {
  regex: RegExp;
  typeConstant: string;
  tokenize: (raw: string, config: RollConfig) => T;
  roll: (token: T, config: RollConfig) => Rolls;
  calculateValue: (token: T, rolls: number[], config: RollConfig) => number;
}

RollConfig helpers

As you can see above, there are some useful helpers given to each part of the dice rule.

export interface RollConfig {
  // Generate a random number between `min` and `max` inclusive
  // `random(1, 6)` would be like rolling 1d6 because it would generate a number between 1 & 6
  random: (min: number, max: number) => number;

  // Generates `numDice` rolls for dice of size `diceSize`
  // `generateRolls(3, 6)` would be like rolling 3d6
  generateRolls: (numDice: number, diceSize: number) => number[];

  // An object that contains any context provided by you
  // See configuration section below
  context: Record<string, any>;
}

Using the custom rule

Once you've created your custom rule, you need to create new roll methods like so:

import { withPlugins, createDiceRoller } from '@airjp73/dice-notation';

// You can use the same roll functions as before, but now your custom rules are injected into it.
const {
  roll,
  tokenize,
  rollDice,
  tallyRolls,
  calculateFinalResult,
} = createDiceRoller(withPlugins(myRule));

Configuration

Configuration options can be provided to createDiceRoller and/or to individual rolling functions.

// Configuration when creating dice roller
createDiceRoller(withPlugins(myRule), config);

// Configuration when rolling
roll('1d6', config);
const tokens = tokenize('1d6', config);
const rolls = rollDice(tokens, config);
const rollTotals = tallyRolls(tokens, rolls, config);

// `calculateFinalResult` does not accept configuration
const result = calculateFinalResult(tokens, rollTotals);

Configuration options

random

Can be used to customize the randomization function used by dice rules.

const config = {
  // Contrived `random` function that returns `min` + `max` instead of a random number
  random: (min, max) => min + max,
};

// The result here will be `7`
roll('1d6', config);

context

Used to provide outside context to custom dice rules.

Example: This could allow you to write a custom rule to allow variables in dice notation. The values for each variable can be provided through context

const config = {
  context: {
    myVariable: 5,
  },
};

// Result will be `1d6 + 5`
roll('1d6 + myVariable', config);

maxRandomRolls

By default, the dice roller will throw an error if it rolls more than 100,000 dice. If you tweak this setting, be aware that rolling too many dice can result in browser or server crashes. This setting is not intended as validation, simply as crash-prevention.

If 100,000 is too few dice, this can be changed with this setting:

const config = {
  maxRandomRolls: 1_000_000,
};

If you really want to disable the limit entirely (this is probably a bad idea), you can turn it off like this:

const config = {
  maxRandomRolls: 'unlimited_rolls_not_recommended',
};