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