using System; using System.Collections.Generic; using System.Numerics; using System.Runtime.CompilerServices; using Robust.Shared.Collections; using Robust.Shared.Maths; namespace Robust.Shared.Random; /// /// Wrapper around random number generator helping methods. /// public interface IRobustRandom { /// Get the underlying . [Obsolete("Do not access the underlying implementation")] System.Random GetRandom(); /// Set seed for underlying . void SetSeed(int seed); /// Get random value between 0 (included) and 1 (excluded). float NextFloat(); /// Get random value in range of (included) and (excluded). /// Random value should be greater or equal to this value. /// Random value should be less then this value. public float NextFloat(float minValue, float maxValue) => NextFloat() * (maxValue - minValue) + minValue; /// Get random value in range of 0 (included) and (excluded). /// Random value should be less then this value. public float NextFloat(float maxValue) => NextFloat() * maxValue; /// Get random value. int Next(); /// Get random value in range of 0 (included) and (excluded). /// Random value should be less then this value. int Next(int maxValue); /// Get random value in range of (included) and (excluded). /// Random value should be greater or equal to this value. /// Random value should be less then this value. int Next(int minValue, int maxValue); /// Get random value between 0 (included) and (excluded). [MethodImpl(MethodImplOptions.AggressiveInlining)] public byte NextByte() => NextByte(byte.MaxValue); /// Get random value in range of 0 (included) and (excluded). /// Random value should be less then this value. [MethodImpl(MethodImplOptions.AggressiveInlining)] public byte NextByte(byte maxValue) => NextByte(0, maxValue); /// Get random value in range of (included) and (excluded). /// Random value should be greater or equal to this value. /// Random value should be less then this value. [MethodImpl(MethodImplOptions.AggressiveInlining)] public byte NextByte(byte minValue, byte maxValue) => (byte)Next(minValue, maxValue); /// Get random value between 0 (included) and 1 (excluded). double NextDouble(); /// Get random value in range of 0 (included) and (excluded). /// Random value should be less then this value. double Next(double maxValue) => NextDouble() * maxValue; /// Get random value in range of (included) and (excluded). /// Random value should be greater or equal to this value. /// Random value should be less then this value. double NextDouble(double minValue, double maxValue) => NextDouble() * (maxValue - minValue) + minValue; /// Get random value in range of (included) and (excluded). /// Random value should be less then this value. TimeSpan Next(TimeSpan maxTime); /// Get random value in range of (included) and (excluded). /// Random value should be greater or equal to this value. /// Random value should be less then this value. TimeSpan Next(TimeSpan minTime, TimeSpan maxTime); /// Fill buffer with random bytes (values). void NextBytes(byte[] buffer); /// Get random value in range of 0 (included) and (excluded). public Angle NextAngle() => NextFloat() * MathF.Tau; /// Get random value in range of 0 (included) and (excluded). /// Random value should be less then this value. public Angle NextAngle(Angle maxValue) => NextFloat() * maxValue; /// Get random value in range of (included) and (excluded). /// Random value should be greater or equal to this value. /// Random value should be less then this value. public Angle NextAngle(Angle minValue, Angle maxValue) => NextFloat() * (maxValue - minValue) + minValue; /// /// Random vector, created from a uniform distribution of magnitudes and angles. /// /// Max value for randomized vector magnitude (excluded). public Vector2 NextVector2(float maxMagnitude = 1) => NextVector2(0, maxMagnitude); /// /// Random vector, created from a uniform distribution of magnitudes and angles. /// /// Min value for randomized vector magnitude (included). /// Max value for randomized vector magnitude (excluded). /// /// In general, NextVector2(1) will tend to result in vectors with smaller magnitudes than /// NextVector2Box(1,1), even if you ignored any vectors with a magnitude larger than one. /// public Vector2 NextVector2(float minMagnitude, float maxMagnitude) => NextAngle().RotateVec(new Vector2(NextFloat(minMagnitude, maxMagnitude), 0)); /// /// Random vector, created from a uniform distribution of x and y coordinates lying inside some box. /// public Vector2 NextVector2Box(float minX, float minY, float maxX, float maxY) => new Vector2(NextFloat(minX, maxX), NextFloat(minY, maxY)); /// /// Random vector, created from a uniform distribution of x and y coordinates lying inside some box. /// Box will have coordinates starting at [- , -] /// and ending in [ , ] /// public Vector2 NextVector2Box(float maxAbsX = 1, float maxAbsY = 1) => NextVector2Box(-maxAbsX, -maxAbsY, maxAbsX, maxAbsY); /// Randomly switches positions in collection. void Shuffle(IList list) { if (list is T[] arr) { // Done to avoid significant performance dip from Moq workaround in RandomExtensions.cs, // doubt it matters much. // https://github.com/space-wizards/RobustToolbox/issues/6329 Shuffle(arr); return; } var n = list.Count; while (n > 1) { n -= 1; var k = Next(n + 1); (list[k], list[n]) = (list[n], list[k]); } } /// Randomly switches positions in collection. void Shuffle(Span list) { var n = list.Length; while (n > 1) { n -= 1; var k = Next(n + 1); (list[k], list[n]) = (list[n], list[k]); } } /// Randomly switches positions in collection. void Shuffle(ValueList list) { Shuffle(list.Span); } } [Obsolete("Always use RobustRandom/IRobustRandom, System.Random does not provide any extra functionality.")] public static class RandomHelpers { [Obsolete("Always use RobustRandom/IRobustRandom, System.Random does not provide any extra functionality.")] public static void Shuffle(this System.Random random, IList list) { var n = list.Count; while (n > 1) { n -= 1; var k = random.Next(n + 1); (list[k], list[n]) = (list[n], list[k]); } } [Obsolete("Always use RobustRandom/IRobustRandom, System.Random does not provide any extra functionality.")] public static bool Prob(this System.Random random, double chance) { return random.NextDouble() < chance; } [MethodImpl(MethodImplOptions.AggressiveInlining)] [Obsolete("Always use RobustRandom/IRobustRandom, System.Random does not provide any extra functionality.")] public static byte NextByte(this System.Random random, byte maxValue) { return NextByte(random, 0, maxValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] [Obsolete("Always use RobustRandom/IRobustRandom, System.Random does not provide any extra functionality.")] public static byte NextByte(this System.Random random) { return NextByte(random, byte.MaxValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] [Obsolete("Always use RobustRandom/IRobustRandom, System.Random does not provide any extra functionality.")] public static byte NextByte(this System.Random random, byte minValue, byte maxValue) { return (byte)random.Next(minValue, maxValue); } }