Program: Switch to sead::Random as the RNG

.NET's built-in algorithms don't let me save their internal state for debugging purposes.
This commit is contained in:
OatmealDome 2024-08-11 13:48:03 -04:00
parent 7eebc76421
commit 8a34971659
2 changed files with 101 additions and 13 deletions

View File

@ -1,4 +1,4 @@
using System.CommandLine;
using System.CommandLine;
using System.CommandLine.Invocation;
using System.Text.Json;
using OatmealDome.BinaryData;
@ -54,8 +54,6 @@ List<VersusRule> defaultGachiRulePool = new List<VersusRule>()
VersusRule.Lift
};
Random random = new Random();
//
// Command handling
//
@ -97,6 +95,11 @@ void Run(InvocationContext context)
int phaseLength = context.ParseResult.GetValueForOption(phaseLengthOption);
int scheduleLength = context.ParseResult.GetValueForOption(scheduleLengthOption);
string? overridePhasesPath = context.ParseResult.GetValueForOption(overridePhasesOption);
uint seed = (uint)Environment.TickCount;
SeadRandom random = new SeadRandom(seed);
Console.WriteLine("Random seed: " + seed);
dynamic lastByaml = ByamlFile.Load(lastByamlPath);
@ -256,7 +259,7 @@ void Run(InvocationContext context)
for (int j = currentPhase.RegularInfo.Stages.Count; j < 2; j++)
{
currentPhase.RegularInfo.Stages.Add(PickStage(currentPhase, lastPhase, nextOverridePhase, VersusRule.Paint,
stagePools[VersusRule.Paint]));
stagePools[VersusRule.Paint], random));
}
currentPhase.RegularInfo.Stages.Sort();
@ -264,13 +267,13 @@ void Run(InvocationContext context)
if (currentPhase.GachiInfo.Rule == VersusRule.None)
{
currentPhase.GachiInfo.Rule = PickGachiRule(currentPhase.GachiInfo, lastPhase.GachiInfo, nextOverridePhase,
gachiRulePool);
gachiRulePool, random);
}
for (int j = currentPhase.GachiInfo.Stages.Count; j < 2; j++)
{
currentPhase.GachiInfo.Stages.Add(PickStage(currentPhase, lastPhase, nextOverridePhase,
currentPhase.GachiInfo.Rule, stagePools[currentPhase.GachiInfo.Rule]));
currentPhase.GachiInfo.Rule, stagePools[currentPhase.GachiInfo.Rule], random));
}
currentPhase.GachiInfo.Stages.Sort();
@ -320,14 +323,14 @@ void Run(InvocationContext context)
// Utility function to pick a random element from a pool.
//
T GetRandomElementFromPool<T>(List<T> pool, Func<T, bool> validityChecker)
T GetRandomElementFromPool<T>(List<T> pool, Func<T, bool> validityChecker, SeadRandom random)
{
T element;
int tries = 0;
do
{
element = pool[random.Next(0, pool.Count)];
element = pool[random.GetInt32(pool.Count)];
tries++;
@ -347,7 +350,7 @@ T GetRandomElementFromPool<T>(List<T> pool, Func<T, bool> validityChecker)
//
VersusRule PickGachiRule(GambitStageInfo stageInfo, GambitStageInfo lastStageInfo, OverridePhase? nextPhaseOverride,
List<VersusRule> pool)
List<VersusRule> pool, SeadRandom random)
{
if (pool.Count == 0)
{
@ -363,13 +366,13 @@ VersusRule PickGachiRule(GambitStageInfo stageInfo, GambitStageInfo lastStageInf
return false;
}
}
return rule != lastStageInfo.Rule;
});
}, random);
}
int PickStage(GambitVersusPhase phase, GambitVersusPhase lastPhase, OverridePhase? nextPhaseOverride, VersusRule rule,
List<int> pool)
List<int> pool, SeadRandom random)
{
List<int> bannedStagesForRule = bannedStages[rule];
@ -418,5 +421,5 @@ int PickStage(GambitVersusPhase phase, GambitVersusPhase lastPhase, OverridePhas
pool = newPool.ToList();
}
return GetRandomElementFromPool(pool, IsStageValid);
return GetRandomElementFromPool(pool, IsStageValid, random);
}

View File

@ -0,0 +1,85 @@
namespace Rotationator;
// sead::Random
public class SeadRandom
{
private readonly uint[] _state;
public SeadRandom() : this((uint)Environment.TickCount)
{
}
public SeadRandom(uint seed)
{
_state = new uint[4];
_state[0] = 1812433253 * (seed ^ (seed >> 30)) + 1;
_state[1] = 1812433253 * (_state[0] ^ (_state[0] >> 30)) + 2;
_state[2] = 1812433253 * (_state[1] ^ (_state[1] >> 30)) + 3;
_state[3] = 1812433253 * (_state[2] ^ (_state[2] >> 30)) + 4;
}
public SeadRandom(uint seedOne, uint seedTwo, uint seedThree, uint seedFour)
{
_state = new uint[] { seedOne, seedTwo, seedThree, seedFour };
}
public SeadRandom(uint[] context)
{
if (context.Length != 4)
{
throw new ArgumentException("Invalid context for SeadRandom");
}
_state = context;
}
public uint GetUInt32()
{
uint v1 = _state[0] ^ (_state[0] << 11);
_state[0] = _state[1];
uint v2 = _state[3];
uint v3 = v1 ^ (v1 >> 8) ^ v2 ^ (v2 >> 19);
_state[1] = _state[2];
_state[2] = v2;
_state[3] = v3;
return v3;
}
// f32 al::getRandom()
public float GetSingle()
{
uint random = (GetUInt32() >> 9) | 0x3F800000;
return BitConverter.UInt32BitsToSingle(random) + -1.0f;
}
// f32 al::getRandom(f32, f32)
public float GetSingle(float min, float max)
{
return (GetSingle() * (max - min)) + min;
}
// f32 al::getRandom(f32)
public float GetSingle(float factor)
{
return GetSingle(0.0f, factor);
}
// s32 al::getRandom(s32, s32)
public int GetInt32(int min, int max)
{
return (int)GetSingle(min, max);
}
// s32 al::getRandom(s32)
public int GetInt32(int factor)
{
return GetInt32(0, factor);
}
public uint[] GetContext()
{
return _state;
}
}