UNPKG

@mousepox/math

Version:

Math-related objects and utilities

75 lines (74 loc) 2.01 kB
const M = 0x80000000; const A = 1103515245; const C = 12345; const DiceNotationPattern = /([0-9]+)?d([0-9]+)([+-]{1}[0-9]+)?/; function parseDiceNotation(notation) { const matches = notation.match(DiceNotationPattern); if (matches === null) { throw new Error(`Invalid dice notation: ${notation}`); } return { bonus: Number(matches[3]), count: Number(matches[1]), sides: Number(matches[2]), }; } export class Random { static getDiceNotationRange(notation) { const { count, sides, bonus } = parseDiceNotation(notation); return { max: count * sides + bonus, min: count * 1 + bonus, }; } state = 0; constructor(seed) { this.reset(seed); } reset(seed) { if (seed !== undefined) { this.state = seed; } else { this.state = Math.floor(Math.random() * (M - 1)); } } next() { this.state = (A * this.state + C) % M; return this.state / M; } integer(min, max) { return Math.floor(this.next() * (max - min + 1)) + min; } chance(probability) { return this.next() <= probability; } choice(items, remove = false) { const index = this.integer(0, items.length - 1); const pick = items[index]; if (remove) { items.splice(index, 1); } return pick; } shuffle(items) { const len = items.length; if (len < 2) { return; } for (let i = 0; i < len; ++i) { const j = this.integer(i, len - 1); const swap = items[i]; items[i] = items[j]; items[j] = swap; } } rollDiceNotation(notation) { const { count, sides, bonus } = parseDiceNotation(notation); let result = bonus; for (let i = 0; i < count; ++i) { result += this.integer(1, sides); } return result; } }