Use Raphael's application of MacroSolver

This commit is contained in:
Asriel Camora
2024-11-28 13:52:09 -08:00
parent f89203a745
commit 127fa43757
3 changed files with 98 additions and 49 deletions
+26 -16
View File
@@ -151,7 +151,7 @@ public sealed class Settings : Window, IDisposable
SolverAlgorithm.Stepwise => "Stepwise", SolverAlgorithm.Stepwise => "Stepwise",
SolverAlgorithm.StepwiseForked => "Stepwise Forked", SolverAlgorithm.StepwiseForked => "Stepwise Forked",
SolverAlgorithm.StepwiseGenetic => "Stepwise Genetic", SolverAlgorithm.StepwiseGenetic => "Stepwise Genetic",
SolverAlgorithm.Raphael => "Optimal (Slow)", SolverAlgorithm.Raphael => "Optimal",
_ => "Unknown", _ => "Unknown",
}; };
@@ -652,7 +652,15 @@ public sealed class Settings : Window, IDisposable
else else
{ {
DrawOption( DrawOption(
"Ensure 100% Reliability", "Quick Solve",
"Speeds up solve times. Backloads all Progress " +
"actions to the end of the rotation.",
config.BackloadProgress,
v => config = config with { BackloadProgress = v },
ref isDirty
);
DrawOption(
"Ensure Reliability",
"Find a rotation that can reach the target quality no matter " + "Find a rotation that can reach the target quality no matter " +
"how unlucky the random conditions are.", "how unlucky the random conditions are.",
config.Adversarial, config.Adversarial,
@@ -660,13 +668,24 @@ public sealed class Settings : Window, IDisposable
ref isDirty ref isDirty
); );
DrawOption( DrawOption(
"Backload Progress", "Minimize Steps",
"Find a rotation that only uses Progress-increasing actions " + "Minimizes the number of crafting steps.",
"at the end of the rotation. May speed up solve times.", config.MinimizeSteps,
config.BackloadProgress, v => config = config with { MinimizeSteps = v },
v => config = config with { BackloadProgress = v },
ref isDirty ref isDirty
); );
if (config.MinimizeSteps && config.Adversarial)
{
ImGui.SameLine();
using (var color = ImRaii.PushColor(ImGuiCol.Text, ImGuiColors.DalamudOrange))
{
using var font = ImRaii.PushFont(UiBuilder.IconFont);
ImGui.TextUnformatted(FontAwesomeIcon.ExclamationCircle.ToIconString());
}
if (ImGui.IsItemHovered())
ImGuiUtils.TooltipWrapped("Combining \"Minimize Steps\" and \"Ensure Reliability\" will significantly increase solve times.");
}
} }
} }
@@ -713,15 +732,6 @@ public sealed class Settings : Window, IDisposable
} }
} }
// TODO: Provide better option name than this lol
//DrawOption(
// "Unsound Branch Pruning",
// "TBD",
// config.UnsoundBranchPruning,
// v => config = config with { UnsoundBranchPruning = v },
// ref isDirty
//);
if (config.Algorithm != SolverAlgorithm.Raphael) if (config.Algorithm != SolverAlgorithm.Raphael)
{ {
using (var panel = ImRaii2.GroupPanel("Score Weights (Advanced)", -1, out _)) using (var panel = ImRaii2.GroupPanel("Score Weights (Advanced)", -1, out _))
+66 -31
View File
@@ -156,15 +156,6 @@ public sealed class Solver : IDisposable
maxProgress = 2000; maxProgress = 2000;
Raphael.SolverConfig config = new()
{
Adversarial = Config.Adversarial,
BackloadProgress = Config.BackloadProgress,
UnsoundBranchPruning = Config.UnsoundBranchPruning,
};
ActionType[]? solution = null;
var s = new SimulatorNoRandom() { State = State }; var s = new SimulatorNoRandom() { State = State };
var pool = RaphaelUtils.ConvertToRawActions(Config.ActionPool.Where(a => a.Base().IsPossible(s)).ToArray()); var pool = RaphaelUtils.ConvertToRawActions(Config.ActionPool.Where(a => a.Base().IsPossible(s)).ToArray());
var input = new Raphael.SolverInput() var input = new Raphael.SolverInput()
@@ -178,33 +169,83 @@ public sealed class Solver : IDisposable
JobLevel = checked((byte)State.Input.Stats.Level), JobLevel = checked((byte)State.Input.Stats.Level),
}; };
using Raphael.Solver solver = new(in config, input, pool); SimulationState ExecuteActions(IEnumerable<ActionType> actions)
solver.OnFinish += s => solution = RaphaelUtils.ConvertRawActions(s);
solver.OnSuggestSolution += s =>
{ {
var steps = RaphaelUtils.ConvertRawActions(s);
var sim = new SimulatorNoRandom(); var sim = new SimulatorNoRandom();
var (resp, outState, failedIdx) = sim.ExecuteMultiple(State, steps); var (resp, outState, failedIdx) = sim.ExecuteMultiple(State, actions);
if (resp != ActionResponse.SimulationComplete) if (resp != ActionResponse.SimulationComplete)
{ {
if (failedIdx != -1) if (failedIdx != -1)
OnLog?.Invoke($"Invalid state; simulation failed to execute solution: {string.Join(',', s)}"); throw new ArgumentException($"Invalid state; simulation failed to execute solution: {string.Join(',', actions)}", nameof(actions));
} }
return outState;
}
OnSuggestSolution?.Invoke(new(steps, in outState)); ActionType[]? solution = null;
};
solver.OnProgress += p => void OnFinish(Raphael.Action[] s) =>
solution = RaphaelUtils.ConvertRawActions(s);
void OnSuggestSolution(Raphael.Action[] s)
{
var steps = RaphaelUtils.ConvertRawActions(s);
var outState = ExecuteActions(steps);
this.OnSuggestSolution?.Invoke(new(steps, in outState));
}
void OnProgress(nuint p)
{ {
var prog = checked((int)p); var prog = checked((int)p);
var stage = prog / maxProgress; var stage = prog / maxProgress;
while (stage != progressStage) while (stage != progressStage)
ResetProgress(); ResetProgress();
progress = prog % maxProgress; progress = prog % maxProgress;
}; }
await using var registration = Token.Register(solver.Cancel).ConfigureAwait(true); if (!Config.MinimizeSteps)
await Task.Run(solver.Solve, Token).ConfigureAwait(true); {
Raphael.SolverConfig config = new()
{
Adversarial = Config.Adversarial,
BackloadProgress = true,
UnsoundBranchPruning = true
};
using var solver = new Raphael.Solver(in config, in input, pool);
solver.OnFinish += OnFinish;
solver.OnSuggestSolution += OnSuggestSolution;
solver.OnProgress += OnProgress;
progressStage = 0;
progress = 0;
await using var registration = Token.Register(solver.Cancel).ConfigureAwait(true);
await Task.Run(solver.Solve, Token).ConfigureAwait(true);
Token.ThrowIfCancellationRequested();
}
if (solution == null || ExecuteActions(solution).HQPercent != 100)
{
Raphael.SolverConfig config = new()
{
Adversarial = Config.Adversarial,
BackloadProgress = Config.BackloadProgress,
UnsoundBranchPruning = false
};
using var solver = new Raphael.Solver(in config, in input, pool);
solver.OnFinish += OnFinish;
solver.OnSuggestSolution += OnSuggestSolution;
solver.OnProgress += OnProgress;
progressStage = 0;
progress = 0;
await using var registration = Token.Register(solver.Cancel).ConfigureAwait(true);
await Task.Run(solver.Solve, Token).ConfigureAwait(true);
Token.ThrowIfCancellationRequested();
}
if (solution == null) if (solution == null)
return new([], State); return new([], State);
@@ -212,14 +253,8 @@ public sealed class Solver : IDisposable
foreach (var action in solution) foreach (var action in solution)
InvokeNewAction(action); InvokeNewAction(action);
var sim = new SimulatorNoRandom(); var outState = ExecuteActions(solution);
var (resp, outState, failedIdx) = sim.ExecuteMultiple(State, solution); return new(solution, in outState);
if (resp != ActionResponse.SimulationComplete)
{
if (failedIdx != -1)
throw new Exception($"Invalid state; simulation failed to execute solution: {string.Join(',', solution)}");
}
return new(solution, outState);
} }
private async Task<SolverSolution> SearchStepwiseGenetic() private async Task<SolverSolution> SearchStepwiseGenetic()
+6 -2
View File
@@ -17,6 +17,7 @@ public enum SolverAlgorithm
[StructLayout(LayoutKind.Auto)] [StructLayout(LayoutKind.Auto)]
public readonly record struct SolverConfig public readonly record struct SolverConfig
{ {
// MCTS configuration
public int Iterations { get; init; } public int Iterations { get; init; }
public int MaxIterations { get; init; } public int MaxIterations { get; init; }
public float MaxScoreWeightingConstant { get; init; } public float MaxScoreWeightingConstant { get; init; }
@@ -28,15 +29,17 @@ public readonly record struct SolverConfig
public int FurcatedActionCount { get; init; } public int FurcatedActionCount { get; init; }
public bool StrictActions { get; init; } public bool StrictActions { get; init; }
// MCTS score weights
public float ScoreProgress { get; init; } public float ScoreProgress { get; init; }
public float ScoreQuality { get; init; } public float ScoreQuality { get; init; }
public float ScoreDurability { get; init; } public float ScoreDurability { get; init; }
public float ScoreCP { get; init; } public float ScoreCP { get; init; }
public float ScoreSteps { get; init; } public float ScoreSteps { get; init; }
// Raphael/A* configuration
public bool Adversarial { get; init; } public bool Adversarial { get; init; }
public bool BackloadProgress { get; init; } public bool BackloadProgress { get; init; }
public bool UnsoundBranchPruning { get; init; } public bool MinimizeSteps { get; init; }
public ActionType[] ActionPool { get; init; } public ActionType[] ActionPool { get; init; }
public SolverAlgorithm Algorithm { get; init; } public SolverAlgorithm Algorithm { get; init; }
@@ -190,7 +193,8 @@ public readonly record struct SolverConfig
public static readonly SolverConfig EditorDefault = new SolverConfig() with public static readonly SolverConfig EditorDefault = new SolverConfig() with
{ {
Iterations = 500000 Algorithm = SolverAlgorithm.Raphael,
Adversarial = true
}; };
public static readonly SolverConfig SynthHelperDefault = new SolverConfig() with public static readonly SolverConfig SynthHelperDefault = new SolverConfig() with