A dice expression parser and roller.
# in a local node_modules/
npm install --save dicebag
# globally, to use the CLI
npm install -g dicebag
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)
$ dicebag 1d6
1
$ dicebag "2d8 + 1d4"
7
$ dicebag -p "2d8 + 1d4"
[ 5, 3, 4 ]
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.
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 ]
Simple expressions involving standard dice notation as used in most roleplaying games are supported. You can do things like:
XdY
: rollsX
Y
-sided dice (1d6
is a single 6-sided die,2d4
is two 4-sided dice).dX
is the same as1dX
(so you can shorten1d6
tod6
).dice +/- constant
: rolls the dice, adds/subtracts the constant.dice +/- moreDice
: sums/takes the difference of the results of rollingdice
andmoreDice
.number K dice
: rolls the dice and keeps thenumber
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
: likeK
but keeps thenumber
lowest results.1k2d20
is D&D5E's "disadvantage" mechanic.
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 ']'
| Die 'd' Die
| 'd' Die
| Die ' + ' Die
| Die ' - ' Die
| Die ' * ' Die
| Die ' / ' Die
| Die '+' Die
| Die '-' Die
| Die '*' Die
| Die '/' Die
| '-' Die
| Die 'E' Die
| Die 'e' Die
| Die 'K' Die
| Die 'k' Die
| Die 'A' Die
| Die 'a' Die
| Die 'T' Die
| Die 't' Die
| Die ' x ' Die
Semantics are defined in terms of the pool
function.
N
, whereN
is an integer, is a die that always rolls a single value equal toN
.pool
returns an array containing justN
.DdE
, whereD
andE
are dice expressions, is a die that rolls a number of dice equal to the result of rollingD
, where each die has a number of sides equal to the result of rollingE
.pool
returns an array ofroll(D)
numbers, each between 1 androll(E)
. Note: ifD
orE
evaluates to a negative number, the behavior is undefined.dD
is equivalent to1dD
.D + E
appends the dice pool generated byE
to the dice pool generated byD
.-D
returns the opposites of values generated byD
.D - E
is equivalent toD + (-E)
.D * E
generates a dicepool with a single value - the product ofroll(D)
androll(E)
.D / E
generates a dicepool with a single value - the result of integer division ofroll(D)
byroll(E)
.D+E
is the additive bonus operation. For each die inD
's pool, the die is rolled androll(E)
is added to its result.D-E
is equivalent toD+(-E)
.D*E
is likeD+E
but multiplies each die inD
's pool the result of rollingE
.D/E
is likeD+E
but performs integer division on each die inD
's pool by the result of rollingE
.DEF
(hereE
is the literal symbolE
,D
andF
are dice expressions) is an "exploding die." FirstD
is rolled. Now each die in the dice pool generated byF
is rolled repeatedly until it rolls something less than the value rolled onD
. The die's result is the sum of all those rolls. Note: this could lead to an infinite evaluation ifF
always rolls higher than a possible result ofD
.DeF
is likeE
, but explodes on values less than what was rolled onD
.DKE
is the "keep highest" mechanic. FirstD
is rolled. Now each die in the dice pool generated byE
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 rollingD
.DkE
is the "keep lowest" mechanic. LikeK
, but selects the lowest rolling dice.DAE
might roll some of the dice inE
's pool again. FirstD
is rolled. Now each die in the dice pool generated byE
is rolled repeatedly until it rolls something less than the value rolled onD
. Each such roll is treated as a separate die, the results for each die are not accumulated like with exploding die. Note: this could lead to an infinite evaluation ifE
always rolls higher than a possible result ofD
.DaE
is likeA
, but rolls again on values less than what was rolled onD
.DTE
applies a threshold to the dice inE
's pool. FirstD
is rolled. Now when a die fromE
's pool rolls below the value rolled onD
, its value is 0, otherwise its value is 1.DtE
is likeT
but dice with values higher than what was rolled onD
are counted as 0's, the rest as 1's.D x E
will repeatedly rollD
. FirstE
is rolled, thenD
is rolled as many times as the value rolled onE
. The pools generated byD
are concatenated to generate the new pool. Note: ifE
evaluates to a negative number, the behavior is undefined.[D]
collectsD
's dice pool - the generated dice pool contains a single element, the result ofroll(D)
.
Additionally:
- The binary arithmetic operations (
+
,-
,*
,/
) are left associative. - The binary arithmetic operations bind as expected (multiplication and division bind stronger than addition and subtraction).
- The bonus operations (
+
,-
,*
,/
) are left associative. They bind stronger than arithmetic operations./
and*
bind stronger than+
and-
. - The die operations (
d
,E
,K
, etc.) are right associative (1d2d3
is equivalent to1d(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. - The repetition operation
x
is left assosiative. It binds stronger than the standard arithmetic operations, but weaker than the dice operations and the bonus operations.