public void EntryLevel() { // Roll a standard cubic die one time: var d6 = new Die(6); var roll = d6.Roll(); // Roll an interval die from 10 to 20 four times: var interval10t20 = new Die(10, 20); roll = interval10t20.Roll(4).Sum(); // There is also a fixed die, which always returns the same value. // It's useful when something expects IDie as value provider and you want to pass a constant value: var fixed50 = new FixedDie(50); // Roll two d10's: var d2d10 =new SeveralDice(Dice.D10, 2); roll = d2d10.Roll(); // Compared to simple Dice.D10.Roll(2), SeveralDice provides statistics and serialization Console.WriteLine("Possible roll value range: " + d2d10.Minimum + " to " + d2d10.Maximum); // Roll a d4d10 / d2 * 3: var d4d10divD2mul3 = Dice.Take(Dice.D4).D(10).Divide(Dice.D2).Multiply(3); // This is a dice chain. // Math operations in dice chains are always executed from left to right, so this chain translates to: // take a 1-4 of d10 dice and divide their roll value by 2 with 50 % chance, then multiply resulting roll value by 3. roll = d4d10divD2mul3.Roll(); // Dice chains also provide statistics and serialization. // This chain was created via fluent interface, but it is also possible to create such chain in a more explicit way: d4d10divD2mul3 = new DiceChain( new SeveralDice(new Die(10), new Die(4))) // d4d10 .Append(DiceOperation.Divide, new SeveralDice(2)) // / 2 .Append(DiceOperation.Multiply, new SeveralDice(3)); // * 3 // Oh, and where is a random number generator? Built-in dice get it from thread-local `Dice.Random`. }
public void IntervalDie50T100ShouldBeValidlySerialized() { deserializedR50t100 = (Die)dieSerializer.ReadObject(serializedR50t100); serializedR50t100.Close(); Assert.AreEqual(r50t100.Maximum, deserializedR50t100.Maximum, "Serialized die maximum is wrong"); Assert.AreEqual(r50t100.Minimum, deserializedR50t100.Minimum, "Serialized die minimum is wrong"); Assert.AreEqual(r50t100.ToString(), deserializedR50t100.ToString(), "Serialized die repr is wrong"); }
/// <summary> Converts the string representation of a die to the actual die. </summary> /// <param name="representation">A string that contains a die to parse.</param> /// <returns> Parsed die. </returns> /// <exception cref="System.ArgumentException"> String is too short for a die. /// or /// Die face count is less than 1. /// or /// String is too short. /// or /// Interval minimum can't be greater than maximum. /// or /// String represents unknown die type. /// </exception> /// <exception cref="FormatException">Interval lacks a delimiter ','.</exception> public static Die Parse(string representation) { Contract.Ensures(Contract.Result<Die>() != null); Die result = null; if (!String.IsNullOrWhiteSpace(representation)) { string clean = representation.Trim(); // It could be either a die or an interval, lets check for both: if (clean.StartsWith("d")) { // die, "d[x]" if (clean.Length < 2) { throw new ArgumentException("String is too short.", "representation"); } int faces = Convert.ToInt32(clean.Substring(1), CultureInfo.InvariantCulture); if (faces < 1) { throw new ArgumentException("Die face count is less than 1.", "representation"); } result = new Die(faces); } else if (clean.StartsWith("[")) { // interval, one of "r[x, y]", "r[-x, y]", "r[-x, -y]" if (clean.Length < 5) { throw new ArgumentException("String is too short.", "representation"); } int delimiter = clean.IndexOf(','); // Find interval delimiter. if (delimiter > -1) { // Parse interval minimum and maximum: const int minStart = 1; int maxStart = delimiter + 1; int min = Convert.ToInt32(clean.Substring(minStart, delimiter - minStart).Trim(), CultureInfo.InvariantCulture); int max = Convert.ToInt32(clean.Substring(maxStart, clean.Length - 1 - maxStart).Trim(), CultureInfo.InvariantCulture); if (min > max) { throw new ArgumentException("Interval minimum is greater than maximum.", "representation"); } result = new Die(min, max); } else { throw new FormatException("Interval lacks a delimiter ','."); } } else { throw new ArgumentException("String represents unknown die type."); } } return result; }
public void CreatedR50T100() { r50t100 = new Die(50, 100); }
private static IEnumerable<double> PropagateLuckyRolls(IEnumerable<double> rolls) { var d10 = new Die(10); // Don't allocate a die for each recursive call in real code :) foreach (var roll in rolls) { yield return roll; if (roll == 9 || roll == 10) { foreach (double nextRoll in PropagateLuckyRolls(d10.Roll(1))) { yield return nextRoll; } } } }
public void TrailingLuckyTens() { // With helper method: var rolls = Rolls.SpawnContinuously(Dice.D10.Roll(2), roll => roll == 9 || roll == 10, () => Dice.D10.Roll(1)); // Manual way would be: var d10 = new Die(10); rolls = PropagateLuckyRolls(d10.Roll(2)); }
/// <summary> Converts the string representation of a die to the actual die. /// A return value indicates whether the conversion succeeded or failed. </summary> /// <param name="representation"> A string that contains a die to parse. </param> /// <param name="die"> When this method returns, contains the parsed die equivalent to the given string, if the /// conversion succeeded, or null if the conversion failed. This parameter is passed uninitialized. </param> /// <returns>true if string was converted successfully; otherwise, false.</returns> public static bool TryParse(string representation, out Die die) { // TODO: That's not a good style, better to do proper format validation someday. try { die = Parse(representation); return die != null; } catch { die = null; return false; } }
public void IntervalStringParsedIntoADie() { rm100tm10 = Die.Parse(rm100tm10repr); }
public void CreatedD12() { d12 = new Die(12); }