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]);
}
}
}
}