Add random number generator

This commit is contained in:
Andrew Cooper
2022-03-02 21:45:42 +11:00
parent f61350ce04
commit 2c1e4af702
2 changed files with 105 additions and 0 deletions

View File

@@ -0,0 +1,55 @@
namespace Games.Common.Randomness;
/// <summary>
/// Provides access to a random number generator
/// </summary>
public interface IRandom
{
/// <summary>
/// Gets a random <see cref="float" /> such that 0 <= n < 1.
/// </summary>
/// <returns>The random number.</returns>
float NextFloat();
/// <summary>
/// Gets a random <see cref="float" /> such that 0 <= n < exclusiveMaximum.
/// </summary>
/// <returns>The random number.</returns>
float NextFloat(float exclusiveMaximum);
/// <summary>
/// Gets a random <see cref="float" /> such that inclusiveMinimum <= n < exclusiveMaximum.
/// </summary>
/// <returns>The random number.</returns>
float NextFloat(float inclusiveMinimum, float exclusiveMaximum);
/// <summary>
/// Gets a random <see cref="int" /> such that 0 <= n < exclusiveMaximum.
/// </summary>
/// <returns>The random number.</returns>
int Next(int exclusiveMaximum);
/// <summary>
/// Gets a random <see cref="int" /> such that inclusiveMinimum <= n < exclusiveMaximum.
/// </summary>
/// <returns>The random number.</returns>
int Next(int inclusiveMinimum, int exclusiveMaximum);
/// <summary>
/// Gets the previous random number as a <see cref="float" />.
/// </summary>
/// <returns>The previous random number.</returns>
float PreviousFloat();
/// <summary>
/// Gets the previous random number as an <see cref="int" />.
/// </summary>
/// <returns>The previous random number.</returns>
int Previous();
/// <summary>
/// Reseeds the random number generator.
/// </summary>
/// <param name="seed">The seed.</param>
void Reseed(int seed);
}

View File

@@ -0,0 +1,50 @@
using System;
namespace Games.Common.Randomness;
public class RandomNumberGenerator : IRandom
{
private Random _random;
private float _previous;
public RandomNumberGenerator()
{
// The BASIC RNG is seeded based on time with a 1 second resolution
_random = new Random((int)(DateTime.UtcNow.Ticks / TimeSpan.TicksPerSecond));
}
public float NextFloat() => NextFloat(1);
public float NextFloat(float exclusiveMaximum)
{
if (exclusiveMaximum <= 0)
{
throw new ArgumentOutOfRangeException(nameof(exclusiveMaximum), "Must be greater than 0.");
}
return NextFloat(0, exclusiveMaximum);
}
public float NextFloat(float inclusiveMinimum, float exclusiveMaximum)
{
if (exclusiveMaximum <= inclusiveMinimum)
{
throw new ArgumentOutOfRangeException(nameof(exclusiveMaximum), "Must be greater than inclusiveMinimum.");
}
var range = exclusiveMaximum - inclusiveMinimum;
return _previous = ((float)_random.NextDouble()) * range + inclusiveMinimum;
}
public int Next(int exclusiveMaximum) => ToInt(NextFloat(exclusiveMaximum));
public int Next(int inclusiveMinimum, int exclusiveMaximum) => ToInt(NextFloat(inclusiveMinimum, exclusiveMaximum));
public float PreviousFloat() => _previous;
public int Previous() => ToInt(_previous);
private static int ToInt(float value) => (int)Math.Floor(value);
public void Reseed(int seed) => _random = new Random(seed);
}