Files
zfxaction25/RobotAndDonkey.Game/Utils/SRandom.cs
2026-04-19 00:43:27 +02:00

100 lines
2.1 KiB
C#

using System;
namespace RobotAndDonkey.Game.Utils;
/// <summary>
/// Implements a XorShift* PRNG, with 64 bits of internal state.
/// See http://en.wikipedia.org/wiki/Xorshift
/// </summary>
public struct SRandom
{
public SRandom(ulong seed)
{
if (seed == 0)
throw new InvalidOperationException("Seed needs to be bigger than zero.");
Seed = seed;
}
public void Shuffle<T>(Span<T> span)
{
var n = span.Length;
for (var i = 0; i < n; i++)
{
var r = i + Next(n - i);
(span[r], span[i]) = (span[i], span[r]);
}
}
public ulong Next()
{
Seed ^= Seed >> 12;
Seed ^= Seed << 25;
Seed ^= Seed >> 27;
return Seed * 2685821657736338717UL; // multiplier taken from wikipedia article on XorShift PRNGs
}
public ulong Next(ulong upperLimit)
{
if (upperLimit == 0)
return 0;
return Next() % upperLimit;
}
public uint Next(uint upperLimit)
{
if (upperLimit == 0)
return 0;
return (uint)(Next() % upperLimit);
}
public uint Next(uint lowerLimit, uint upperLimit)
{
if (upperLimit == 0)
return 0;
if (lowerLimit == upperLimit)
return lowerLimit;
return lowerLimit + (uint)(Next() % (upperLimit - lowerLimit));
}
public int Next(int upperLimit)
{
if (upperLimit == 0)
return 0;
return (int)(Next() % (uint)(upperLimit & 0x7fffffff));
}
public int Next(int lowerLimit, int upperLimit)
{
if (upperLimit == 0)
return 0;
if (lowerLimit == upperLimit)
return lowerLimit;
return lowerLimit + (int)(Next() % (uint)((upperLimit - lowerLimit) & 0x7fffffff));
}
public double NextDouble()
{
return Next(int.MaxValue) * (1.0 / int.MaxValue);
}
public float NextSingle()
{
return (float)NextDouble();
}
public readonly override string ToString()
{
return $"0x{Seed:X}";
}
public ulong Seed { get; internal set; }
}