ExDiceRoller v0.5.0-alpha ExDiceRoller
Converts strings into dice rolls and returns expected results. Ignores any
spaces, including tabs and newlines, in the provided string. A roll can be
invoked via ExDiceRoller.roll/3
.
iex> ExDiceRoller.roll("2d6+3")
8
iex> ExDiceRoller.roll("(1d4)d(6*y)-(2/3+1dx)", [x: 2, y: 3])
11
iex> import ExDiceRoller.Sigil
iex> ExDiceRoller.roll(~a/1d2+z/, [z: ~a/1d2/], [:explode])
8
Rolls and invoked compiled functions can be supplied a number of options:
:cache
: Performs a cache lookup, with a miss generating a compiled roll that is both cached and returned.ExDiceRoller.Cache.obtain/2
for more information.:explode
: Causes dice to explode. This means that if a die roll results in the highest possible value for a die (such as rolling a 20 on a d20), the die will be rerolled until the result is no longer the max possible. It then sums the total of all rolls and returns that value.:keep
: Retains each dice roll. For more information, seeExDiceRoller.Compilers.Roll
.:highest
: Selects the highest of all calculated values when using the,
operator.:lowest
: Selects the lowest of all calculated values when using the,
operator.
Order of Precedence
The following table shows order of precendence, from highest to lowest, of the operators available to ExDiceRoller.
Operator | Associativity | Compiler |
---|---|---|
d | left-to-right | ExDiceRoller.Compilers.Roll |
+ , - | unary | NA (handled by the parser in dice_parser.yrl ) |
* , / , % , ^ | left-to-right | ExDiceRoller.Compilers.Math |
+ , - | left-to-right | ExDiceRoller.Compilers.Math |
, | left-to-right | ExDiceRoller.Compilers.Separator |
Effects of Parentheses
As in math, parentheses can be used to create sub-expressions.
iex> ExDiceRoller.tokenize("1+3d4*1-2/-3") |> elem(1) |> ExDiceRoller.parse()
{:ok,
{{:operator, '-'},
{{:operator, '+'}, {:digit, '1'},
{{:operator, '*'}, {:roll, {:digit, '3'}, {:digit, '4'}}, {:digit, '1'}}},
{{:operator, '/'}, {:digit, '2'}, {:digit, '-3'}}}}
iex> ExDiceRoller.tokenize("(1+3)d4*1-2/-3") |> elem(1) |> ExDiceRoller.parse()
{:ok,
{{:operator, '-'},
{{:operator, '*'},
{:roll, {{:operator, '+'}, {:digit, '1'}, {:digit, '3'}}, {:digit, '4'}},
{:digit, '1'}}, {{:operator, '/'}, {:digit, '2'}, {:digit, '-3'}}}}
iex> ExDiceRoller.tokenize("1+3d(4*1)-2/-3") |> elem(1) |> ExDiceRoller.parse()
{:ok,
{{:operator, '-'},
{{:operator, '+'}, {:digit, '1'},
{:roll, {:digit, '3'}, {{:operator, '*'}, {:digit, '4'}, {:digit, '1'}}}},
{{:operator, '/'}, {:digit, '2'}, {:digit, '-3'}}}}
iex> ExDiceRoller.tokenize("1+3d4*(1-2)/-3") |> elem(1) |> ExDiceRoller.parse()
{:ok,
{{:operator, '+'}, {:digit, '1'},
{{:operator, '/'},
{{:operator, '*'}, {:roll, {:digit, '3'}, {:digit, '4'}},
{{:operator, '-'}, {:digit, '1'}, {:digit, '2'}}}, {:digit, '-3'}}}}
Compiled Rolls
Some systems utilize complex dice rolling equations. Repeatedly tokenizing, parsing, and interpreting complicated dice rolls strings can lead to a performance hit on an application. To ease the burden, developers can compile a dice roll string into an anonymous function. This anonymous function can be passed around as any other function and reused repeatedly without having to re-tokenize the string, nor re-interpret a parsed expression.
iex> {:ok, roll_fun} = ExDiceRoller.compile("2d6+3")
iex> ExDiceRoller.execute(roll_fun)
8
iex> ExDiceRoller.execute(roll_fun)
13
iex> ExDiceRoller.execute(roll_fun)
10
More information can be found in ExDiceRoller.Compiler
.
Variables
Single-letter variables can be used when compiling dice rolls. However, values for those variables must be supplied upon invocation. Values can be any of the following:
- numbers
- expressions, such as “1d6+2”
- compiled dice rolls
results of
~a
sigil, as described inExDiceRoller.Sigil
iex> {:ok, fun} = ExDiceRoller.compile("2d4+x") iex> ExDiceRoller.execute(fun, x: 2) 7 iex> ExDiceRoller.execute(fun, x: "5d100") 245 iex> {:ok, fun_2} = ExDiceRoller.compile("3d8-2") iex> ExDiceRoller.execute(fun, x: fun_2) 23 iex> import ExDiceRoller.Sigil iex> ExDiceRoller.execute(fun, x: ~a/3d5+2d4/) 22
More information can be found in ExDiceRoller.Compilers.Variable
.
Caching
ExDiceRoller can cache and reuse dice rolls.
iex> ExDiceRoller.start_cache()
iex> ExDiceRoller.roll("8d6-(4d5)", [], [:cache])
20
iex> ExDiceRoller.roll("8d6-(4d5)", [], [:cache])
13
iex> ExDiceRoller.roll("1d3+x", [x: 4], [:cache])
6
iex> ExDiceRoller.roll("1d3+x", [x: 1], [:cache, :explode])
6
More details can be found in the documentation for ExDiceRoller.Cache
.
Sigil Support
ExDiceRoller comes with its own sigil, ~a
, that can be used to create
compiled dice roll functions or roll them on the spot.
iex> import ExDiceRoller.Sigil
iex> fun = ~a/2d6+2/
iex> ExDiceRoller.roll(fun)
7
iex> ExDiceRoller.roll(~a|1d4+x/5|, [x: 43])
11
iex> ExDiceRoller.roll(~a|xdy|, [x: fun, y: ~a/12d4-15/])
111
More information can be found in ExDiceRoller.Sigil
.
ExDiceRoller Examples
The following examples show a variety of types of rolls, and includes examples of basic and complex rolls, caching, sigil support, variables, and combinations of thereof.
iex> ExDiceRoller.roll("1")
1
iex> ExDiceRoller.roll("1d8")
1
iex> ExDiceRoller.roll("2d20 + 5")
34
iex> import ExDiceRoller.Sigil
iex> ExDiceRoller.roll(~a/2d8-2/)
3
iex> ExDiceRoller.roll("(1d4)d(6*5) - (2/3+1)")
18
iex> ExDiceRoller.roll("1+2-3*4+5/6*7+8-9")
-4
iex> ExDiceRoller.roll("1+ 2*3d 4")
15
iex> ExDiceRoller.roll("1dx+6-y", x: 10, y: 5)
10
iex> import ExDiceRoller.Sigil
iex> ExDiceRoller.roll(~a/2+5dx/, x: ~a|3d(7/2)|)
19
iex> ExDiceRoller.roll("1d2", [], [:explode])
1
iex> ExDiceRoller.roll("1d2", [], [:explode])
7
iex> ExDiceRoller.start_cache()
iex> ExDiceRoller.roll("1d2+x", [x: 3], [:cache])
4
iex> ExDiceRoller.roll("1d2+x", [x: 3], [:cache, :explode])
10
iex> import ExDiceRoller.Sigil
iex> ~a/1d2+3/r
4
iex> ~a/1d2+2/re
9
Link to this section Summary
Functions
Takes a given expression from parse and calculates the result
Compiles a string or t:expression/0
into an anonymous function
Executes a function built by compile/1
Helper function that calls ExDiceRoller.Tokenizer.tokenize/1
Processes a given string as a dice roll and returns the final result. The final result is a rounded integer
Processes a given string as a dice roll and returns the calculated result. The result is a rounded integer
Starts the underlying roll function cache. See ExDiceRoller.Cache
for more
details
Helper function that calls ExDiceRoller.Tokenizer.tokenize/1
Link to this section Functions
calculate( ExDiceRoller.Parser.expression(), ExDiceRoller.Compiler.args(), ExDiceRoller.Compiler.opts() ) :: number()
Takes a given expression from parse and calculates the result.
compile(String.t() | ExDiceRoller.Parser.expression()) :: {:ok, ExDiceRoller.Compiler.compiled_function()} | {:error, any()}
Compiles a string or t:expression/0
into an anonymous function.
iex> {:ok, roll_fun} = ExDiceRoller.compile("1d8+2d(5d3+4)/3")
iex> ExDiceRoller.execute(roll_fun)
5
If roll
is not a string or expression compile/1 will return
{:error, {:cannot_compile_roll, other}}
.
execute(function(), ExDiceRoller.Compiler.args(), ExDiceRoller.Compiler.opts()) :: integer() | [integer()]
Executes a function built by compile/1
.
parse(ExDiceRoller.Tokenizer.tokens()) :: {:ok, ExDiceRoller.Parser.expression()}
Helper function that calls ExDiceRoller.Tokenizer.tokenize/1
.
Processes a given string as a dice roll and returns the final result. The final result is a rounded integer.
iex> ExDiceRoller.roll("1d6+15")
18
Note that using variables with this call will result in errors. If you need
variables, use roll/3
instead.
roll( String.t() | ExDiceRoller.Compiler.compiled_fun(), ExDiceRoller.Compiler.args(), ExDiceRoller.Compiler.opts() ) :: integer()
Processes a given string as a dice roll and returns the calculated result. The result is a rounded integer.
Any variable values should be specified in args
. Options can be passed in
opts
.
Possible values for opts
include:
:cache
: Performs a cache lookup, with a miss generating a compiled roll that is both cached and returned.ExDiceRoller.Cache.obtain/2
for more information.:explode
: Causes dice to explode. This means that if a die roll results in the highest possible value for a die (such as rolling a 20 on a d20), the die will be rerolled until the result is no longer the max possible. It then sums the total of all rolls and returns that value.:keep
: Retains each dice roll. For more information, seeExDiceRoller.Compilers.Roll
.:highest
: Selects the highest of all calculated values when using the,
operator.:lowest
: Selects the lowest of all calculated values when using the,
operator.
Examples
iex> ExDiceRoller.roll("1d6+15", [])
18
iex> ExDiceRoller.roll("1d8+x", x: 5)
6
iex> ExDiceRoller.roll("1d3", [], [:explode])
5
iex> ExDiceRoller.roll("1d3", [], [:explode])
4
iex> ExDiceRoller.roll("1d3", [], [:explode])
2
iex> ExDiceRoller.start_cache(ExDiceRoller.Cache)
iex> ExDiceRoller.roll("(1d6)d4-3+y", [y: 3], [:cache])
10
iex> ExDiceRoller.roll("1d2+y", [y: 1], [:cache, :explode])
2
iex> ExDiceRoller.roll("1d2+y", [y: 2], [:cache, :explode])
11
iex> ExDiceRoller.roll("1,2", [], [:highest])
2
iex> ExDiceRoller.roll("10,12,45,3,100", [], [:lowest])
3
Starts the underlying roll function cache. See ExDiceRoller.Cache
for more
details.
tokenize(String.t()) :: {:ok, ExDiceRoller.Tokenizer.tokens()}
Helper function that calls ExDiceRoller.Tokenizer.tokenize/1
.