import { sum } from "./utils/sum"; export class Dice { private count!: number; private sides!: number; constructor(dice: string) { this.parseDice(dice); } private parseDice(dice: string) { const [c, s] = dice.split(/[dD]/); this.count = Number(c); this.sides = Number(s); } public roll() { let results = []; for (let i = 0; i < this.count; i++) { results.push(this.rollSingle()); } return { total: sum(...results), max: Math.max(...results), min: Math.min(...results), results, }; } public rollMax() { return this.roll().max; } public rollMin() { return this.roll().min; } private rollSingle() { return Math.ceil(Math.random() * this.sides); } public rollAvg() { return this.roll().total / this.count; } public rollTimes(times: number) { let total = 0; for (let i = 0; i < times; i++) { total += this.roll().total; } return total; } public rollTimesAvg(times: number) { return this.rollTimes(times) / times; } public getNormalizedRollDistribution(): Record { const distribution: Record = this.computeDistribution(); // Normalize the distribution const totalOutcomes = Math.pow(this.sides, this.count); for (const sum in distribution) { if (distribution.hasOwnProperty(sum)) { distribution[sum] /= totalOutcomes; } } return distribution; } public getRollDistribution(): Record { return this.computeDistribution(); } private computeDistribution(): Record { const distribution: Record = {}; // Helper function to compute the sum distribution for given number of dice const computeSumDistribution = ( dice: number, sides: number, currentSum: number, currentDice: number ): void => { if (currentDice === dice) { distribution[currentSum] = (distribution[currentSum] || 0) + 1; return; } for (let i = 1; i <= sides; i++) { computeSumDistribution(dice, sides, currentSum + i, currentDice + 1); } }; // Compute distribution computeSumDistribution(this.count, this.sides, 0, 0); return distribution; } // STATIC static isDice(d: string) { return /\d+[dD]\d+/.test(d); } }