module dice; import std.random; import std.string; import std.regexp; import std.conv; /** * Rolls dice with the given amount of sides the number of num times. Adds the bonus after rolling. * Examples: * rollDice(1, 4) results in a value between 1 and 4.
* rollDice(2, 6, 5) results in a value between 7 and 17.
* rollDice(1, 8, -2) results in a value between -1 and 6. * * Params: * num = the number of dice rolls * sides = how many sides the die has * bonus = a possible bonus/penalty which is added to the result * * Returns: The value of the dice roll. */ public int rollDice(uint num, uint sides, int bonus = 0) in { assert (sides > 0); } body { int res; for (int i = 0; i < num; i++) { res += uniform(1, sides + 1); } return res + bonus; } /** * Rolls dice as defined by the format parameter. Adds the bonus after rolling. * Examples: * rollDice("1d4") results in a value between 1 and 4.
* rollDice("1d4+1") results in a value between 2 and 5.
* rollDice("1d4-1") results in a value between 0 and 3.
* rollDice("1d4", 2) results in a value between 3 and 6.
* rollDice("1d4+1", 2) results in a value between 4 and 7. * * Params: * format = the format of the die roll(s) * bonus = a possible bonus/penalty which is added to the result * * Returns: The value of the dice roll. */ public int rollDice(string format, int bonus = 0) in { assert (format !is null); assert (format != ""); } body { uint num, sides; int parsedBonus; // parse the dice string parseDice(format, num, sides, parsedBonus); // Roll the dice return rollDice(num, sides, bonus + parsedBonus); } /** * Parses strings like "2d6", "1d4+2" and "3d8 - 5". */ private void parseDice(string format, out uint num, out uint sides, out int parsedBonus) { format = normalize(format); // Remove any whitespace format = replace(format, " ", ""); int bonusType = format.indexOf("-") == -1 ? 1 : -1; // Split at the 'd' auto args = split(format, RegExp("d")); // Get the number of throws num = to!(uint)(args[0]); // Split at '+' or '-' args = split(args[1], RegExp("\\+|-")); sides = to!(uint)(args[0]); parsedBonus = to!(uint)(args[1]) * bonusType; } /** * Normalizes the dice str to the format "x1dx2+x3". */ private string normalize(string diceStr) { if (diceStr.indexOf("+") == -1 && diceStr.indexOf("-") == -1) { // Add "+0" to the end to make it complete return diceStr ~ "+0"; } return diceStr; } unittest { auto roll = rollDice(1, 4); assert (roll >= 1 && roll <= 4); roll = rollDice(2, 6, 3); assert (roll >= 5 && roll <= 15); roll = rollDice(1, 8, -2); assert (roll >= -1 && roll <= 6); roll = rollDice("2d4"); assert (roll >= 2 && roll <= 8); roll = rollDice("2d4+2"); assert (roll >= 4 && roll <= 10); roll = rollDice("2d4-2"); assert (roll >= 0 && roll <= 6); roll = rollDice("2d4", 2); assert (roll >= 4 && roll <= 10); roll = rollDice("2d4-1", 2); assert (roll >= 3 && roll <= 9); roll = rollDice("1d6+2"); assert (roll >= 3 && roll <= 8); roll = rollDice("1d4 - 1"); assert (roll >= 0 && roll <= 3); }