feat(rng-seam): SeededRandomSource mirrors the engine's two System.Random streams
This commit is contained in:
@@ -17,5 +17,23 @@ namespace SVSim.BattleEngine.Tests
|
|||||||
Assert.That(RandomSourceBridge.Range(3, 0.5), Is.EqualTo(1)); // floor(1.5) = 1 (middle of 3)
|
Assert.That(RandomSourceBridge.Range(3, 0.5), Is.EqualTo(1)); // floor(1.5) = 1 (middle of 3)
|
||||||
Assert.That(RandomSourceBridge.Range(1, 0.5), Is.EqualTo(0)); // floor(0.5) = 0
|
Assert.That(RandomSourceBridge.Range(1, 0.5), Is.EqualTo(0)); // floor(0.5) = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SeededRandomSource(seed) must reproduce the engine's own generators EXACTLY: BattleManagerBase
|
||||||
|
// seeds both _stableRandom and _stableRandomOnlySelf as `new System.Random(RandomSeed)`
|
||||||
|
// (BattleManagerBase.cs:721-722). NextUnit() == synced.NextDouble(); NextSelf(max) == self.Next(max).
|
||||||
|
[Test]
|
||||||
|
public void SeededSource_reproduces_two_System_Random_streams()
|
||||||
|
{
|
||||||
|
const int seed = 12345;
|
||||||
|
var src = new SeededRandomSource(seed);
|
||||||
|
|
||||||
|
var refSynced = new System.Random(seed); // mirrors _stableRandom
|
||||||
|
var refSelf = new System.Random(seed); // mirrors _stableRandomOnlySelf (separate stream)
|
||||||
|
|
||||||
|
for (int i = 0; i < 8; i++)
|
||||||
|
Assert.That(src.NextUnit(), Is.EqualTo(refSynced.NextDouble()), $"NextUnit drift at {i}");
|
||||||
|
for (int i = 0; i < 8; i++)
|
||||||
|
Assert.That(src.NextSelf(100), Is.EqualTo(refSelf.Next(100)), $"NextSelf drift at {i}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
22
SVSim.BattleEngine/Rng/SeededRandomSource.cs
Normal file
22
SVSim.BattleEngine/Rng/SeededRandomSource.cs
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace SVSim.BattleEngine.Rng
|
||||||
|
{
|
||||||
|
// Default source. Faithfully reproduces the engine's own RNG: BattleManagerBase seeds two separate
|
||||||
|
// System.Random(RandomSeed) instances (_stableRandom synced, _stableRandomOnlySelf self-only) at
|
||||||
|
// BattleManagerBase.cs:721-722. The authoritative server uses this; tests use ScriptedRandomSource.
|
||||||
|
public sealed class SeededRandomSource : IRandomSource
|
||||||
|
{
|
||||||
|
private readonly Random _synced;
|
||||||
|
private readonly Random _self;
|
||||||
|
|
||||||
|
public SeededRandomSource(int seed)
|
||||||
|
{
|
||||||
|
_synced = new Random(seed);
|
||||||
|
_self = new Random(seed);
|
||||||
|
}
|
||||||
|
|
||||||
|
public double NextUnit() => _synced.NextDouble();
|
||||||
|
public int NextSelf(int max) => _self.Next(max);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user