Program: Implement the ability to override specific phases

This commit is contained in:
OatmealDome 2024-08-11 01:34:16 -04:00
parent a15ac807e8
commit 052cb0b45b
4 changed files with 187 additions and 20 deletions

View File

@ -19,6 +19,7 @@ Arguments:
Options:
--phaseLength <phaseLength> The length of each phase in hours. [default: 4]
--scheduleLength <scheduleLength> How long the schedule should be in days. [default: 30]
--overridePhases <overridePhases> The override phases file. []
--version Show version information
-?, -h, --help Show help and usage information
```

View File

@ -70,4 +70,41 @@ public class GambitVersusPhase
return byamlPhase;
}
public void ApplyOverridePhase(OverridePhase overridePhase)
{
if (overridePhase.Length > 0)
{
Length = overridePhase.Length;
}
List<int> GetStageList(List<int> overrideList, List<int> normalList)
{
List<int> stages = new List<int>();
for (int i = 0; i < 2; i++)
{
int overrideStage = overrideList[i];
if (overrideStage != -1)
{
stages.Add(overrideStage);
}
else if (i < normalList.Count)
{
stages.Add(normalList[i]);
}
}
return stages;
}
RegularInfo.Stages = GetStageList(overridePhase.RegularStages, RegularInfo.Stages);
GachiInfo.Stages = GetStageList(overridePhase.GachiStages, GachiInfo.Stages);
if (overridePhase.GachiRule != VersusRule.None)
{
GachiInfo.Rule = overridePhase.GachiRule;
}
}
}

View File

@ -0,0 +1,28 @@
namespace Rotationator;
public class OverridePhase
{
public int Length
{
get;
set;
}
public List<int> RegularStages
{
get;
set;
}
public VersusRule GachiRule
{
get;
set;
}
public List<int> GachiStages
{
get;
set;
}
}

View File

@ -1,4 +1,4 @@
using System.CommandLine;
using System.CommandLine;
using System.CommandLine.Invocation;
using System.Text.Json;
using OatmealDome.BinaryData;
@ -70,12 +70,16 @@ Option<int> phaseLengthOption =
Option<int> scheduleLengthOption = new Option<int>("--scheduleLength", () => defaultScheduleLength,
"How long the schedule should be in days.");
Option<string?> overridePhasesOption =
new Option<string?>("--overridePhases", () => null, "The override phases file.");
Command command = new RootCommand("Generates a new VSSetting BYAMl file.")
{
lastByamlArg,
outputByamlArg,
phaseLengthOption,
scheduleLengthOption
scheduleLengthOption,
overridePhasesOption
};
command.SetHandler(context => Run(context));
@ -92,6 +96,7 @@ void Run(InvocationContext context)
string outputByamlPath = context.ParseResult.GetValueForArgument(outputByamlArg);
int phaseLength = context.ParseResult.GetValueForOption(phaseLengthOption);
int scheduleLength = context.ParseResult.GetValueForOption(scheduleLengthOption);
string? overridePhasesPath = context.ParseResult.GetValueForOption(overridePhasesOption);
dynamic lastByaml = ByamlFile.Load(lastByamlPath);
@ -138,6 +143,28 @@ void Run(InvocationContext context)
// The last phase is set to 10 years, so correct this to the correct phase length.
currentPhases.Last().Length = phaseLength;
//
// Load the override phases
//
Dictionary<DateTime, OverridePhase> overridePhases;
if (overridePhasesPath != null)
{
string overridePhasesJson = File.ReadAllText(overridePhasesPath);
Dictionary<string, OverridePhase> overridePhasesStrKey =
JsonSerializer.Deserialize<Dictionary<string, OverridePhase>>(overridePhasesJson)!;
overridePhases = overridePhasesStrKey.Select(p =>
new KeyValuePair<DateTime, OverridePhase>(DateTime.Parse(p.Key).ToUniversalTime(), p.Value)).ToDictionary();
Console.WriteLine($"Loaded {overridePhases.Count} override phases");
}
else
{
overridePhases = new Dictionary<DateTime, OverridePhase>();
}
//
// Find the maximum number of phases to add.
//
@ -148,9 +175,19 @@ void Run(InvocationContext context)
for (int i = 0; i < currentPhases.Count; i++)
{
loopTime = loopTime.AddHours(currentPhases[i].Length);
GambitVersusPhase phase = currentPhases[i];
// This is the most convenient place to do this.
if (overridePhases.TryGetValue(loopTime, out OverridePhase? overridePhase))
{
phase.ApplyOverridePhase(overridePhase);
}
loopTime = loopTime.AddHours(phase.Length);
}
DateTime newPhaseBaseTime = loopTime;
int maximumPhases = currentPhases.Count;
// This definitely isn't the most efficient way to do this, but it works.
@ -158,7 +195,18 @@ void Run(InvocationContext context)
{
maximumPhases++;
loopTime = loopTime.AddHours(phaseLength);
int length;
if (overridePhases.TryGetValue(loopTime, out OverridePhase? phase))
{
length = phase.Length;
}
else
{
length = phaseLength;
}
loopTime = loopTime.AddHours(length);
}
Console.WriteLine($"Generating {maximumPhases} phases to reach {endTime:O} (already have {currentPhases.Count})");
@ -176,28 +224,60 @@ void Run(InvocationContext context)
{ VersusRule.Lift, new List<int>() }
};
DateTime currentTime = newPhaseBaseTime;
for (int i = currentPhases.Count; i < maximumPhases; i++)
{
GambitVersusPhase currentPhase = new GambitVersusPhase();
GambitVersusPhase lastPhase = i != 0 ? currentPhases[i - 1] : new GambitVersusPhase();
if (overridePhases.TryGetValue(currentTime, out OverridePhase? overridePhase))
{
currentPhase.ApplyOverridePhase(overridePhase);
}
VersusRule gachiRule = PickGachiRule(currentPhase.GachiInfo, lastPhase.GachiInfo, gachiRulePool);
// Calculate next phase time
if (currentPhase.Length <= 0)
{
currentPhase.Length = phaseLength;
}
DateTime nextPhaseTime = currentTime.AddHours(currentPhase.Length);
// Grab the next override phase for later use
overridePhases.TryGetValue(nextPhaseTime, out OverridePhase? nextOverridePhase);
// Populate rules and stages
currentPhase.RegularInfo.Rule = VersusRule.Paint;
currentPhase.RegularInfo.Stages.Add(PickStage(currentPhase, lastPhase, VersusRule.Paint,
stagePools[VersusRule.Paint]));
currentPhase.RegularInfo.Stages.Add(PickStage(currentPhase, lastPhase, VersusRule.Paint,
stagePools[VersusRule.Paint]));
for (int j = currentPhase.RegularInfo.Stages.Count; j < 2; j++)
{
currentPhase.RegularInfo.Stages.Add(PickStage(currentPhase, lastPhase, nextOverridePhase, VersusRule.Paint,
stagePools[VersusRule.Paint]));
}
currentPhase.RegularInfo.Stages.Sort();
currentPhase.GachiInfo.Rule = gachiRule;
currentPhase.GachiInfo.Stages.Add(PickStage(currentPhase, lastPhase, gachiRule, stagePools[gachiRule]));
currentPhase.GachiInfo.Stages.Add(PickStage(currentPhase, lastPhase, gachiRule, stagePools[gachiRule]));
if (currentPhase.GachiInfo.Rule == VersusRule.None)
{
currentPhase.GachiInfo.Rule = PickGachiRule(currentPhase.GachiInfo, lastPhase.GachiInfo, nextOverridePhase,
gachiRulePool);
}
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.Stages.Sort();
currentPhase.Length = phaseLength;
currentPhases.Add(currentPhase);
currentTime = nextPhaseTime;
}
//
@ -258,17 +338,30 @@ T GetRandomElementFromPool<T>(List<T> pool, Func<T, bool> validityChecker)
// Random stage + rule pickers.
//
VersusRule PickGachiRule(GambitStageInfo stageInfo, GambitStageInfo lastStageInfo, List<VersusRule> pool)
VersusRule PickGachiRule(GambitStageInfo stageInfo, GambitStageInfo lastStageInfo, OverridePhase? nextPhaseOverride,
List<VersusRule> pool)
{
if (pool.Count == 0)
{
pool.AddRange(defaultGachiRulePool);
}
return GetRandomElementFromPool(pool, rule => rule != lastStageInfo.Rule);
return GetRandomElementFromPool(pool, rule =>
{
if (nextPhaseOverride != null)
{
if (nextPhaseOverride.GachiRule == rule)
{
return false;
}
}
return rule != lastStageInfo.Rule;
});
}
int PickStage(GambitVersusPhase phase, GambitVersusPhase lastPhase, VersusRule rule, List<int> pool)
int PickStage(GambitVersusPhase phase, GambitVersusPhase lastPhase, OverridePhase? nextPhaseOverride, VersusRule rule,
List<int> pool)
{
List<int> bannedStagesForRule = bannedStages[rule];
@ -300,13 +393,21 @@ int PickStage(GambitVersusPhase phase, GambitVersusPhase lastPhase, VersusRule r
// If so, pick a random stage from the default pool, excluding:
// - the current phase's stages (in both Regular and Gachi)
// - the last phase's stages (in both Regular and Gachi)
// - the next phase's stages (in both Regular and Gachi, if known)
// - all banned stages for this rule
pool = defaultStagePool.Except(phase.RegularInfo.Stages)
IEnumerable<int> newPool = defaultStagePool.Except(phase.RegularInfo.Stages)
.Except(phase.GachiInfo.Stages)
.Except(lastPhase.RegularInfo.Stages)
.Except(lastPhase.GachiInfo.Stages)
.Except(bannedStagesForRule)
.ToList();
.Except(bannedStagesForRule);
if (nextPhaseOverride != null)
{
newPool = newPool.Except(nextPhaseOverride.RegularStages)
.Except(nextPhaseOverride.GachiStages);
}
pool = newPool.ToList();
}
return GetRandomElementFromPool(pool, IsStageValid);