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);
}