So I want to be able to parse, and evaluate, "dice expressions" in C#. A dice expression is defined like so:
<expr> := <expr> + <expr>
| <expr> - <expr>
| [<number>]d(<number>|%)
| <number>
<number> := positive integer
So e.g. d6+20-2d3
would be allowed, and should evaluate as
rand.Next(1, 7) + 20 - (rand.Next(1, 4) + rand.Next(1, 4))
Also d%
should be equivalent to d100
.
I know I could hack together some solution, but I also know that this seems like a very typical computer-science type problem, so there must be some super-elegant solution I should look into.
I'd like the result of my parsing to have these capabilities:
- I should be able to output a normalized form of the expression; I'm thinking dice first, sorted by dice size, and always with a prefix. So e.g. the above sample would become
1d6-2d3+20
. Also any instances ofd%
would becomed100
in the normalized form. - I should be able to evaluate the expression at-will, rolling different random numbers each time.
- I should be able to evaluate the expression with all of the dice-rolls maximized, so e.g. the sample above would give (deterministically)
1*6+20+2*3 = 32
.
I know that this is exactly the type of thing Haskell, and probably other functional-type languages, would be great at, but I'd like to stay in C# if possible.
My initial thoughts tend toward recursion, lists, and maybe some LINQ, but again, if I tried without some pointers from people who know things, I'm sure it'd end up being an inelegant mess.
Another tactic that might work would be some initial regex-based string-replacement to turn dice expressions into rand.Next
calls, and then on-the-fly evaluation or compilation... would this actually work? How could I avoid creating a new rand
object every time?