import { roll } from "../random_utils.js";
const RANGE_ERROR = "Dice ranges must be from 1 to 100";
/**
* A table of stuff you select by rolling 1d100.
*
* @example
* let table = new Table();
* table.add(50, 'heads')
* table.add(50, 'tails');
* table.get();
* => 'heads'
*
*/
class Table {
/**
* @param outFunction {Function} A function to run on values supplied to the add method. For
* example, you might create a function to convert item names to true Item objects, as a
* convenience when building the table.
*/
constructor({ outFunction = (a) => a } = {}) {
this.outFunction = outFunction;
this.rows = [];
this.sum = 0;
}
/**
* Add something to this table. You can either specify the specific percentage that this
* element should be selected, or you can provide the range of die roll numbers (this
* latter approach is easier when you're adapting an existing pen-and-paper table).
*
* The percentages must add up to 100% (or 100 on 1d100).
*
* @example
* let table = new Table();
* table.add(50, object); // will occur 50% of the time
* table.add(1, 70, object); // Will occur 70% of the time, on a roll of 1 to 70
*
* @param percentOrStartRoll {Number} % chance occurrence of 100%, or the start number on 1d100
* @param [endRoll] {Number}
* @param object {Object} Element to add to the table, can be any type
*/
add(...args) {
let start, end, object, chance;
if (args.length === 3) {
start = args[0];
end = args[1];
object = args[2];
chance = end - start + 1;
if (start < 1 || start > 100 || end < 1 || end > 100) {
throw new Error(RANGE_ERROR);
}
} else {
chance = args[0];
object = args[1];
if (chance < 1 || chance > 100) {
throw new Error(RANGE_ERROR);
}
}
if (typeof object === "undefined") {
throw new Error("Object is undefined");
}
this.rows.push({ chance, object });
this.sum += chance;
return this;
}
/**
* Get an item from the table, based on percentages.
*
* @return {Object} An item from the table
*/
get() {
if (Math.round(this.sum) !== 100) {
throw new Error(`Table elements add up to ${Math.round(this.sum)} (not 100%)`);
}
let result = roll(100);
for (let i = 0, len = this.rows.length; i < len; i++) {
if (result <= this.rows[i].chance) {
return this.outFunction(this.rows[i].object);
}
result -= this.rows[i].chance;
}
}
/**
* @return {Number} the number of items in the table.
*/
size() {
return this.rows.length;
}
}
export default Table;