using System; namespace STVrogue.Utils { /// /// A generic interface for a random generator. /// public interface IRandomGenerator { /// /// Return the value of the seed used by this generator. /// /// public int Seed(); /// /// Generate a random integer in the range of [0..maxvakye) /// public int NextInt(int maxvalue); /// /// Generate a random flo.ating number in the range of [0..1] /// public double NextDouble(); } /// /// An implementation of . This implementation /// just wraps around . You can set its seed, but it does /// not implement the Singleton pattern. /// public class RandomGenerator : IRandomGenerator { int? seed = null; Random rnd; public RandomGenerator() { rnd = new Random(); } public RandomGenerator(int seed) { rnd = new Random(seed); this.seed = seed; } public int Seed() { if (seed == null) throw new Exception("The seed is unknown"); return (int) seed; } public int NextInt(int maxvalue) { return rnd.Next(maxvalue); } public double NextDouble() { return rnd.NextDouble(); } } /// /// Provide an implementation of a controlled random generator. It uses a Singleton /// design pattern so that internally there is only one random generator that is /// shared by all instances of this class STVControlledRandom. /// /// Internally a random generator keeps a state to create the next random value. /// This next value is actually deterministically depend on the current state /// of the random generator. So, ultimately the whole series of random values /// the generator produces only depends on its initial state, which is the generator /// seed. /// /// Use the static method SetSeed(value) to set the value of this seed. This seed /// value is global: it is shared by all instances of STVControlledRandom. /// /// The method Reset() will reset the state of all instances of STVControlledRandom to /// the their initial state, which is the value of the above meant common seed. /// /// IMPORTANT NOTE: /// When testing STV method classes that use STVControlledRandom, make sure that you /// call Reset() before the run of every test-method. This makes sure that the /// tests' results do not depend on the order with which the test methods are called. /// public class STVControlledRandom : IRandomGenerator { /// /// The the seed value of all instances of STVControlledRandom. They all share /// this seed value. /// static int seed = 4731 ; /// /// This is the single, actual random generator that will be shared by all /// instances of STVControlledRandom. /// static Random rnd; /// /// For setting the seed value of all instances of STVControlledRandom. /// They all share this seed value. Setting the seed will cause the /// actual random generator of all instances of STVControlledRandom. /// public static void SetSeed(int seedvalue) { Reset(); seed = seedvalue; } /// /// Reset the state of all instances of STVControlledRandom to the value of /// their common seed. /// public static void Reset() { rnd = null; } /// /// Return the seed value of this STVControlledRandom. /// public int Seed() { return seed; } public int NextInt(int maxvalue) { if (rnd == null) rnd = new Random(seed); return rnd.Next(maxvalue); } public double NextDouble() { if (rnd == null) rnd = new Random(seed); return rnd.NextDouble(); } } }