Deukhoofd 8a857ed232
All checks were successful
Build / Build (push) Successful in 51s
Implements some micro-optimizations
2025-07-05 15:46:32 +02:00

127 lines
4.0 KiB
C#

using Pcg;
namespace PkmnLib.Static.Utils;
/// <summary>
/// Wrapper interface for getting random numbers.
/// </summary>
public interface IRandom
{
/// <summary>
/// Get a random integer between min and max.
/// </summary>
/// <param name="min">The minimum value (inclusive).</param>
/// <param name="max">The maximum value (exclusive).</param>
/// <returns>A random integer that is greater than or equal to min and less than max.</returns>
public int GetInt(int min, int max);
/// <summary>
/// Get a random integer between 0 and max.
/// </summary>
/// <param name="max">The maximum value (exclusive).</param>
/// <returns>A random integer that is greater than or equal to 0 and less than max.</returns>
public int GetInt(int max);
/// <summary>
/// Get a random integer between 0 and <see cref="int.MaxValue"/>.
/// </summary>
/// <returns>A random integer that is greater than or equal to 0 and less than <see cref="int.MaxValue"/>.</returns>
public int GetInt();
/// <summary>
/// Get a random float that is greater than or equal to 0.0 and less than 1.0.
/// </summary>
/// <returns>A random float that is greater than or equal to 0.0 and less than 1.0.</returns>
public float GetFloat();
/// <summary>
/// Get a random float that is greater than or equal to min and less than max.
/// </summary>
/// <param name="min">The minimum value (inclusive).</param>
/// <param name="max">The maximum value (exclusive).</param>
/// <returns>A random float that is greater than or equal to min and less than max.</returns>
public float GetFloat(float min, float max);
/// <summary>
/// Get a random boolean. 50% chance of being true.
/// </summary>
public bool GetBool();
/// <summary>
/// Get a random element from the given list.
/// </summary>
public T OneOf<T>(IReadOnlyList<T> list);
}
/// <inheritdoc />
public class RandomImpl : IRandom
{
private readonly PcgRandom _random;
/// <summary>
/// Creates a new instance that uses the given <see cref="PcgRandom"/> instance as its source of randomness.
/// </summary>
public RandomImpl(PcgRandom random)
{
_random = random;
}
/// <summary>
/// Creates a new instance that uses the given seed to create a new <see cref="PcgRandom"/> instance.
/// </summary>
public RandomImpl(int seed)
{
_random = new PcgRandom(seed);
}
/// <summary>
/// Creates a new instance that uses a new <see cref="PcgRandom"/> instance.
/// </summary>
public RandomImpl()
{
_random = new PcgRandom();
}
/// <inheritdoc />
public int GetInt(int min, int max) => _random.Next(min, max);
/// <inheritdoc />
public int GetInt(int max) => _random.Next(max);
/// <inheritdoc />
public int GetInt() => _random.Next();
/// <inheritdoc />
public float GetFloat() => (float)_random.NextDouble();
/// <inheritdoc />
public float GetFloat(float min, float max) => (float)(_random.NextDouble() * (max - min) + min);
/// <inheritdoc />
public bool GetBool() => _random.Next(2) == 1;
/// <inheritdoc />
public T OneOf<T>(IReadOnlyList<T> list)
{
if (list.Count == 0)
throw new ArgumentException("List cannot be empty.", nameof(list));
return list[GetInt(list.Count)];
}
/// <summary>
/// Generates a new random <see cref="Guid"/>.
/// </summary>
/// <remarks>
/// The goal of this method is to create a new unique identifier that can be used for various purposes,
/// without having to rely on the system's built-in GUID generation. The built-in GUID generation
/// can be slow (see also: https://github.com/dotnet/runtime/issues/13628)
/// </remarks>
public Guid NewGuid()
{
var guidBytes = GuidCache.Value.AsSpan();
_random.NextBytes(guidBytes);
return new Guid(guidBytes);
}
private static readonly ThreadLocal<byte[]> GuidCache = new(() => new byte[16]);
}