using System; using System.Collections.Generic; using Robust.Shared.Collections; using Robust.Shared.Maths; using Robust.Shared.Utility; namespace Robust.Shared.Random { public static class RandomExtensions { /// /// Generate a random number from a normal (gaussian) distribution. /// /// The random object to generate the number from. /// The average or "center" of the normal distribution. /// The standard deviation of the normal distribution. public static double NextGaussian(this IRobustRandom random, double μ = 0, double σ = 1) { // https://stackoverflow.com/a/218600 var α = random.NextDouble(); var β = random.NextDouble(); var randStdNormal = Math.Sqrt(-2.0 * Math.Log(α)) * Math.Sin(2.0 * Math.PI * β); return μ + σ * randStdNormal; } public static T Pick(this IRobustRandom random, IReadOnlyList list) { var index = random.Next(list.Count); return list[index]; } public static ref T Pick(this IRobustRandom random, ValueList list) { var index = random.Next(list.Count); return ref list[index]; } /// Picks a random element from a collection. /// /// This is O(n). /// public static T Pick(this IRobustRandom random, IReadOnlyCollection collection) { var index = random.Next(collection.Count); var i = 0; foreach (var t in collection) { if (i++ == index) { return t; } } throw new InvalidOperationException("This should be unreachable!"); } public static T PickAndTake(this IRobustRandom random, IList list) { var index = random.Next(list.Count); var element = list[index]; list.RemoveAt(index); return element; } public static Angle NextAngle(this System.Random random) => NextFloat(random) * MathF.Tau; public static float NextFloat(this IRobustRandom random) { // This is pretty much the CoreFX implementation. // So credits to that. // Except using float instead of double. return random.Next() * 4.6566128752458E-10f; } public static float NextFloat(this System.Random random) { return random.Next() * 4.6566128752458E-10f; } /// /// Have a certain chance to return a boolean. /// /// The random instance to run on. /// The chance to pass, from 0 to 1. public static bool Prob(this IRobustRandom random, float chance) { DebugTools.Assert(chance <= 1 && chance >= 0, $"Chance must be in the range 0-1. It was {chance}."); return random.NextDouble() < chance; } internal static void Shuffle(Span array, System.Random random) { var n = array.Length; while (n > 1) { n--; var k = random.Next(n + 1); (array[k], array[n]) = (array[n], array[k]); } } } }