function roll(num, sides, exploding, rerolls) { // Holy SHIT this is a mess. What am I DOING. var result = { "rolled": num + "d" + sides, "total": 0, "dice": [] }, u = []; for(var i = 0; i < num; i++) { var r = Math.ceil(Math.random() * sides); while(rerolls && (r === 1 || u[r])) { r = Math.ceil(Math.random() * sides); } result.total += r; u[r] = true; if(exploding && r === sides) { num++; result.dice.push(String(r) + "!"); } else { result.dice.push(r); } } return result; } function stringify(res) { if(res.total > 0 && res.dice.length > 0) { return "(" + res.rolled + ": " + res.dice.join(", ") + " = " + res.total + ")"; } else { return "(???)"; // whoops fuck } } function parse(str) { var tokens = str.split(/([\+\-\*\/\^])/gi), total = 0, result = [], modo = null; for(var k in tokens) { var tok = tokens[k]; if(/^\d*d\d+\!?$/.test(tok)) { // It's a roll var d = tok.match(/^(\d*)d(\d+)(\!?)$/); if(Number(d[1]) > 0 && Number(d[2]) > 1) { var r = roll(Number(d[1]), Number(d[2]), d[3] === "!", false), s = stringify(r); if(typeof(modo) === "function") { // OPERAAAANDS total = modo(total, r.total); } else { total = r.total; } result.push(s); } else { return "Invalid token at index " + k + " (" + tok + ")"; } } else if(/^[\+\-\*\/\^]$/i.test(tok)) { // It's an operand modo = operands["+-*/^".indexOf(tok)]; result.push(tok); } else if(/^\d+$/.test(tok)) { // It's a number if(typeof(modo) === "function") { total = modo(total, Number(tok)); } else { total = Number(tok); } result.push(tok); } else { return "Invalid token at index " + k + " (" + tok + ")"; } } return result.join(" ") + " for a total of " + String(total); } var operands = [ // +-*/^ function(a, b) { return a+b; }, function(a, b) { return a-b; }, function(a, b) { return a*b; }, function(a, b) { return a/b; }, function(a, b) { return Math.pow(a, b); } ]; module.exports = parse;