The Pit-Marshal's Bone Dice
Posted by the Pit-Marshals of the Corvane Arena
Before every bout in the sand pits of Corvane, each champion's strike is written on a slate as a dice formula. It is then settled with carved bone dice in front of the crowd. The bookmakers will not take a single wager until a marshal has declared the lowest and highest result that formula could possibly produce. The marshals are tired of arguing it out by hand. Write the reckoner that declares the range.
The formula
formula is a string built from these parts:
- Integer literals: one or more digits, such as
7or12. They are never negative on their own. - Dice terms:
NdM, whereNandMare positive integers written in digits anddis a lowercase letter.Nmay be omitted, sodMmeans1dM. A dice term stands for rollingNdice, each with faces1throughM, and summing them. There are no spaces inside a literal or a dice term. - Binary operators:
+,-and*. - Unary minus: a
-that appears where a value is expected. This is at the start of the formula, directly after(, or directly after another operator. It negates the value that follows it. - Parentheses
(and)for grouping. - Spaces, which may appear between any of the parts above and carry no meaning.
The rules of precedence:
- Unary minus binds tightest.
*binds tighter than binary+and-.- Binary
+,-and*are all left-associative, so3 - 2 - 1means(3 - 2) - 1.
Every dice term in the formula is rolled separately and independently, even if the same term is written more than once. The formula is always well-formed.
The task
Write diceRange(formula). Consider every possible combination of die faces. It returns a list of two integers, [lowest, highest]: the smallest and largest value the formula can evaluate to.
examples
- case 1
formula of "2d6 - d4"[-2, 11] (2 - 4 at the low end, 12 - 1 at the high end) - case 2
formula of "(d4 - 3) * (d4 - 3)"[-2, 4] (the two d4s are rolled separately, so one factor can be -2 while the other is 1) - case 3
formula of "3 - 2 - 1"[0, 0] (subtraction groups from the left) - case 4
formula of "1d100 - (d10 * -d10)"[2, 200]
- reward
- 540 XP
- signature
diceRange
TypeScript, run as ES2022 — types are stripped, not checked. If a JS engine would run it, so will we.
- single dice term
- omitted count plus literal
- subtracting a dice term swaps its ends
- independent factors crossing zero
- unary minus then multiply
- bare literal
- left associative subtraction
- multiplication before addition
- double unary minus
- one-faced dice times negative group
- symmetric ranges multiplied
- nested negative product subtracted
- zero times negated dice
- multi-digit counts and faces
- spaces around a parenthesised literal
- unary minus on a group