dice.js

I love to play table top roleplaying games. Many of those require that you roll dice. I don't always have any handy, so here is a little class written in javascript to roll dice given a string in standard dice notation, e.g. '2d20+3' – also available as typescript.

New version

This is the newest version of the dice roller – it is encapsulated within a class, and includes a log of passed rolls.

class diceRoller {

  constructor() {
    this.log = [];
  }

  validate(diceNotation) {
    const match = /^(\d+)?d(\d+)([+-]\d+)?$/.exec(diceNotation);
    if (!match) {
      throw "Invalid dice notation: " + diceNotation;
    } else {
      return match;
    }
  }

  parseDice(diceNotation) {
    const match = this.validate(diceNotation);
    if (match) {
      const diceInfo = {
        numberOfDice: typeof match[1] === "undefined" ? 1 : parseInt(match[1]),
        sidesOfDice: parseInt(match[2]),
        diceModifier: typeof match[3] === "undefined" ? 0 : parseInt(match[3])
      };
      return diceInfo;
    }
  }

  tallyRolls(diceData) {
    let total = 0;
    for (let i = 0; i < diceData.numberOfDice; i++) {
      total += Math.floor(Math.random() * diceData.sidesOfDice) + 1;
    }
    total += diceData.diceModifier;
    return total;
  }

  roll(humanInput) {
    const rollResult = this.tallyRolls(this.parseDice(humanInput));
    const rightNow = new Date();
    let logEntry = {
      "timestamp": rightNow.toISOString(),
      "input": humanInput,
      "result": rollResult
    }
    this.log.push(logEntry);
    return rollResult;
  }

};

Example usage

Instantiate an instance of the class for each player, and then go nuts!

// instantiate yo' players
const playerSarah = new diceRoller();
const playerEli = new diceRoller();

// play the game
playerSarah.roll('2d10-4');
playerEli.roll('2d12+12');
playerSarah.roll('1d12');
playerEli.roll('1d2');


// check the log!
console.log('==== Sarah\'s log ====');
playerSarah.log.forEach(logEntry => {
  console.log(logEntry.input + " : " + logEntry.result + " : " + logEntry.timestamp);
});

console.log('==== Eli\'s log ====');
playerEli.log.forEach(logEntry => {
  console.log(logEntry.input + " : " + logEntry.result + " : " + logEntry.timestamp);
});

Older, simpler version

This is the original version of the dice roller code. It includes the same logic, and is simpler than the new on, but that it doesn't bake in any logging of passed rolls. I think this one is easier to parse, but not as useful in actual play without some more infrastructure around it.

"use strict";

const dice = {

  validate: (diceNotation) => {
    const match = /^(\d+)?d(\d+)([+-]\d+)?$/.exec(diceNotation);
    if (!match) {
      throw "Invalid dice notation: " + diceNotation;
    } else {
      return match;
    }
  },

  diceData: (diceNotation) => {
    const match = dice.validate(diceNotation);
    if (match) {
      const diceInfo = {
        numberOfDice: typeof match[1] === "undefined" ? 1 : parseInt(match[1]),
        sidesOfDice: parseInt(match[2]),
        diceModifier: typeof match[3] === "undefined" ? 0 : parseInt(match[3])
      };
      return diceInfo;
    }
  },

  math: (diceData) => {
    let total = 0;
    for (let i = 0; i < diceData.numberOfDice; i++) {
      total += Math.floor(Math.random() * diceData.sidesOfDice) + 1;
    }
    total += diceData.diceModifier;
    return total;
  },

  roll: (humanInput) => {
    return dice.math(dice.diceData(humanInput));
  }
};

// example usage
dice.roll('2d20');