From 47c9339d56b25f91219da4a604ca45b6747fed90 Mon Sep 17 00:00:00 2001 From: Asriel Camora Date: Tue, 20 Jun 2023 22:37:59 -0700 Subject: [PATCH] Replace ActionHistory with persistent ActionStatuses --- Craftimizer/SimulatorWindow.cs | 21 +++++++++--------- Simulator/ActionStates.cs | 29 +++++++++++++++++++++++++ Simulator/Actions/AdvancedTouch.cs | 2 +- Simulator/Actions/CarefulObservation.cs | 2 +- Simulator/Actions/FocusedSynthesis.cs | 2 +- Simulator/Actions/FocusedTouch.cs | 2 +- Simulator/Actions/HeartAndSoul.cs | 2 +- Simulator/Actions/StandardTouch.cs | 2 +- Simulator/SimulationState.cs | 8 +++---- Simulator/Simulator.cs | 18 +++++++-------- Solver/Crafty/Simulator.cs | 6 ++--- Solver/Crafty/Solver.cs | 10 ++++----- 12 files changed, 66 insertions(+), 38 deletions(-) create mode 100644 Simulator/ActionStates.cs diff --git a/Craftimizer/SimulatorWindow.cs b/Craftimizer/SimulatorWindow.cs index f3e9d0a..839887e 100644 --- a/Craftimizer/SimulatorWindow.cs +++ b/Craftimizer/SimulatorWindow.cs @@ -122,16 +122,17 @@ public class SimulatorWindow : Window } ImGuiHelpers.ScaledDummy(5); { - var i = 0; - foreach (var action in State.ActionHistory) - { - var baseAction = action.With(Simulation); - ImGui.Image(action.GetIcon(ClassJob.Carpenter).ImGuiHandle, new Vector2(ImGui.GetFontSize() * 2f)); - if (ImGui.IsItemHovered()) - ImGui.SetTooltip($"{action.GetName(ClassJob.Carpenter)}\n{baseAction.GetTooltip(false)}"); - if (++i % 5 != 0) - ImGui.SameLine(); - } + ImGui.Text("TODO: Action History"); + //var i = 0; + //foreach (var action in State.ActionHistory) + //{ + // var baseAction = action.With(Simulation); + // ImGui.Image(action.GetIcon(ClassJob.Carpenter).ImGuiHandle, new Vector2(ImGui.GetFontSize() * 2f)); + // if (ImGui.IsItemHovered()) + // ImGui.SetTooltip($"{action.GetName(ClassJob.Carpenter)}\n{baseAction.GetTooltip(false)}"); + // if (++i % 5 != 0) + // ImGui.SameLine(); + //} } ImGui.EndChild(); ImGui.EndTable(); diff --git a/Simulator/ActionStates.cs b/Simulator/ActionStates.cs new file mode 100644 index 0000000..c3210c7 --- /dev/null +++ b/Simulator/ActionStates.cs @@ -0,0 +1,29 @@ +using Craftimizer.Simulator.Actions; + +namespace Craftimizer.Simulator; + +public record struct ActionStates +{ + public byte TouchComboIdx { get; set; } + public byte CarefulObservationCount { get; set; } + public bool UsedHeartAndSoul { get; set; } + public bool Observed { get; set; } + + public void MutateState(ActionType action) + { + if (action == ActionType.BasicTouch) + TouchComboIdx = 1; + else if (TouchComboIdx == 1 && action == ActionType.StandardTouch) + TouchComboIdx = 2; + else + TouchComboIdx = 0; + + if (action == ActionType.CarefulObservation) + CarefulObservationCount++; + + if (action == ActionType.HeartAndSoul) + UsedHeartAndSoul = true; + + Observed = action == ActionType.Observe; + } +} diff --git a/Simulator/Actions/AdvancedTouch.cs b/Simulator/Actions/AdvancedTouch.cs index d234b77..abd1378 100644 --- a/Simulator/Actions/AdvancedTouch.cs +++ b/Simulator/Actions/AdvancedTouch.cs @@ -6,7 +6,7 @@ internal sealed class AdvancedTouch : BaseAction public override int Level => 84; public override uint ActionId => 100411; - public override int CPCost => Simulation.IsPreviousAction(ActionType.StandardTouch) && Simulation.IsPreviousAction(ActionType.BasicTouch, 2) ? 18 : 46; + public override int CPCost => Simulation.ActionStates.TouchComboIdx == 2 ? 18 : 46; public override float Efficiency => 1.50f; public override bool IncreasesQuality => true; } diff --git a/Simulator/Actions/CarefulObservation.cs b/Simulator/Actions/CarefulObservation.cs index cdd12f3..4115fab 100644 --- a/Simulator/Actions/CarefulObservation.cs +++ b/Simulator/Actions/CarefulObservation.cs @@ -10,7 +10,7 @@ internal sealed class CarefulObservation : BaseAction public override int DurabilityCost => 0; public override bool IncreasesStepCount => false; - public override bool CanUse => Simulation.Input.Stats.IsSpecialist && Simulation.CountPreviousAction(ActionType.CarefulObservation) < 3; + public override bool CanUse => Simulation.Input.Stats.IsSpecialist && Simulation.ActionStates.CarefulObservationCount < 3; public override void UseSuccess() => Simulation.StepCondition(); diff --git a/Simulator/Actions/FocusedSynthesis.cs b/Simulator/Actions/FocusedSynthesis.cs index 075c3f2..0725d8b 100644 --- a/Simulator/Actions/FocusedSynthesis.cs +++ b/Simulator/Actions/FocusedSynthesis.cs @@ -9,5 +9,5 @@ internal sealed class FocusedSynthesis : BaseAction public override int CPCost => 5; public override float Efficiency => 2.00f; public override bool IncreasesProgress => true; - public override float SuccessRate => Simulation.IsPreviousAction(ActionType.Observe) ? 1.00f : 0.50f; + public override float SuccessRate => Simulation.ActionStates.Observed ? 1.00f : 0.50f; } diff --git a/Simulator/Actions/FocusedTouch.cs b/Simulator/Actions/FocusedTouch.cs index 667305b..4a836c0 100644 --- a/Simulator/Actions/FocusedTouch.cs +++ b/Simulator/Actions/FocusedTouch.cs @@ -9,5 +9,5 @@ internal sealed class FocusedTouch : BaseAction public override int CPCost => 18; public override float Efficiency => 1.50f; public override bool IncreasesQuality => true; - public override float SuccessRate => Simulation.IsPreviousAction(ActionType.Observe) ? 1.00f : 0.50f; + public override float SuccessRate => Simulation.ActionStates.Observed ? 1.00f : 0.50f; } diff --git a/Simulator/Actions/HeartAndSoul.cs b/Simulator/Actions/HeartAndSoul.cs index 8311779..78851f4 100644 --- a/Simulator/Actions/HeartAndSoul.cs +++ b/Simulator/Actions/HeartAndSoul.cs @@ -11,5 +11,5 @@ internal sealed class HeartAndSoul : BaseBuffAction public override EffectType Effect => EffectType.HeartAndSoul; - public override bool CanUse => Simulation.Input.Stats.IsSpecialist && Simulation.CountPreviousAction(ActionType.HeartAndSoul) == 0; + public override bool CanUse => Simulation.Input.Stats.IsSpecialist && !Simulation.ActionStates.UsedHeartAndSoul; } diff --git a/Simulator/Actions/StandardTouch.cs b/Simulator/Actions/StandardTouch.cs index 087ff41..4fd0b9d 100644 --- a/Simulator/Actions/StandardTouch.cs +++ b/Simulator/Actions/StandardTouch.cs @@ -6,7 +6,7 @@ internal sealed class StandardTouch : BaseAction public override int Level => 18; public override uint ActionId => 100004; - public override int CPCost => Simulation.IsPreviousAction(ActionType.BasicTouch) ? 18 : 32; + public override int CPCost => Simulation.ActionStates.TouchComboIdx == 1 ? 18 : 32; public override float Efficiency => 1.25f; public override bool IncreasesQuality => true; } diff --git a/Simulator/SimulationState.cs b/Simulator/SimulationState.cs index c767199..c2ae295 100644 --- a/Simulator/SimulationState.cs +++ b/Simulator/SimulationState.cs @@ -6,8 +6,7 @@ public readonly record struct SimulationState { public SimulationInput Input { get; init; } - public int ActionCount => ActionHistory.Count; - + public int ActionCount { get; init; } public int StepCount { get; init; } public int Progress { get; init; } public int Quality { get; init; } @@ -15,7 +14,7 @@ public readonly record struct SimulationState public int CP { get; init; } public Condition Condition { get; init; } public Effects ActiveEffects { get; init; } - public List ActionHistory { get; init; } + public ActionStates ActionStates { get; init; } // https://github.com/ffxiv-teamcraft/simulator/blob/0682dfa76043ff4ccb38832c184d046ceaff0733/src/model/tables.ts#L2 private static readonly int[] HQPercentTable = { @@ -39,6 +38,7 @@ public readonly record struct SimulationState CP = Input.Stats.CP; Condition = Condition.Normal; ActiveEffects = new(); - ActionHistory = new(); + ActionCount = 0; + ActionStates = new(); } } diff --git a/Simulator/Simulator.cs b/Simulator/Simulator.cs index c2adbb8..e4bd2a1 100644 --- a/Simulator/Simulator.cs +++ b/Simulator/Simulator.cs @@ -5,6 +5,7 @@ namespace Craftimizer.Simulator; public class Simulator { public SimulationInput Input { get; private set; } + public int ActionCount { get; private set; } public int StepCount { get; private set; } public int Progress { get; private set; } public int Quality { get; private set; } @@ -12,7 +13,7 @@ public class Simulator public int CP { get; private set; } public Condition Condition { get; private set; } public Effects ActiveEffects; - public List ActionHistory { get; private set; } + public ActionStates ActionStates; public bool IsFirstStep => StepCount == 0; @@ -41,6 +42,7 @@ public class Simulator private void Emplace(SimulationState state) { Input = state.Input; + ActionCount = state.ActionCount; StepCount = state.StepCount; Progress = state.Progress; Quality = state.Quality; @@ -48,12 +50,13 @@ public class Simulator CP = state.CP; Condition = state.Condition; ActiveEffects = state.ActiveEffects; - ActionHistory = new(state.ActionHistory); + ActionStates = state.ActionStates; } private SimulationState Displace() => new() { Input = Input, + ActionCount = ActionCount, StepCount = StepCount, Progress = Progress, Quality = Quality, @@ -61,7 +64,7 @@ public class Simulator CP = CP, Condition = Condition, ActiveEffects = ActiveEffects, - ActionHistory = ActionHistory!, + ActionStates = ActionStates, }; public (ActionResponse Response, SimulationState NewState) Execute(SimulationState state, ActionType action) @@ -86,7 +89,8 @@ public class Simulator } baseAction.Use(); - ActionHistory!.Add(action); + ActionStates.MutateState(action); + ActionCount++; ActiveEffects.DecrementDuration(); @@ -119,12 +123,6 @@ public class Simulator public bool HasEffect(EffectType effect) => ActiveEffects.HasEffect(effect); - public bool IsPreviousAction(ActionType action, int stepsBack = 1) => - ActionHistory!.Count >= stepsBack && ActionHistory[^stepsBack] == action; - - public int CountPreviousAction(ActionType action) => - ActionHistory!.Count(a => a == action); - public virtual bool RollSuccessRaw(float successRate) => successRate >= Input.Random.NextSingle(); diff --git a/Solver/Crafty/Simulator.cs b/Solver/Crafty/Simulator.cs index 1e7193e..8afa032 100644 --- a/Solver/Crafty/Simulator.cs +++ b/Solver/Crafty/Simulator.cs @@ -7,7 +7,7 @@ namespace Craftimizer.Solver.Crafty; public class Simulator : Sim { public new CompletionState CompletionState => - (ActionHistory.Count + 1) >= Solver.MaxStepCount ? + (ActionCount + 1) >= Solver.MaxStepCount ? CompletionState.MaxActionCountReached : (CompletionState)base.CompletionState; public override bool IsComplete => CompletionState != CompletionState.Incomplete; @@ -65,7 +65,7 @@ public class Simulator : Sim return false; if (action == ActionType.Observe && - IsPreviousAction(ActionType.Observe)) + ActionStates.Observed) return false; if (action == ActionType.FinalAppraisal) @@ -78,7 +78,7 @@ public class Simulator : Sim return true; // only allow Focused moves after Observe - if (IsPreviousAction(ActionType.Observe) && + if (ActionStates.Observed && action != ActionType.FocusedSynthesis && action != ActionType.FocusedTouch) return false; diff --git a/Solver/Crafty/Solver.cs b/Solver/Crafty/Solver.cs index 56656b7..692f00e 100644 --- a/Solver/Crafty/Solver.cs +++ b/Solver/Crafty/Solver.cs @@ -242,12 +242,13 @@ public class Solver // playout to a terminal state var currentState = Tree.Get(expandedIndex).State; - var preCount = currentState.State.ActionCount; + var actions = new List(); while (true) { if (currentState.IsComplete) break; randomAction = currentState.AvailableActions.ElementAt(0); + actions.Add(randomAction); currentState = Execute(currentState.State, randomAction, true); } @@ -257,7 +258,7 @@ public class Solver { if (score >= ScoreStorageThreshold && score >= Tree.Get(0).State.Scores.MaxScore) { - (var terminalIndex, _) = ExecuteActions(expandedIndex, currentState.State.ActionHistory.Skip(preCount).ToList(), true); + (var terminalIndex, _) = ExecuteActions(expandedIndex, actions, true); return (terminalIndex, currentState.CompletionState, score); } } @@ -298,13 +299,12 @@ public class Solver { var actions = new List(); var node = Tree.Get(0); - while (node.Children.Count != 0) { + while (node.Children.Count != 0) + { var next_index = RustMaxBy(node.Children, n => Tree.Get(n).State.Scores.MaxScore); node = Tree.Get(next_index); if (node.State.Action != null) - { actions.Add(node.State.Action.Value); - } } return (actions, node.State);