Files
Christopher Wiebe b451f83174 Initial commit: Theriapolis baseline at port/godot branch point
Captures the pre-Godot-port state of the codebase. This is the rollback
anchor for the Godot port (M0 of theriapolis-rpg-implementation-plan-godot-port.md).
All Phase 0 through Phase 6.5 work is included; Phase 7 is in flight.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-30 20:40:51 -07:00

68 lines
2.2 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
namespace Theriapolis.Core.Util;
/// <summary>
/// SplitMix64-based pseudo-random number generator with named sub-stream support.
/// All game randomness must go through this class — no new System.Random() anywhere.
/// </summary>
public sealed class SeededRng
{
private ulong _state;
public SeededRng(ulong seed)
{
// Mix the seed to avoid bad low-entropy states
_state = seed == 0 ? 0x9e3779b97f4a7c15UL : seed;
// Warm up the state
NextUInt64();
NextUInt64();
}
/// <summary>Create a sub-stream for a specific subsystem using the world seed and a named tag constant.</summary>
public static SeededRng ForSubsystem(ulong worldSeed, ulong subsystemTag)
=> new(worldSeed ^ subsystemTag);
public ulong NextUInt64()
{
// SplitMix64 step
_state += 0x9e3779b97f4a7c15UL;
ulong z = _state;
z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9UL;
z = (z ^ (z >> 27)) * 0x94d049bb133111ebUL;
return z ^ (z >> 31);
}
public uint NextUInt32() => (uint)(NextUInt64() >> 32);
/// <summary>Returns a double in [0, 1).</summary>
public double NextDouble() => (NextUInt64() >> 11) * (1.0 / (1UL << 53));
/// <summary>Returns a float in [0, 1).</summary>
public float NextFloat() => (float)NextDouble();
/// <summary>Returns a float in [min, max).</summary>
public float NextFloat(float min, float max) => min + NextFloat() * (max - min);
/// <summary>Returns an int in [min, max).</summary>
public int NextInt(int min, int max)
{
if (max <= min) return min;
return min + (int)(NextUInt64() % (ulong)(max - min));
}
/// <summary>Returns an int in [0, max).</summary>
public int NextInt(int max) => NextInt(0, max);
/// <summary>Returns true with probability p (01).</summary>
public bool NextBool(double p = 0.5) => NextDouble() < p;
/// <summary>Shuffles a span in place using FisherYates.</summary>
public void Shuffle<T>(Span<T> span)
{
for (int i = span.Length - 1; i > 0; i--)
{
int j = NextInt(0, i + 1);
(span[i], span[j]) = (span[j], span[i]);
}
}
}