# The Bones Dice Rolling Language

## Synopsis

Bones is a highly-expressive functional dice rolling language. Bones is capable of handling any dice rolling mechanism which could reasonably be carried out by players of any game (plus many which couldn't). Every expression in Bones is either a scalar (an integer or variable) or a list of scalars.

## Quick Start

Single die rolls may be made using the '`d`' operator, followed by the number of faces on the die to be rolled. E.g., `d6` will roll a single six-sided die, and `d2` will flip a coin. Expressions may be modified by the standard arithmetic operators. `d10-1` will yield a value between 0 and 9, inclusive. In order to roll multiple dice of the same type, use the repetition operator '`#`'. `2#d6` will roll two six-sided dice; this is not the same as `2*d6`, which rolls only a single die but multipies the result by two, or `2d6` which will cause a syntax error. In order to get the sum of two six-sided dice, do `sum(2#d6)`.

## Syntax

Valid expressions in Bones are defined as follows:

`<integer> ::=`
`-?[0-9]+`
`<variable> ::=`
`[A-Za-z]+`
`<scalar> ::=`
```<integer> | <variable> | -<scalar> | <scalar> + <scalar> | <scalar> - <scalar> | <scalar> * <scalar> | <scalar> / <scalar> | <scalar> % <scalar> | <scalar> ^ <scalar> | <scalar> . <scalar> | d<scalar> | sum <expr>  | prod <expr>  | count <expr> ```
`<list> ::=`
```<scalar> # <expr> | <scalar> .. <scalar> | <expr> , <expr> | perm <expr> | sort <expr> | rev <expr> | (drop|keep)? low <scalar> <expr> | (drop|keep)? high <scalar> <expr> | (drop|keep)? first <scalar> <expr> | (drop|keep)? last <scalar> <expr> | (drop|keep)? == <scalar> <expr> | (drop|keep)? != <scalar> <expr> | (drop|keep)? < <scalar> <expr> | (drop|keep)? > <scalar> <expr> | (drop|keep)? <= <scalar> <expr> | (drop|keep)? >= <scalar> <expr> | let <variable> = <expr> in <expr> | while <variable> = <expr> do <expr> | foreach <variable> in <expr> do <expr> | if <expr> then <expr> else <expr>```
`<expr> ::=`
`<scalar>| <list>`

Whitespace between expressions is permitted, and required only between consecutive integers, variables, or alphabetic operators. Comments maybe be inserted into expressions by prepending double slashes ("`//`") to them:

```sum(10#d6) +   // this is a comment
7
```

Comments run to the ends of the lines on which they appear, as in the programming language C++. Parentheses ("`(`", "`)`") may be used to enclose any expression as needed to indicate order of operations. `5+d(d10+1)` is properly parenthesized, while `high(1 4#d6)` is not, because `(1 4#d6)` is not a valid expression. An empty list may be specified with an empty pair of parentheses: `( )`. Any alphabetic string which does not conflict with a keyword may be used as a variable name. In particular, the lowercase '`d`' may not be used as a variable name, as it would conflict with the die roll operator.

## Semantics

### Operators

`+`
`-`
`*`
`/`
`^`
These are the familiar binary arithmetic operators for addition, subtraction, multiplication, division, and exponentiation. Division rounds toward zero. Examples: `5+7`, `d6-1`, `2^10`
`-`
This is the unary minus operator. Examples: `-1`
`%`
This is the modulus operator. `x % y` gives the remainder of `x` divided by `y`. Examples: `11%2`, `d6%3`
`.`
This is the scalar concatenation operator. `x . y` gives `xy`, the concatenation of `x` and `y`. Examples: `-10.9`, `d6.d6`
`d`
This is the die roll operator. `dn` gives the value of a single roll of an `n`-sided die. Examples: `d6`, `2#d6`
`sum`
`prod`
These are the extended sum and product operators. If `e` is an expression, `sum e` and `prod e` give the sum of the members of `e` and the product of the members of `e`, respectively. Examples: `sum(1..100)`, `prod(3#d6)`
`count`
This is the list size operator. If `e` is an expression, then `count e` gives the number of members of `e`. Examples: `count(1,2,3)`, `count(== 6 10#d6)`
`#`
This is the list repetition operator. If `n` is a nonnegative scalar and `e` is an expression, then `n#e` is a list containing the results of `n` evaluations of `e`. Examples: `10#8`, `3#d10`
`..`
This is the range operator. If `x` and `y` are scalars, then `x..y` is a list consisting of the interval `[x,y]`. If `x>y`, then the resulting list is empty. Examples: `1..10`, `4..d10`
`,`
This is the list concatenation operator. `v,u` gives the list consisting of all of the members of `v`, followed by all of the members of `u`. Examples: `1,2`, `4,(3#d6)`
`sort`
This is the list sorting operator. `sort e` sorts the list `e` in ascending order. Examples: `sort(10#d6)`
`perm`
This is the list permutation operator. `sort e` results in a random permutation of the list `e`. Use `perm` to shuffle a list. Examples: `perm(1..52)`
`rev`
This is the list reversal operator. `rev e` results in a list with the same members as the list `e`, but in reverse order. Examples: `rev(1..10)`, `rev sort(10#d8)`
`low`
`high`
These operators act as filters by finding the least and greatest values in lists. If `n` is a nonnegative scalar and `e` is an expression, then `low n e` gives the `n` least members of `e`, and `high n e` gives the `n` greatest members of `e`. Examples: `high 3 5#d6`
`first`
`last`
These operators act as filters by finding initial and final segments of lists. If `n` is a nonnegtive scalar and `e` is an expression, then `first n e` gives the first `n` members of `e`, and `last n e` gives the last `n` members of `e`. Examples: `first 3 (1..10)`
`==`
`!=`
`<`
`>`
`<=`
`>=`
These operators act as filters by finding values in lists which meet given conditions. If `x` is a scalar and `e` is an expression, then `== x e` gives the list of members of `e` equal to `x`; `!= x e` gives the list of members of `e` not equal to `x`; `< x e` gives the list of members of `e` less than `x`; `> x e` gives the list of members of `e` greater than `x`; `<= x e` gives the list of members of `e` less than or equal to `x`; `>= x e` gives the list of members of `e` greater than or equal to `x`. Examples: `>= 3 5#d6`
`drop`
`keep`
These operators modify filters on lists. If `fop` is a filter operation on an expression `e`, then `keep fop e` has the same result as `fop e` and `drop fop e` evaluates to `e` less `keep fop e`. In other words, `drop` negates filter conditions, and `keep` affirms them. `keep` is never necessary and exists only for symmetry. Examples: `sum(drop low 1 4#d6)`
`let`
This is the variable assignment and substitution operator. If `x` is a variable and `e` and `f` are an expressions, then `let x = e in f` gives the list which results from evaluating `f` with the value of `e` substituted for every occurance of `x` in `f`. Evaluation of `e` is done prior to substitution. Examples: `let x = d6 in x*x`
`foreach`
This is the bounded iteration operator. If `x` is a variable and `e` and `f` are expressions, then `foreach x in e do f` gives the list which results from assigning to `x` each of the members of `e` and evaluating `f`. Examples: `foreach x in c do x+1 `
`while`
This is the unbounded iteration operator. If `x` is a variable and `e` and `f` are expressions, then `while x = e do f` is the list `v0,v1,...,vn`, where `v0` is the result of evaluating `e` and `vi+1` is the result of assigning `vi` to `x` and evaluating `f`, stopping at the first `vi` which is empty. Examples: `while x=d6 do ((count <6 x)#d6)`
`if`
This is the branching operator. If `e`, `f`, and `g` are expressions, then `if e then f else g` gives `f` if `e` is nonempty, and `g` otherwise. Examples: `if count(>4 2#d6) then 1 else 0`

### Operator Precedence

PrecedenceOperatorAssociativity
1`d`right
2`^`right
3`#`right
4`sum` `prod` `count` `low` `high`none
5`- (unary)`right
6`*` `/` `%`left
7`+` `-` `.`left
8`==` `!=` `<` `>` `<=` `>=`none
9`,`right
10`..`none
11`in` `while` `do` `else`none

## Examples

• Count the number of dice greater than 7:
```count >7 5#d10
```
• Count the number of dice greater than 7 minus the number of dice equal to 1:
```let c=5#d10 in (count >7 c)-(count ==1 c)
```
• Count the number of rolls until a 6 is rolled:
```count (while x=d6 do ((count <6 x)#d6))
```
• Count the number of rolls until a 6 is rolled, more efficiently:
```count (while x=(d6/6) do ((count <1 x)#(d6/6)))
```
• Roll attributes for a new D&D character:
```6#sum(drop low 1 4#d6)
```
• Roll on the 11..66 morale check table in The Gamers' Civil War Brigade Series:
```d6.d6
```
• Find the median of 3 d20s:
`high 1 low 2 3#d20`
• 3d6 with rerolls on 6s:
`sum(while x=3#d6 do ((count ==6 x)#d6))`
• Roll 7 d10 and find the largest sum of identical dice:
`let x = 7#d10 in high 1 (foreach y in 1..10 do sum (==y x))`
• The Fibonacci sequence is defined by `Fn = Fn-1 + Fn-2`, with `F1 = F2 = 1`. Calculate the first twenty Fibonacci numbers:
```let n = 20 in
let f = (1,1) in
foreach i in 1..n do
let f = (f,sum(high 2 f)) in
if ==n i then f else ()
```
• Risk has battles where the attacker rolls 3d6 and the defender rolls 2d6. The highest attacker die is matched with the highest defender die and the second highest attacker die to the second highest defender die. For both matches, the highest wins, with ties going to the defender. The number of attacker wins:
```let a = 3#d6 in
let b = 2#d6 in
count( (<(high 1 a) high 1 b),
(<(high 1 low 2 a) low 1 b))
```
• Storyteller die roll with target number 8 and botches indicated at -1:
```let c=5#d10 in
let succs = count >7 c in
let ones = count ==1 c in
if >0 succs then high 1 (0,succs-ones)
else if >0 ones then -1 else 0
```
• Combat in Silent Death is rather complex. Three dice are rolled. If their sum is above a target, the roll is a hit. To calculate damage, the same dice are sorted. If all three are equal, all are summed to yield the damage. If the least two are equal, but the third is higher, the high die is the damage. If the two highest are equal, but the third is lower, the two high dice are summed to yield the damage. If all three dice are different, the middle die is the damage. This example assumes that the dice are two d8s and a d10, with a target number of 15:
```let x = 2#d8,d10 in
(count >15 sum x)#
let a = low 1 x in               // low die
let b = high 1 low 2 x in        // middle die
let c = high 1 x in              // high die
if ==a ==b c then a+b+c       // all equal
else if ==a <c b then c       // two low equal
else if >a ==c b then b+c     // two high equal
else b                        // all different
```

## Bugs & Features

If you find a bug in Bones or have an idea for a feature, please email Joel Uckelman.

## Author

Bones is written by Joel Uckelman, based on the Roll language devised by Torben Mogensen. This documentation contains examples adapted from the Roll documentation.