Write a function that accepts string as a parameter, returning evaluated value of expression in dice notation, including addition and multiplication.
To
Clojure, 854 characters as is, 412 shrunk
Just run "(roll-dice "input-string")".
(defn roll-dice
[string]
(let [parts (. (. (. string replace "-" "+-") replaceAll "\\s" "") split "\\+")
dice-func (fn [d-notation]
(let [bits (. d-notation split "d")]
(if (= 1 (count bits))
(Integer/parseInt (first bits)) ; Just a number, like 12
(if (zero? (count (first bits)))
(inc (rand-int (Integer/parseInt (second bits)))) ; Just d100 or some such
(if (. (first bits) contains "*")
(* (Integer/parseInt (. (first bits) replace "*" ""))
(inc (rand-int (Integer/parseInt (second bits)))))
(reduce +
(map #(+ 1 %)
(map rand-int
(repeat
(Integer/parseInt (first bits))
(Integer/parseInt (second bits)))))))))))]
(reduce + (map dice-func parts))))
To shrink, I made variables 1 letter, moved the (first bits)/(second bits) into variables, made dice-func an anonymous function, made a wrapper for Integer.parseInt called 'i', and stripped out comments and extra whitespace.
This should work on anything valid, with or without whitespace. Just don't go asking it for "15dROBERT", it will throw an exception.
They way it works is by splitting up the string into dice (that's the 3rd line, the let). So "5d6+2*d4-17" becomes "5d6","2*d4","-17".
Each of those is then processed by the function dice-func, and the results are added up (this is the map/reduce on the last line)
Dice-func takes a little dice string (such a "5d6") and splits it on the "d". If there is only one part left, it was a simple number (6, -17, etc).
If the first part contains a *, we multiply that number by a random interger, 1 to (number after d), inclusive.
If the first part doesn't contain a *, we take first number random rolls (just like previous line) and add them up (this is the map/reduce in the middle).
This was fun little challenge.