From 127fa4375709ccba79dec50ae9c5b6efdcbb3743 Mon Sep 17 00:00:00 2001 From: Asriel Camora Date: Thu, 28 Nov 2024 13:52:09 -0800 Subject: [PATCH] Use Raphael's application of MacroSolver --- Craftimizer/Windows/Settings.cs | 42 ++++++++------ Solver/Solver.cs | 97 ++++++++++++++++++++++----------- Solver/SolverConfig.cs | 8 ++- 3 files changed, 98 insertions(+), 49 deletions(-) diff --git a/Craftimizer/Windows/Settings.cs b/Craftimizer/Windows/Settings.cs index 7058caf..ab1cc64 100644 --- a/Craftimizer/Windows/Settings.cs +++ b/Craftimizer/Windows/Settings.cs @@ -151,7 +151,7 @@ private static string GetAlgorithmName(SolverAlgorithm algorithm) => SolverAlgorithm.Stepwise => "Stepwise", SolverAlgorithm.StepwiseForked => "Stepwise Forked", SolverAlgorithm.StepwiseGenetic => "Stepwise Genetic", - SolverAlgorithm.Raphael => "Optimal (Slow)", + SolverAlgorithm.Raphael => "Optimal", _ => "Unknown", }; @@ -652,7 +652,15 @@ ref isDirty else { 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 " + "how unlucky the random conditions are.", config.Adversarial, @@ -660,13 +668,24 @@ ref isDirty ref isDirty ); DrawOption( - "Backload Progress", - "Find a rotation that only uses Progress-increasing actions " + - "at the end of the rotation. May speed up solve times.", - config.BackloadProgress, - v => config = config with { BackloadProgress = v }, + "Minimize Steps", + "Minimizes the number of crafting steps.", + config.MinimizeSteps, + v => config = config with { MinimizeSteps = v }, 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 @@ ref isDirty } } - // 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) { using (var panel = ImRaii2.GroupPanel("Score Weights (Advanced)", -1, out _)) diff --git a/Solver/Solver.cs b/Solver/Solver.cs index b06c68a..18d5ec8 100644 --- a/Solver/Solver.cs +++ b/Solver/Solver.cs @@ -156,15 +156,6 @@ private async Task SearchRaphael() 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 pool = RaphaelUtils.ConvertToRawActions(Config.ActionPool.Where(a => a.Base().IsPossible(s)).ToArray()); var input = new Raphael.SolverInput() @@ -178,33 +169,83 @@ private async Task SearchRaphael() JobLevel = checked((byte)State.Input.Stats.Level), }; - using Raphael.Solver solver = new(in config, input, pool); - - solver.OnFinish += s => solution = RaphaelUtils.ConvertRawActions(s); - solver.OnSuggestSolution += s => + SimulationState ExecuteActions(IEnumerable actions) { - var steps = RaphaelUtils.ConvertRawActions(s); 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 (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)); - }; - solver.OnProgress += p => + ActionType[]? solution = null; + + 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 stage = prog / maxProgress; while (stage != progressStage) ResetProgress(); progress = prog % maxProgress; - }; - - await using var registration = Token.Register(solver.Cancel).ConfigureAwait(true); - await Task.Run(solver.Solve, Token).ConfigureAwait(true); + } + + if (!Config.MinimizeSteps) + { + 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) return new([], State); @@ -212,14 +253,8 @@ private async Task SearchRaphael() foreach (var action in solution) InvokeNewAction(action); - var sim = new SimulatorNoRandom(); - var (resp, outState, failedIdx) = sim.ExecuteMultiple(State, solution); - if (resp != ActionResponse.SimulationComplete) - { - if (failedIdx != -1) - throw new Exception($"Invalid state; simulation failed to execute solution: {string.Join(',', solution)}"); - } - return new(solution, outState); + var outState = ExecuteActions(solution); + return new(solution, in outState); } private async Task SearchStepwiseGenetic() diff --git a/Solver/SolverConfig.cs b/Solver/SolverConfig.cs index 82a4d1e..d7abbe7 100644 --- a/Solver/SolverConfig.cs +++ b/Solver/SolverConfig.cs @@ -17,6 +17,7 @@ public enum SolverAlgorithm [StructLayout(LayoutKind.Auto)] public readonly record struct SolverConfig { + // MCTS configuration public int Iterations { get; init; } public int MaxIterations { get; init; } public float MaxScoreWeightingConstant { get; init; } @@ -28,15 +29,17 @@ public readonly record struct SolverConfig public int FurcatedActionCount { get; init; } public bool StrictActions { get; init; } + // MCTS score weights public float ScoreProgress { get; init; } public float ScoreQuality { get; init; } public float ScoreDurability { get; init; } public float ScoreCP { get; init; } public float ScoreSteps { get; init; } + // Raphael/A* configuration public bool Adversarial { get; init; } public bool BackloadProgress { get; init; } - public bool UnsoundBranchPruning { get; init; } + public bool MinimizeSteps { get; init; } public ActionType[] ActionPool { get; init; } public SolverAlgorithm Algorithm { get; init; } @@ -190,7 +193,8 @@ public SolverConfig FilterSpecialistActions() => public static readonly SolverConfig EditorDefault = new SolverConfig() with { - Iterations = 500000 + Algorithm = SolverAlgorithm.Raphael, + Adversarial = true }; public static readonly SolverConfig SynthHelperDefault = new SolverConfig() with