UNPKG

@randsum/dice

Version:

A flexible, type-safe dice roller for tabletop RPGs, game development, and probability simulations

159 lines (158 loc) 3.23 kB
import { RandsumError } from '@randsum/core'; import { roll } from './roll'; import { coreSpreadRolls } from './utils/coreSpreadRolls'; import { generateNumericFaces } from './utils/generateNumericFaces'; class DieBase { sides; constructor(sides) { this.sides = sides; } } class NumericDieImpl extends DieBase { type = 'numeric'; faces; isCustom = false; constructor(sides) { super(sides); this.faces = generateNumericFaces(sides); } roll(quantity = 1) { const rolls = this.rollSpread(quantity); return rolls.reduce((acc, roll) => acc + roll, 0); } rollSpread(quantity = 1) { return coreSpreadRolls(quantity, this.sides, this.faces); } rollModified(quantity = 1, modifiers = {}) { const options = { ...this.toOptions, quantity, modifiers }; return roll(options); } get toOptions() { return { quantity: 1, sides: this.sides }; } } class CustomDieImpl extends DieBase { type = 'custom'; faces; isCustom = true; constructor(faces) { if (!faces.length) { throw new RandsumError('Custom die must have at least one face', 'INVALID_DIE_CONFIG', { input: faces, expected: 'Array with at least one face value' }, [ 'Provide at least one face value: ["H", "T"] for a coin', 'Use standard dice like D6 if you need numbered faces', 'Custom faces must be non-empty strings' ]); } super(faces.length); this.faces = [...faces]; } roll(quantity = 1) { const rolls = this.rollSpread(quantity); return rolls.join(', '); } rollSpread(quantity = 1) { return coreSpreadRolls(quantity, this.sides, this.faces); } rollModified(quantity = 1, modifiers = {}) { return roll({ ...this.toOptions, quantity, modifiers }); } get toOptions() { return { quantity: 1, sides: [...this.faces] }; } } function D(arg) { if (typeof arg === 'number') { return new NumericDieImpl(arg); } else { return new CustomDieImpl(arg); } } export const D4 = D(4); export const D6 = D(6); export const D8 = D(8); export const D10 = D(10); export const D12 = D(12); export const D20 = D(20); export const D100 = D(100); export const coin = D(['Heads', 'Tails']); export const fudgeDice = D(['+', '+', '+', '-', ' ', ' ']); const alphanumFaces = [ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' ]; export const alphaNumDie = D(alphanumFaces); export { D };