Skip to main content

DEL Specification for AI Systems

Machine-readable specification for the Dice Expression Language. Optimized for language models and AI assistants.

# DICE EXPRESSION LANGUAGE (DEL) SPECIFICATION
# Version: 1.0
# Purpose: AI-readable specification for parsing and understanding DEL expressions
# Target: Language models, AI assistants, code generators

================================================================================
OVERVIEW
================================================================================

DEL (Dice Expression Language) is a domain-specific language for expressing 
tabletop RPG dice mechanics. It supports dice notation, arithmetic, comparisons,
conditionals, and mathematical functions.

All arithmetic uses INTEGER MATH. Division floors the result.

================================================================================
GRAMMAR (EBNF-style)
================================================================================

expression     → conditional
conditional    → comparison ( "?" expression ":" expression )?
comparison     → sum ( ( "==" | "!=" | "<" | "<=" | ">" | ">=" ) sum )?
sum            → product ( ( "+" | "-" ) product )*
product        → power ( ( "*" | "/" | "%" ) power )*
power          → unary ( "^" unary )*
unary          → ( "-" )? call
call           → IDENTIFIER "(" arguments? ")" | primary
arguments      → expression ( "," expression )*
primary        → NUMBER | dice | "(" expression ")"
dice           → NUMBER? "d" NUMBER modifiers*

================================================================================
TOKEN TYPES
================================================================================

NUMBER     → [0-9]+                    (integers only, no decimals)
IDENTIFIER → [a-z]+                    (function names: min, max, abs, floor, ceil, median)
OPERATOR   → + | - | * | / | % | ^ | == | != | < | <= | > | >= | ? | :
PAREN      → ( | )
COMMA      → ,
DICE       → [0-9]*d[0-9]+             (e.g., d20, 3d6, 10d10)

================================================================================
DICE NOTATION
================================================================================

Format: NdX
- N = number of dice (optional, defaults to 1)
- d = literal character 'd'
- X = number of sides on each die

Examples:
  d20      → roll 1 twenty-sided die (implicit N=1)
  1d20     → roll 1 twenty-sided die (explicit)
  3d6      → roll 3 six-sided dice and sum
  4d4      → roll 4 four-sided dice and sum
  10d10    → roll 10 ten-sided dice and sum

Each die produces a uniformly random integer in range [1, X].
The base result is the SUM of all dice rolled.

================================================================================
DICE MODIFIERS
================================================================================

Modifiers are appended directly after dice notation (no spaces).
They are processed in this FIXED ORDER regardless of how they're written:
  1. Reroll
  2. Explode
  3. Keep/Drop
  4. Sort
  5. Success Count

--------------------------------------------------------------------------------
KEEP MODIFIERS
--------------------------------------------------------------------------------

kh<N>  → Keep Highest N dice, sum only those
kl<N>  → Keep Lowest N dice, sum only those
dh<N>  → Drop Highest N dice, sum the rest
dl<N>  → Drop Lowest N dice, sum the rest

Examples:
  4d6kh3   → Roll 4d6, keep the 3 highest, sum them (D&D ability scores)
  2d20kh1  → Roll 2d20, keep highest 1 (D&D advantage)
  2d20kl1  → Roll 2d20, keep lowest 1 (D&D disadvantage)
  5d10dh1  → Roll 5d10, drop the highest, sum remaining 4
  3d8dl1   → Roll 3d8, drop the lowest, sum remaining 2

--------------------------------------------------------------------------------
EXPLODE MODIFIER
--------------------------------------------------------------------------------

!          → Explode on maximum value (roll again if max, can chain)
!<N>       → Explode on exactly N
!<OP><N>   → Explode when comparison is true

Comparison operators: = | == | != | < | <= | > | >=

Each exploded die can trigger another explosion (recursive).
Implementation should cap recursion to prevent infinite loops (typically 100).

Examples:
  2d6!      → Roll 2d6, each 6 adds another d6 (can chain)
  d20!      → Roll d20, 20s add another d20
  4d10!10   → Roll 4d10, explode on exactly 10
  5d8!>=7   → Roll 5d8, explode on 7 or 8
  3d6!<=2   → Roll 3d6, explode on 1 or 2

--------------------------------------------------------------------------------
REROLL MODIFIER
--------------------------------------------------------------------------------

r<OP><N>   → Reroll WHILE condition is true (can reroll same die multiple times)
ro<OP><N>  → Reroll ONCE if condition is true (maximum one reroll per die)

Comparison operators: = | == | != | < | <= | > | >=

Examples:
  4d6r=1    → Roll 4d6, keep rerolling any 1s until no 1s remain
  4d6ro=1   → Roll 4d6, reroll 1s at most once per die
  6d10r<=2  → Roll 6d10, keep rerolling while result <= 2
  3d8ro<3   → Roll 3d8, reroll once any die showing < 3

--------------------------------------------------------------------------------
SORT MODIFIER
--------------------------------------------------------------------------------

sa         → Sort Ascending (display order only, does not affect sum)
sd         → Sort Descending (display order only, does not affect sum)

Examples:
  5d6sa     → Roll 5d6, display sorted low to high
  4d8sd     → Roll 4d8, display sorted high to low

--------------------------------------------------------------------------------
SUCCESS COUNT MODIFIER
--------------------------------------------------------------------------------

cs<OP><N>  → Count Successes: return COUNT of dice meeting condition (not sum)
cf<OP><N>  → Count Failures: return COUNT of dice meeting condition (not sum)

When cs or cf is used, the dice expression returns a COUNT instead of a SUM.

Comparison operators: = | == | != | < | <= | > | >=

Examples:
  10d10cs>=8   → Roll 10d10, count how many are >= 8 (World of Darkness)
  8d6cs>=5     → Roll 8d6, count how many are 5 or 6
  5d10cf<=3    → Roll 5d10, count how many are <= 3
  12d6cs=6     → Roll 12d6, count only the 6s

--------------------------------------------------------------------------------
COMBINING MODIFIERS
--------------------------------------------------------------------------------

Multiple modifiers can be chained. They execute in fixed order:
reroll → explode → keep/drop → sort → success count

Examples:
  4d6ro=1kh3        → Reroll 1s once, then keep highest 3
  6d10!ro<=2kh4     → Explode 10s, reroll <=2 once, keep top 4
  10d6!>=6cs>=4     → Explode 6s, then count 4+ as successes
  5d8ro=1sacs>=5    → Reroll 1s once, sort ascending, count 5+ successes

================================================================================
ARITHMETIC OPERATORS
================================================================================

Operator  Precedence  Associativity  Description
--------  ----------  -------------  -----------
    +         1        Left          Addition
    -         1        Left          Subtraction
    *         2        Left          Multiplication
    /         2        Left          Integer division (floor)
    %         2        Left          Modulo (remainder)
    ^         3        Right         Exponentiation (power)

All operations produce integers. Division truncates toward negative infinity.

Examples:
  5 + 3        → 8
  10 - 4       → 6
  3 * 7        → 21
  17 / 5       → 3 (integer division)
  17 % 5       → 2 (remainder)
  2 ^ 10       → 1024

================================================================================
COMPARISON OPERATORS
================================================================================

Return 1 for true, 0 for false.

Operator  Description
--------  -----------
   ==     Equal to
   !=     Not equal to
   <      Less than
   <=     Less than or equal
   >      Greater than
   >=     Greater than or equal

Examples:
  5 > 3      → 1 (true)
  3 == 3     → 1 (true)
  5 != 5     → 0 (false)
  10 < 5     → 0 (false)

================================================================================
TERNARY CONDITIONAL
================================================================================

Format: condition ? value_if_true : value_if_false

The condition is evaluated. If non-zero (truthy), returns the first value.
If zero (falsy), returns the second value.

Examples:
  10 > 5 ? 100 : 0           → 100 (condition is true)
  3 > 5 ? 100 : 0            → 0 (condition is false)
  1d20 >= 15 ? 1d8+3 : 0     → Roll d20, if >=15 then roll 1d8+3, else 0
  1d20 == 20 ? 2d8 : 1d8     → Critical hit logic: nat 20 = 2d8, else 1d8

Nested conditionals:
  1d20 == 20 ? 2d8+5 : 1d20 >= 15 ? 1d8+5 : 0
  → Crit on 20 (2d8+5), hit on 15+ (1d8+5), miss otherwise (0)

================================================================================
BUILT-IN FUNCTIONS
================================================================================

All functions use parentheses and comma-separated arguments.

--------------------------------------------------------------------------------
min(a, b, ...)
--------------------------------------------------------------------------------
Returns the minimum value among all arguments.
Accepts 2 or more arguments.

Examples:
  min(5, 3)           → 3
  min(4d6, 20)        → Roll 4d6 or 20, whichever is lower (damage cap)
  min(10, 20, 5, 15)  → 5

--------------------------------------------------------------------------------
max(a, b, ...)
--------------------------------------------------------------------------------
Returns the maximum value among all arguments.
Accepts 2 or more arguments.

Examples:
  max(5, 3)           → 5
  max(2d6, 8)         → Roll 2d6 or 8, whichever is higher (minimum damage)
  max(1, 2, 3, 4)     → 4

--------------------------------------------------------------------------------
abs(x)
--------------------------------------------------------------------------------
Returns the absolute value of x.
Accepts exactly 1 argument.

Examples:
  abs(-5)       → 5
  abs(5)        → 5
  abs(3 - 10)   → 7

--------------------------------------------------------------------------------
floor(x)
--------------------------------------------------------------------------------
Returns the floor of x (round down toward negative infinity).
Note: Division already floors in DEL, so this is rarely needed.
Accepts exactly 1 argument.

Examples:
  floor(7)      → 7
  floor(-3)     → -3

--------------------------------------------------------------------------------
ceil(x)
--------------------------------------------------------------------------------
Returns the ceiling of x (round up toward positive infinity).
Since DEL uses integers, this is mainly for explicit documentation.
Accepts exactly 1 argument.

Examples:
  ceil(7)       → 7
  ceil(-3)      → -3

--------------------------------------------------------------------------------
median(a, b, c, ...)
--------------------------------------------------------------------------------
Returns the median (middle value) of the arguments.
If even number of arguments, returns the lower middle value.
Accepts 1 or more arguments.

Examples:
  median(1, 5, 3)                      → 3 (middle of sorted [1, 3, 5])
  median(1, 2, 3, 4)                   → 2 (lower middle of [1, 2, 3, 4])
  median(1d20, 1d20, 1d20)             → Middle of 3 d20 rolls
  median(2d6, 2d6, 2d6)                → Roll 3 sets of 2d6, take middle sum

================================================================================
OPERATOR PRECEDENCE (highest to lowest)
================================================================================

1. Parentheses ()           - Grouping
2. Function calls           - min(), max(), abs(), floor(), ceil(), median()
3. Unary minus              - Negation (e.g., -5)
4. Exponentiation ^         - Right associative
5. Multiplication * / %     - Left associative
6. Addition + -             - Left associative
7. Comparison == != < <= > >= - Left associative
8. Ternary ? :              - Right associative

================================================================================
PRACTICAL EXAMPLES BY GAME SYSTEM
================================================================================

D&D 5th Edition:
  1d20 + 5                    → Attack roll with +5 modifier
  2d20kh1 + 3                 → Advantage: keep higher d20, add +3
  2d20kl1 + 3                 → Disadvantage: keep lower d20, add +3
  4d6kh3                      → Ability score generation (drop lowest)
  4d6ro=1kh3                  → Generous ability scores (reroll 1s once)
  8d6                         → Fireball damage
  1d20 >= 15 ? 1d8+5 : 0      → Attack: hit on 15+, deal 1d8+5
  1d20 == 20 ? 4d6 : 2d6      → Crit doubles dice (approximation)

World of Darkness / Storyteller:
  10d10cs>=8                  → Roll pool, count 8+ as successes
  7d10!cs>=8                  → Explode on 10s, count successes
  7d10!>=10cs>=8              → Explicit: explode on 10+, count 8+

Shadowrun:
  12d6cs>=5                   → Roll 12d6, count 5-6 as hits

Savage Worlds:
  1d6! + 1d8!                 → Trait die + Wild die, both explode
  max(1d6!, 1d8!)             → Take better of exploding dice

Custom Mechanics:
  max(2d6, 8)                 → Minimum 8 damage guarantee
  min(10d6, 50)               → Roll 10d6, cap at 50
  3d6 >= 10 ? 2d6 : 1d6       → Conditional bonus damage
  abs(1d6 - 1d6)              → Difference between two rolls

================================================================================
ERROR CONDITIONS
================================================================================

These inputs should produce parse or evaluation errors:

- Empty expression: ""
- Invalid syntax: "3d" (missing sides), "d" (incomplete dice)
- Division by zero: "10 / 0"
- Invalid modifier: "3d6xx" (unknown modifier)
- Unclosed parentheses: "(3 + 5"
- Missing operand: "3 + * 2"
- Invalid function: "foo(3)" (unknown function)
- Wrong arity: "abs(1, 2)" (abs takes 1 arg)

================================================================================
IMPLEMENTATION NOTES
================================================================================

1. Dice rolls should use cryptographically secure random or high-quality PRNG
2. Exploding dice should cap recursion (suggest 100 iterations max)
3. Keep/drop with N > dice count: keep/drop all available dice
4. All arithmetic is integer-based; no floating point
5. Comparison operators in modifiers can use = as shorthand for ==
6. Negative numbers are supported: -5, -(3+2)
7. Parentheses can be nested arbitrarily deep

================================================================================
API USAGE
================================================================================

To evaluate a DEL expression via the Tactical Dice API:

POST /v1/dice/evaluate
Content-Type: application/json

{
  "expression": "4d6kh3"
}

Response:
{
  "result": 14,
  "rolls": [6, 5, 3, 2],
  "kept": [6, 5, 3],
  "expression": "4d6kh3"
}

================================================================================
END OF SPECIFICATION
================================================================================

© 2026 Tactical Dice. This specification is provided for AI systems to understand and generate valid DEL expressions.