mirror of
https://github.com/coding-horror/basic-computer-games.git
synced 2025-12-23 07:29:02 -08:00
Improve Random interface
This commit is contained in:
@@ -6,47 +6,17 @@ namespace Games.Common.Randomness;
|
|||||||
public interface IRandom
|
public interface IRandom
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a random <see cref="float" /> such that 0 <= n < 1.
|
/// Gets a random <see cref="float" /> such that 0 <= n < 1.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>The random number.</returns>
|
/// <returns>The random number.</returns>
|
||||||
float NextFloat();
|
float NextFloat();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a random <see cref="float" /> such that 0 <= n < exclusiveMaximum.
|
/// Gets the <see cref="float" /> returned by the previous call to <see cref="NextFloat" />.
|
||||||
/// </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>
|
/// </summary>
|
||||||
/// <returns>The previous random number.</returns>
|
/// <returns>The previous random number.</returns>
|
||||||
float PreviousFloat();
|
float PreviousFloat();
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the previous random number as an <see cref="int" />.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>The previous random number.</returns>
|
|
||||||
int Previous();
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Reseeds the random number generator.
|
/// Reseeds the random number generator.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -0,0 +1,91 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Games.Common.Randomness;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Provides extension methods to <see cref="IRandom" /> providing random numbers in a given range.
|
||||||
|
/// </summary>
|
||||||
|
/// <value></value>
|
||||||
|
public static class IRandomExtensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a random <see cref="float" /> such that 0 <= n < exclusiveMaximum.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The random number.</returns>
|
||||||
|
public static float NextFloat(this IRandom random, float exclusiveMaximum) =>
|
||||||
|
Scale(random.NextFloat(), exclusiveMaximum);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a random <see cref="float" /> such that inclusiveMinimum <= n < exclusiveMaximum.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The random number.</returns>
|
||||||
|
public static float NextFloat(this IRandom random, float inclusiveMinimum, float exclusiveMaximum) =>
|
||||||
|
Scale(random.NextFloat(), inclusiveMinimum, exclusiveMaximum);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a random <see cref="int" /> such that 0 <= n < exclusiveMaximum.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The random number.</returns>
|
||||||
|
public static int Next(this IRandom random, int exclusiveMaximum) => ToInt(random.NextFloat(exclusiveMaximum));
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a random <see cref="int" /> such that inclusiveMinimum <= n < exclusiveMaximum.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The random number.</returns>
|
||||||
|
public static int Next(this IRandom random, int inclusiveMinimum, int exclusiveMaximum) =>
|
||||||
|
ToInt(random.NextFloat(inclusiveMinimum, exclusiveMaximum));
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the previous unscaled <see cref="float" /> (between 0 and 1) scaled to a new range:
|
||||||
|
/// 0 <= x < <paramref name="exclusiveMaximum" />.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The random number.</returns>
|
||||||
|
public static float PreviousFloat(this IRandom random, float exclusiveMaximum) =>
|
||||||
|
Scale(random.PreviousFloat(), exclusiveMaximum);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the previous unscaled <see cref="float" /> (between 0 and 1) scaled to a new range:
|
||||||
|
/// <paramref name="inclusiveMinimum" /> <= n < <paramref name="exclusiveMaximum" />.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The random number.</returns>
|
||||||
|
public static float PreviousFloat(this IRandom random, float inclusiveMinimum, float exclusiveMaximum) =>
|
||||||
|
Scale(random.PreviousFloat(), inclusiveMinimum, exclusiveMaximum);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the previous unscaled <see cref="float" /> (between 0 and 1) scaled to an <see cref="int" /> in a new
|
||||||
|
/// range: 0 <= n < <paramref name="exclusiveMaximum" />.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The random number.</returns>
|
||||||
|
public static int Previous(this IRandom random, int exclusiveMaximum) =>
|
||||||
|
ToInt(random.PreviousFloat(exclusiveMaximum));
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the previous unscaled <see cref="float" /> (between 0 and 1) scaled to an <see cref="int" /> in a new
|
||||||
|
/// range: <paramref name="inclusiveMinimum" /> <= n < <paramref name="exclusiveMaximum" />.
|
||||||
|
/// <returns>The random number.</returns>
|
||||||
|
public static int Previous(this IRandom random, int inclusiveMinimum, int exclusiveMaximum) =>
|
||||||
|
ToInt(random.PreviousFloat(inclusiveMinimum, exclusiveMaximum));
|
||||||
|
|
||||||
|
private static float Scale(float zeroToOne, float exclusiveMaximum)
|
||||||
|
{
|
||||||
|
if (exclusiveMaximum <= 0)
|
||||||
|
{
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(exclusiveMaximum), "Must be greater than 0.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return Scale(zeroToOne, 0, exclusiveMaximum);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static float Scale(float zeroToOne, float inclusiveMinimum, float exclusiveMaximum)
|
||||||
|
{
|
||||||
|
if (exclusiveMaximum <= inclusiveMinimum)
|
||||||
|
{
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(exclusiveMaximum), "Must be greater than inclusiveMinimum.");
|
||||||
|
}
|
||||||
|
|
||||||
|
var range = exclusiveMaximum - inclusiveMinimum;
|
||||||
|
return zeroToOne * range + inclusiveMinimum;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int ToInt(float value) => (int)Math.Floor(value);
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@ using System;
|
|||||||
|
|
||||||
namespace Games.Common.Randomness;
|
namespace Games.Common.Randomness;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public class RandomNumberGenerator : IRandom
|
public class RandomNumberGenerator : IRandom
|
||||||
{
|
{
|
||||||
private Random _random;
|
private Random _random;
|
||||||
@@ -13,38 +14,9 @@ public class RandomNumberGenerator : IRandom
|
|||||||
_random = new Random((int)(DateTime.UtcNow.Ticks / TimeSpan.TicksPerSecond));
|
_random = new Random((int)(DateTime.UtcNow.Ticks / TimeSpan.TicksPerSecond));
|
||||||
}
|
}
|
||||||
|
|
||||||
public float NextFloat() => NextFloat(1);
|
public float NextFloat() => _previous = (float)_random.NextDouble();
|
||||||
|
|
||||||
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 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);
|
public void Reseed(int seed) => _random = new Random(seed);
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user