ExDiceRoller v0.2.0-alpha ExDiceRoller

Converts strings into dice rolls and returns expected results. Ignores any spaces, including tabs and newlines, in the provided string.

Examples

iex> ExDiceRoller.roll("1")
1

iex> ExDiceRoller.roll("1d8")
1

iex> ExDiceRoller.roll("2d20 + 5")
34

iex> ExDiceRoller.roll("2d8 + -5")
0

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

Order of Precedence

The following table shows order of precendence, from highest to lowest, of the operators available to ExDiceRoller.

OperatorAssociativity
dleft-to-right
+, -unary
*, /left-to-right
+, -left-to-right

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 cached and reused repeatedly without having to re-parse the string, nor re-interpret the 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
iex> ExDiceRoller.execute(roll_fun)
11

Link to this section Summary

Functions

Takes a given expression from parse and calculates the result

Compiles a string or expression/0 into an anonymous function

Executes a function built by compile/1

Converts a series of tokens provided by tokenize/1 and parses them into an expression structure. This expression structure is what’s used by the dice rolling functions to calculate rolls. The BNF grammar definition file is located at src/dice_parser.yrl

Processes a given string as a dice roll and returns the final result. Note that the final result is a rounded integer

Converts a roll-based string into tokens using leex. The input definition file is located at src/dice_lexer.xrl. See token_type/0, token/0, and tokens/0 for the possible return values

Link to this section Types

Link to this type expression()
expression() ::
  {:digit, list()}
  | {{:operator, list()}, expression(), expression()}
  | {:roll, expression(), expression()}
Link to this type token()
token() :: {token_type(), integer(), list()}
Link to this type token_type()
token_type() ::
  :digit | :basic_operator | :complex_operator | :roll | :"(" | :")"
Link to this type tokens()
tokens() :: [token(), ...]

Link to this section Functions

Link to this function calculate(expression)
calculate(expression()) :: integer() | float()

Takes a given expression from parse and calculates the result.

Link to this function compile(roll_string)
compile(String.t() | expression()) ::
  {:ok, ExDiceRoller.Compiler.compiled_function()} | {:error, any()}

Compiles a string or expression/0 into an anonymous function.

iex> {:ok, roll_fun} = ExDiceRoller.compile("1d8+2d(5d3+4)/3")
iex> ExDiceRoller.execute(roll_fun)
5.0
Link to this function execute(compiled)
execute(function()) :: integer() | float()

Executes a function built by compile/1.

Link to this function parse(tokens)
parse(tokens()) :: {:ok, expression()}

Converts a series of tokens provided by tokenize/1 and parses them into an expression structure. This expression structure is what’s used by the dice rolling functions to calculate rolls. The BNF grammar definition file is located at src/dice_parser.yrl.

iex> {:ok, tokens} = ExDiceRoller.tokenize("2d8 + (1+2)")
{:ok,
[
  {:digit, 1, '2'},
  {:roll, 1, 'd'},
  {:digit, 1, '8'},
  {:basic_operator, 1, '+'},
  {:"(", 1, '('},
  {:digit, 1, '1'},
  {:basic_operator, 1, '+'},
  {:digit, 1, '2'},
  {:")", 1, ')'}
]}
iex> {:ok, _} = ExDiceRoller.parse(tokens)
{:ok,
{{:operator, '+'}, {:roll, {:digit, '2'}, {:digit, '8'}},
  {{:operator, '+'}, {:digit, '1'}, {:digit, '2'}}}}
Link to this function roll(roll_string)
roll(String.t()) :: integer()

Processes a given string as a dice roll and returns the final result. Note that the final result is a rounded integer.

iex> ExDiceRoller.roll("1d6+15")
18
Link to this function tokenize(roll_string)
tokenize(String.t()) :: {:ok, tokens()}

Converts a roll-based string into tokens using leex. The input definition file is located at src/dice_lexer.xrl. See token_type/0, token/0, and tokens/0 for the possible return values.

iex> ExDiceRoller.tokenize("2d8+3")
{:ok,
[
  {:digit, 1, '2'},
  {:roll, 1, 'd'},
  {:digit, 1, '8'},
  {:basic_operator, 1, '+'},
  {:digit, 1, '3'}
]}