Quick start
DicEx.roll("1d20") # => %DicEx.Result{total: 14, ...}
DicEx.roll("3d6 + 2") # => %DicEx.Result{total: 13, ...}
DicEx.roll("2d20kh1") # advantage — keep highest
DicEx.roll("4d6dl1") # 4d6, drop lowest
DicEx.roll("8d6!") # explode (fireball)
DicEx.roll("1d20r1") # reroll natural 1s
# safe variant for untrusted/LLM-generated expressions
{:ok, result} = DicEx.roll_e(prompted_by_the_llm)
# programmatic API matching a UI's "count + die + modifier"
DicEx.roll_dice(2, 20, mod: 5, advantage: true)
# reproducible
DicEx.roll("4d6", seed: 42)Notation reference
| Token | Meaning |
|---|---|
NdS | Roll N dice of S sides (d4..d100) |
kh[n] | Keep highest n (advantage) |
kl[n] | Keep lowest n (disadvantage) |
dh[n] | Drop highest n |
dl[n] | Drop lowest n |
! / !p | Explode / explode & penetrate |
r<op>n | Reroll (< <= = >= >); ro rerolls once |
+ / - | Add / subtract pools or modifiers |
Only +/- compose — there's no *, /, or parentheses.
Reproducible rolls
Seed the default RNG for a reproducible sequence — useful for tests, replays, and anti-cheat:
DicEx.roll("2d20kh1", seed: 42)A note on :seed
:seed reseeds the calling process's :rand state to produce a
reproducible sequence. The prior state is not restored, so in a long-lived
process (e.g. a LiveView) a later unseeded roll/2 continues the seeded
sequence rather than drawing fresh entropy. Thread :rng explicitly when you
need isolation, or re-seed per request.
Summary
Functions
Pretty-prints a result as a human readable string, e.g. "2d20kh1+5 = 23".
Rolls the given expression and returns a DicEx.Result.
Convenience for a single typed roll — the shape the dragonEx UI emits.
Like roll/2 but returns {:ok, result} or {:error, reason} without
raising. Handy when the expression comes from untrusted input (e.g. a chat
command parsed by an LLM in dragonEx).
Types
Functions
@spec format(DicEx.Result.t()) :: String.t()
Pretty-prints a result as a human readable string, e.g. "2d20kh1+5 = 23".
@spec roll(binary(), [roll_opt()]) :: DicEx.Result.t()
Rolls the given expression and returns a DicEx.Result.
Options
:seed— integer seed for the default RNG (reproducible sequence).:rng— an explicit RNG module (stateless) or{module, state}tuple.
@spec roll_dice(pos_integer(), pos_integer(), keyword()) :: DicEx.Result.t()
Convenience for a single typed roll — the shape the dragonEx UI emits.
DicEx.roll_dice(2, 20) # 2d20
DicEx.roll_dice(1, 20, mod: 5) # 1d20 + 5Options
:mod— integer modifier added to the total (+/-).:advantage— boolean, keeps highest of 2 (implies 2 dice ifcount==1).:disadvantage— boolean, keeps lowest of 2.- Plus any option accepted by
roll/2(:seed,:rng).
@spec roll_e(binary(), [roll_opt()]) :: {:ok, DicEx.Result.t()} | {:error, String.t()}
Like roll/2 but returns {:ok, result} or {:error, reason} without
raising. Handy when the expression comes from untrusted input (e.g. a chat
command parsed by an LLM in dragonEx).