using System; namespace MLEM.Misc { /// /// The SingleRandom class allows generating single, one-off pseudorandom numbers based on a seed or a . /// The types of numbers that can be generated are and , both of which can be generated with specific minimum and maximum values if desired. /// Methods in this class are tested to be sufficiently "random", that is, to be sufficiently distributed throughout their range, as well as sufficiently different for neighboring seeds. /// public class SingleRandom { /// /// Generates a single, one-off pseudorandom integer between 0 and based on a given . /// This method is guaranteed to return the same result for the same . /// /// The seed to use. /// The generated number. public static int Int(int seed) { return (int) (SingleRandom.Single(seed) * int.MaxValue); } /// /// Generates a single, one-off pseudorandom integer between 0 and based on a given . /// This method is guaranteed to return the same result for the same . /// /// The to use. /// The generated number. public static int Int(SeedSource source) { return (int) (SingleRandom.Single(source) * int.MaxValue); } /// /// Generates a single, one-off pseudorandom integer between 0 and based on a given . /// This method is guaranteed to return the same result for the same . /// /// The (exclusive) maximum value. /// The seed to use. /// The generated number. public static int Int(int maxValue, int seed) { return (int) (maxValue * SingleRandom.Single(seed)); } /// /// Generates a single, one-off pseudorandom integer between 0 and based on a given . /// This method is guaranteed to return the same result for the same . /// /// The (exclusive) maximum value. /// The to use. /// The generated number. public static int Int(int maxValue, SeedSource source) { return (int) (maxValue * SingleRandom.Single(source)); } /// /// Generates a single, one-off pseudorandom integer between and based on a given . /// This method is guaranteed to return the same result for the same . /// /// The (inclusive) minimum value. /// The (exclusive) maximum value. /// The seed to use. /// The generated number. public static int Int(int minValue, int maxValue, int seed) { return (int) ((maxValue - minValue) * SingleRandom.Single(seed)) + minValue; } /// /// Generates a single, one-off pseudorandom integer between and based on a given . /// This method is guaranteed to return the same result for the same . /// /// The (inclusive) minimum value. /// The (exclusive) maximum value. /// The to use. /// The generated number. public static int Int(int minValue, int maxValue, SeedSource source) { return (int) ((maxValue - minValue) * SingleRandom.Single(source)) + minValue; } /// /// Generates a single, one-off pseudorandom floating point number between 0 and 1 based on a given . /// This method is guaranteed to return the same result for the same . /// /// The seed to use. /// The generated number. public static float Single(int seed) { return (new SeedSource(seed).Get() / (float) int.MaxValue + 1) / 2; } /// /// Generates a single, one-off pseudorandom floating point number between 0 and 1 based on a given . /// This method is guaranteed to return the same result for the same . /// /// The to use. /// The generated number. public static float Single(SeedSource source) { return (source.Get() / (float) int.MaxValue + 1) / 2; } /// /// Generates a single, one-off pseudorandom floating point number between 0 and based on a given . /// This method is guaranteed to return the same result for the same . /// /// The (exclusive) maximum value. /// The seed to use. /// The generated number. public static float Single(float maxValue, int seed) { return maxValue * SingleRandom.Single(seed); } /// /// Generates a single, one-off pseudorandom floating point number between 0 and based on a given . /// This method is guaranteed to return the same result for the same . /// /// The (exclusive) maximum value. /// The to use. /// The generated number. public static float Single(float maxValue, SeedSource source) { return maxValue * SingleRandom.Single(source); } /// /// Generates a single, one-off pseudorandom floating point number between and based on a given . /// This method is guaranteed to return the same result for the same . /// /// The (inclusive) minimum value. /// The (exclusive) maximum value. /// The seed to use. /// The generated number. public static float Single(float minValue, float maxValue, int seed) { return (maxValue - minValue) * SingleRandom.Single(seed) + minValue; } /// /// Generates a single, one-off pseudorandom floating point number between and based on a given . /// This method is guaranteed to return the same result for the same . /// /// The (inclusive) minimum value. /// The (exclusive) maximum value. /// The to use. /// The generated number. public static float Single(float minValue, float maxValue, SeedSource source) { return (maxValue - minValue) * SingleRandom.Single(source) + minValue; } } /// /// A seed source contains an value which can be used as a seed for a or . Seed sources feature a convenient way to add multiple seeds using , which will be sufficiently scrambled to be deterministically semi-random and combined into a single . /// This struct behaves similarly to System.HashCode in many ways, with an important distinction being that 's scrambling procedure is not considered an implementation detail, and will stay consistent between process executions. /// /// /// For example, a seed source can be used to create a new based on an object's x and y coordinates by combining them into a using . The values generated by the created using will then be determined by the specific pair of x and y values used. /// public readonly struct SeedSource { private readonly int? value; /// /// Creates a new seed source from the given seed, which will be added automatically using . /// /// The initial seed to use. public SeedSource(int seed) : this() { this = this.Add(seed); } /// /// Creates a new seed source from the given set of seeds, which will be added automatically using . /// /// The initial seeds to use. public SeedSource(params int[] seeds) : this() { foreach (var seed in seeds) this = this.Add(seed); } private SeedSource(int? value) { this.value = value; } /// /// Adds the given seed to this seed source's value and returns the result as a new seed source. /// The algorithm used for adding involves various scrambling operations that sufficiently semi-randomize the seed and final value. /// /// The seed to add. /// A new seed source with the seed added. public SeedSource Add(int seed) { seed ^= seed << 7; seed *= 207398809; seed ^= seed << 17; seed *= 928511849; seed ^= seed << 12; seed += 3; return new SeedSource(new int?(this.Get() + seed)); } /// /// Adds the given seed to this seed source's value and returns the result as a new seed source. /// Floating point values are scrambled by invoking using a typecast version, followed by invoking using the decimal value multiplied by . /// /// The seed to add. /// A new seed source with the seed added. public SeedSource Add(float seed) { return this.Add((int) seed).Add((seed - (int) seed) * int.MaxValue); } /// /// Adds the given seed to this seed source's value and returns the result as a new seed source. /// Strings are scrambled by invoking using every character contained in the string, in order. /// /// The seed to add. /// A new seed source with the seed added. public SeedSource Add(string seed) { var ret = this; foreach (var c in seed) ret = ret.Add(c); return ret; } /// /// Returns this seed source's seed value, which can then be used in or elsewhere. /// /// This seed source's value. public int Get() { return this.value ?? 1623487; } /// /// Returns a new instance using this source seed's value, retrieved using . /// /// A new using this seed source's value. public Random Random() { return new Random(this.Get()); } } }