1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
|
# dicebag
A dice expression parser and roller.
## Installation
# in a local node_modules/
npm install --save dicebag
# globally, to use the CLI
npm install -g dicebag
## Command-line usage
dicebag [-p] [<dice expression>]
If a dice expression is provided, prints the result of rolling those dice and
exits. Otherwise, reads expressions from `stdin` in a loop.
* `-p` print dice pools (default behavior is to print the dice's sum)
### Examples
$ dicebag 1d6
1
$ dicebag "2d8 + 1d4"
7
$ dicebag -p "2d8 + 1d4"
[ 5, 3, 4 ]
## Library usage
const { parse, pool, roll } = require('dicebag')
The API consists of three functions:
* `parse(diceExpression)` parses an expression into an object understood by the
other two functions.
* `pool(dice)` rolls the dice and returns an array of their results.
* `roll(dice)` rolls the dice and returns their sum.
### Examples
const d6 = parse('1d6')
roll(d6) // 4
roll(d6) // 5
pool(d6) // [ 2 ]
const dice = parse('2d6 + 1d8')
roll(dice) // 10
pool(dice) // [ 1, 4, 7 ]
## Dice expressions
### Basics
Simple expressions involving standard dice notation as used in most roleplaying
games are supported. You can do things like:
* `XdY`: rolls `X` `Y`-sided dice (`1d6` is a single 6-sided die, `2d4` is two
4-sided dice).
* `dX` is the same as `1dX` (so you can shorten `1d6` to `d6`).
* `dice +/- constant`: rolls the dice, adds/subtracts the constant.
* `dice +/- moreDice`: sums/takes the difference of the results of rolling
`dice` and `moreDice`.
* `number K dice`: rolls the dice and keeps the `number` highest results. For
example, `1K2d20` is the "rolling with advantage" mechanic from 5th Edition
Dungeons and Dragons (roll two d20's, keep the highest).
* `number k dice`: like `K` but keeps the `number` lowest results. `1k2d20` is
D&D5E's "disadvantage" mechanic.
### Full syntax and semantics
**Note:** this is still an early version. Syntax and semantics will be expanded
in future versions. *Backwards incompatible changes are possible.*
The parser recognizes the following grammar:
Die ::= <an integer>
| '(' Die ')'
| Die 'd' Die
| 'd' Die
| Die ' + ' Die
| Die ' - ' Die
| Die '+' Die
| Die '-' Die
| '-' Die
| Die 'E' Die
| Die 'K' Die
| Die 'k' Die
| Die 'A' Die
| Die 'T' Die
Semantics are defined in terms of the `pool` function.
* `N`, where `N` is an integer, is a die that always rolls a single value
equal to `N`. `pool` returns an array containing just `N`.
* `DdE`, where `D` and `E` are dice expressions, is a die that rolls a number of
dice equal to the result of rolling `D`, where each die has a number of sides
equal to the result of rolling `E`. `pool` returns an array of `roll(D)`
numbers, each between 1 and `roll(E)`. *Note:* if `D` or `E` evaluates to a
negative number, the behavior is undefined.
* `dD` is equivalent to `1dD`.
* `D + E` appends the dice pool generated by `E` to the dice pool generated by
`D`.
* `-D` returns the opposites of values generated by `D`.
* `D - E` is equivalent to `D + (-E)`.
* `D+E` is the additive bonus operation. For each die in `D`'s pool, the die is
rolled and `roll(E)` is added to its result.
* `D-E` is equivalent to `D+(-E)`.
* `DEF` (here `E` is the literal symbol `E`, `D` and `F` are dice expressions)
is an "exploding die." First `D` is rolled. Now each die in the dice pool
generated by `F` is rolled repeatedly until it rolls something less than the
value rolled on `D`. The die's result is the sum of all those rolls. *Note:*
this could lead to an infinite evaluation if `F` always rolls higher than a
possible result of `D`.
* `DKE` is the "keep highest" mechanic. First `D` is rolled. Now each die in the
dice pool generated by `E` is rolled, and the resulting dice pool is composed
of those dice that rolled highest, taking up to as many dice as the result of
rolling `D`.
* `DkE` is the "keep lowest" mechanic. Like `K`, but selects the lowest rolling
dice.
* `DAE` might roll some of `E`'s pool again. First `D` is rolled. Now each die
in the dice pool generated by `E` is rolled repeatedly until it rolls
something less than the value rolled on `D`. Each such roll is treated as a
separate die, the results for each die are not accumulated like with exploding
die.
* `DTE` applies a threshold to the dice in `E`'s pool. First `D` is rolled. Now
when a die from `E`'s pool rolls below the value rolled on `D`, its value is
0, otherwise its value is 1.
Additionally:
* The binary arithmetic operations (` + `, ` - `) are left associative.
* The bonus operations (`+`, `-`) are left associative. They bind stronger than
arithmetic operations.
* The die operations (`d`, `E`, `K`, etc.) are right associative (`1d2d3` is
equivalent to `1d(2d3)`, use explicit parentheses if you need `(1d2)d3`).
* Die operations bind stronger than the binary arithmetic operations
(`1d6 + 1d4` is equivalent to `(1d6) + (1d4)`) and the bonus operations.
|