Combo actions for better macro quality
This commit is contained in:
+18
-1
@@ -1,4 +1,5 @@
|
|||||||
using Craftimizer.Simulator;
|
using Craftimizer.Simulator;
|
||||||
|
using Craftimizer.Simulator.Actions;
|
||||||
using Craftimizer.Solver.Crafty;
|
using Craftimizer.Solver.Crafty;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
|
||||||
@@ -52,7 +53,23 @@ internal static class Program
|
|||||||
|
|
||||||
var sim = new SimulatorNoRandom(new(input));
|
var sim = new SimulatorNoRandom(new(input));
|
||||||
(_, var state) = sim.Execute(new(input), ActionType.MuscleMemory);
|
(_, var state) = sim.Execute(new(input), ActionType.MuscleMemory);
|
||||||
Console.WriteLine($"{state.Quality} {state.CP} {state.Progress}");
|
(_, state) = sim.Execute(state, ActionType.PrudentTouch);
|
||||||
|
(_, state) = sim.Execute(state, ActionType.Manipulation);
|
||||||
|
(_, state) = sim.Execute(state, ActionType.Veneration);
|
||||||
|
(_, state) = sim.Execute(state, ActionType.WasteNot);
|
||||||
|
(_, state) = sim.Execute(state, ActionType.Groundwork);
|
||||||
|
(_, state) = sim.Execute(state, ActionType.Groundwork);
|
||||||
|
(_, state) = sim.Execute(state, ActionType.Groundwork);
|
||||||
|
(_, state) = sim.Execute(state, ActionType.Innovation);
|
||||||
|
(_, state) = sim.Execute(state, ActionType.PrudentTouch);
|
||||||
|
(_, state) = sim.Execute(state, ActionType.AdvancedTouchCombo);
|
||||||
|
(_, state) = sim.Execute(state, ActionType.Manipulation);
|
||||||
|
(_, state) = sim.Execute(state, ActionType.Innovation);
|
||||||
|
(_, state) = sim.Execute(state, ActionType.PrudentTouch);
|
||||||
|
(_, state) = sim.Execute(state, ActionType.AdvancedTouchCombo);
|
||||||
|
(_, state) = sim.Execute(state, ActionType.GreatStrides);
|
||||||
|
|
||||||
|
Console.WriteLine($"{state.Quality} {state.CP} {state.Progress} {state.Durability}");
|
||||||
//return;
|
//return;
|
||||||
var (_, s) = Solver.Crafty.Solver.SearchStepwiseFurcated(config, state, a => Console.WriteLine(a));
|
var (_, s) = Solver.Crafty.Solver.SearchStepwiseFurcated(config, state, a => Console.WriteLine(a));
|
||||||
Console.WriteLine($"Qual: {s.Quality}/{s.Input.Recipe.MaxQuality}");
|
Console.WriteLine($"Qual: {s.Quality}/{s.Input.Recipe.MaxQuality}");
|
||||||
|
|||||||
@@ -38,7 +38,11 @@ public sealed partial class SimulatorWindow : Window, IDisposable
|
|||||||
|
|
||||||
static SimulatorWindow()
|
static SimulatorWindow()
|
||||||
{
|
{
|
||||||
SortedActions = Enum.GetValues<ActionType>().GroupBy(a => a.Category()).Select(g => (g.Key, g.OrderBy(a => a.Level()).ToArray())).ToArray();
|
SortedActions = Enum.GetValues<ActionType>()
|
||||||
|
.Where(a => a.Category() != ActionCategory.Combo)
|
||||||
|
.GroupBy(a => a.Category())
|
||||||
|
.Select(g => (g.Key, g.OrderBy(a => a.Level()).ToArray()))
|
||||||
|
.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Draw()
|
public override void Draw()
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ public enum ActionCategory
|
|||||||
Quality,
|
Quality,
|
||||||
Durability,
|
Durability,
|
||||||
Buffs,
|
Buffs,
|
||||||
|
Combo,
|
||||||
Other
|
Other
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -38,6 +38,11 @@ public enum ActionType : byte
|
|||||||
Veneration,
|
Veneration,
|
||||||
WasteNot,
|
WasteNot,
|
||||||
WasteNot2,
|
WasteNot2,
|
||||||
|
|
||||||
|
StandardTouchCombo,
|
||||||
|
AdvancedTouchCombo,
|
||||||
|
FocusedSynthesisCombo,
|
||||||
|
FocusedTouchCombo,
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class ActionUtils
|
public static class ActionUtils
|
||||||
@@ -106,6 +111,10 @@ public static class ActionUtils
|
|||||||
ActionType.Veneration => "Veneration",
|
ActionType.Veneration => "Veneration",
|
||||||
ActionType.WasteNot => "Waste Not",
|
ActionType.WasteNot => "Waste Not",
|
||||||
ActionType.WasteNot2 => "Waste Not II",
|
ActionType.WasteNot2 => "Waste Not II",
|
||||||
|
ActionType.StandardTouchCombo => "Standard Touch Combo",
|
||||||
|
ActionType.AdvancedTouchCombo => "Advanced Touch Combo",
|
||||||
|
ActionType.FocusedSynthesisCombo => "Focused Synthesis Combo",
|
||||||
|
ActionType.FocusedTouchCombo => "Focused Touch Combo",
|
||||||
_ => me.ToString(),
|
_ => me.ToString(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
namespace Craftimizer.Simulator.Actions;
|
||||||
|
|
||||||
|
// Basic Touch -> Standard Touch -> Advanced Touch
|
||||||
|
internal sealed class AdvancedTouchCombo : BaseAction
|
||||||
|
{
|
||||||
|
public override ActionCategory Category => ActionCategory.Combo;
|
||||||
|
public override int Level => 84;
|
||||||
|
public override uint ActionId => 100411;
|
||||||
|
|
||||||
|
public override bool IncreasesQuality => true;
|
||||||
|
|
||||||
|
public override int CPCost(Simulator s) => 18 + 18 + 18;
|
||||||
|
|
||||||
|
public override bool CanUse(Simulator s) =>
|
||||||
|
// BasicTouch.DurabilityCost vv vv StandardTouch.DurabilityCost
|
||||||
|
base.CanUse(s) && StandardTouchCombo.VerifyDurability3(s, 10, 10);
|
||||||
|
|
||||||
|
private static readonly BasicTouch ActionA = new();
|
||||||
|
private static readonly StandardTouch ActionB = new();
|
||||||
|
private static readonly AdvancedTouch ActionC = new();
|
||||||
|
public override void Use(Simulator s)
|
||||||
|
{
|
||||||
|
s.ExecuteForced(ActionType.BasicTouch, ActionA);
|
||||||
|
s.ExecuteForced(ActionType.StandardTouch, ActionB);
|
||||||
|
ActionC.Use(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string GetTooltip(Simulator s, bool addUsability) =>
|
||||||
|
$"{ActionA.GetTooltip(s, addUsability)}\n{ActionB.GetTooltip(s, addUsability)}\n{ActionC.GetTooltip(s, addUsability)}";
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
namespace Craftimizer.Simulator.Actions;
|
||||||
|
|
||||||
|
// Observe -> Focused Synthesis
|
||||||
|
internal sealed class FocusedSynthesisCombo : BaseAction
|
||||||
|
{
|
||||||
|
public override ActionCategory Category => ActionCategory.Combo;
|
||||||
|
public override int Level => 67;
|
||||||
|
public override uint ActionId => 100235;
|
||||||
|
|
||||||
|
public override bool IncreasesProgress => true;
|
||||||
|
|
||||||
|
public override int CPCost(Simulator s) => 7 + 5;
|
||||||
|
|
||||||
|
public override bool CanUse(Simulator s) =>
|
||||||
|
// Observe.DurabilityCost v
|
||||||
|
base.CanUse(s) && StandardTouchCombo.VerifyDurability2(s, 0);
|
||||||
|
|
||||||
|
private static readonly Observe ActionA = new();
|
||||||
|
private static readonly FocusedSynthesis ActionB = new();
|
||||||
|
public override void Use(Simulator s)
|
||||||
|
{
|
||||||
|
s.ExecuteForced(ActionType.Observe, ActionA);
|
||||||
|
ActionB.Use(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string GetTooltip(Simulator s, bool addUsability) =>
|
||||||
|
$"{ActionA.GetTooltip(s, addUsability)}\n{ActionB.GetTooltip(s, addUsability)}";
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
namespace Craftimizer.Simulator.Actions;
|
||||||
|
|
||||||
|
// Observe -> Focused Touch
|
||||||
|
internal sealed class FocusedTouchCombo : BaseAction
|
||||||
|
{
|
||||||
|
public override ActionCategory Category => ActionCategory.Combo;
|
||||||
|
public override int Level => 68;
|
||||||
|
public override uint ActionId => 100243;
|
||||||
|
|
||||||
|
public override bool IncreasesQuality => true;
|
||||||
|
|
||||||
|
public override int CPCost(Simulator s) => 7 + 18;
|
||||||
|
|
||||||
|
public override bool CanUse(Simulator s) =>
|
||||||
|
// Observe.DurabilityCost v
|
||||||
|
base.CanUse(s) && StandardTouchCombo.VerifyDurability2(s, 0);
|
||||||
|
|
||||||
|
private static readonly Observe ActionA = new();
|
||||||
|
private static readonly FocusedTouch ActionB = new();
|
||||||
|
public override void Use(Simulator s)
|
||||||
|
{
|
||||||
|
s.ExecuteForced(ActionType.Observe, ActionA);
|
||||||
|
ActionB.Use(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string GetTooltip(Simulator s, bool addUsability) =>
|
||||||
|
$"{ActionA.GetTooltip(s, addUsability)}\n{ActionB.GetTooltip(s, addUsability)}";
|
||||||
|
}
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
namespace Craftimizer.Simulator.Actions;
|
||||||
|
|
||||||
|
// Basic Touch -> Standard Touch
|
||||||
|
internal sealed class StandardTouchCombo : BaseAction
|
||||||
|
{
|
||||||
|
public override ActionCategory Category => ActionCategory.Combo;
|
||||||
|
public override int Level => 18;
|
||||||
|
public override uint ActionId => 100004;
|
||||||
|
|
||||||
|
public override bool IncreasesQuality => true;
|
||||||
|
|
||||||
|
public override int CPCost(Simulator s) => 18 + 18;
|
||||||
|
|
||||||
|
public override bool CanUse(Simulator s) =>
|
||||||
|
// BasicTouch.DurabilityCost vv
|
||||||
|
base.CanUse(s) && VerifyDurability2(s, 10);
|
||||||
|
|
||||||
|
private static readonly BasicTouch ActionA = new();
|
||||||
|
private static readonly StandardTouch ActionB = new();
|
||||||
|
public override void Use(Simulator s)
|
||||||
|
{
|
||||||
|
s.ExecuteForced(ActionType.BasicTouch, ActionA);
|
||||||
|
ActionB.Use(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string GetTooltip(Simulator s, bool addUsability) =>
|
||||||
|
$"{ActionA.GetTooltip(s, addUsability)}\n{ActionB.GetTooltip(s, addUsability)}";
|
||||||
|
|
||||||
|
public static bool VerifyDurability2(Simulator s, int durabilityA)
|
||||||
|
{
|
||||||
|
var d = s.Durability;
|
||||||
|
var wasteNots = s.HasEffect(EffectType.WasteNot) || s.HasEffect(EffectType.WasteNot2);
|
||||||
|
|
||||||
|
// -A
|
||||||
|
d -= (int)MathF.Ceiling(durabilityA * (wasteNots ? .5f : 1f));
|
||||||
|
if (d <= 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// If we can do the first action and still have durability left to survive to the next
|
||||||
|
// step (even before the Manipulation modifier), we can certainly do the next action.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool VerifyDurability3(Simulator s, int durabilityA, int durabilityB)
|
||||||
|
{
|
||||||
|
var d = s.Durability;
|
||||||
|
var wasteNots = Math.Max(s.GetEffectDuration(EffectType.WasteNot), s.GetEffectDuration(EffectType.WasteNot2));
|
||||||
|
var manips = s.GetEffectDuration(EffectType.Manipulation);
|
||||||
|
|
||||||
|
d -= (int)MathF.Ceiling(durabilityA * wasteNots > 0 ? .5f : 1f);
|
||||||
|
if (d <= 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (manips > 0)
|
||||||
|
d += 5;
|
||||||
|
|
||||||
|
if (wasteNots > 0)
|
||||||
|
wasteNots--;
|
||||||
|
|
||||||
|
d -= (int)MathF.Ceiling(durabilityB * wasteNots > 0 ? .5f : 1f);
|
||||||
|
|
||||||
|
if (d <= 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// If we can do the second action and still have durability left to survive to the next
|
||||||
|
// step (even before the Manipulation modifier), we can certainly do the next action.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -57,13 +57,18 @@ public class Simulator
|
|||||||
return ActionResponse.CannotUseAction;
|
return ActionResponse.CannotUseAction;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ExecuteForced(action, baseAction);
|
||||||
|
|
||||||
|
return ActionResponse.UsedAction;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ExecuteForced(ActionType action, BaseAction baseAction)
|
||||||
|
{
|
||||||
baseAction.Use(this);
|
baseAction.Use(this);
|
||||||
ActionStates.MutateState(action);
|
ActionStates.MutateState(action);
|
||||||
ActionCount++;
|
ActionCount++;
|
||||||
|
|
||||||
ActiveEffects.DecrementDuration();
|
ActiveEffects.DecrementDuration();
|
||||||
|
|
||||||
return ActionResponse.UsedAction;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int GetEffectStrength(EffectType effect) =>
|
public int GetEffectStrength(EffectType effect) =>
|
||||||
|
|||||||
@@ -19,6 +19,10 @@ public sealed class Simulator : SimulatorNoRandom
|
|||||||
|
|
||||||
public static readonly ActionType[] AcceptedActions = new[]
|
public static readonly ActionType[] AcceptedActions = new[]
|
||||||
{
|
{
|
||||||
|
ActionType.StandardTouchCombo,
|
||||||
|
ActionType.AdvancedTouchCombo,
|
||||||
|
ActionType.FocusedTouchCombo,
|
||||||
|
ActionType.FocusedSynthesisCombo,
|
||||||
ActionType.TrainedFinesse,
|
ActionType.TrainedFinesse,
|
||||||
ActionType.PrudentSynthesis,
|
ActionType.PrudentSynthesis,
|
||||||
ActionType.Groundwork,
|
ActionType.Groundwork,
|
||||||
@@ -101,6 +105,11 @@ public sealed class Simulator : SimulatorNoRandom
|
|||||||
CP > 10)
|
CP > 10)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
// don't allow combo actions if the combo is already in progress
|
||||||
|
if (ActionStates.TouchComboIdx != 0 &&
|
||||||
|
(action == ActionType.StandardTouchCombo || action == ActionType.AdvancedTouchCombo))
|
||||||
|
return false;
|
||||||
|
|
||||||
// don't allow pure quality moves under Veneration
|
// don't allow pure quality moves under Veneration
|
||||||
if (HasEffect(EffectType.Veneration) &&
|
if (HasEffect(EffectType.Veneration) &&
|
||||||
!baseAction.IncreasesProgress &&
|
!baseAction.IncreasesProgress &&
|
||||||
|
|||||||
@@ -298,7 +298,7 @@ public sealed class Solver
|
|||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private void Search(CancellationToken token, int iterations)
|
private void Search(int iterations, CancellationToken token)
|
||||||
{
|
{
|
||||||
Simulator simulator = new(rootNode.State.State, config.MaxStepCount);
|
Simulator simulator = new(rootNode.State.State, config.MaxStepCount);
|
||||||
var random = rootNode.State.State.Input.Random;
|
var random = rootNode.State.State.Input.Random;
|
||||||
@@ -360,7 +360,7 @@ public sealed class Solver
|
|||||||
Task.Run(() =>
|
Task.Run(() =>
|
||||||
{
|
{
|
||||||
var solver = new Solver(config, activeStates[stateIdx].State);
|
var solver = new Solver(config, activeStates[stateIdx].State);
|
||||||
solver.Search(token, config.Iterations / config.ForkCount);
|
solver.Search(config.Iterations / config.ForkCount, token);
|
||||||
return (solver.MaxScore, stateIdx, solver.Solution());
|
return (solver.MaxScore, stateIdx, solver.Solution());
|
||||||
}, token)
|
}, token)
|
||||||
);
|
);
|
||||||
@@ -461,7 +461,7 @@ public sealed class Solver
|
|||||||
tasks[i] = Task.Run(() =>
|
tasks[i] = Task.Run(() =>
|
||||||
{
|
{
|
||||||
var solver = new Solver(config, state);
|
var solver = new Solver(config, state);
|
||||||
solver.Search(token, config.Iterations / config.ForkCount);
|
solver.Search(config.Iterations / config.ForkCount, token);
|
||||||
return (solver.MaxScore, solver.Solution());
|
return (solver.MaxScore, solver.Solution());
|
||||||
}, token);
|
}, token);
|
||||||
Task.WaitAll(tasks, CancellationToken.None);
|
Task.WaitAll(tasks, CancellationToken.None);
|
||||||
@@ -504,7 +504,7 @@ public sealed class Solver
|
|||||||
var solver = new Solver(config, state);
|
var solver = new Solver(config, state);
|
||||||
|
|
||||||
var s = Stopwatch.StartNew();
|
var s = Stopwatch.StartNew();
|
||||||
solver.Search(token, config.Iterations);
|
solver.Search(config.Iterations, token);
|
||||||
s.Stop();
|
s.Stop();
|
||||||
|
|
||||||
var (solution_actions, solution_node) = solver.Solution();
|
var (solution_actions, solution_node) = solver.Solution();
|
||||||
@@ -536,7 +536,7 @@ public sealed class Solver
|
|||||||
tasks[i] = Task.Run(() =>
|
tasks[i] = Task.Run(() =>
|
||||||
{
|
{
|
||||||
var solver = new Solver(config, state);
|
var solver = new Solver(config, state);
|
||||||
solver.Search(token, config.Iterations / config.ForkCount);
|
solver.Search(config.Iterations / config.ForkCount, token);
|
||||||
return (solver.MaxScore, solver.Solution());
|
return (solver.MaxScore, solver.Solution());
|
||||||
}, token);
|
}, token);
|
||||||
Task.WaitAll(tasks, CancellationToken.None);
|
Task.WaitAll(tasks, CancellationToken.None);
|
||||||
@@ -551,7 +551,7 @@ public sealed class Solver
|
|||||||
public static (List<ActionType> Actions, SimulationState State) SearchOneshot(SolverConfig config, SimulationState state, CancellationToken token = default)
|
public static (List<ActionType> Actions, SimulationState State) SearchOneshot(SolverConfig config, SimulationState state, CancellationToken token = default)
|
||||||
{
|
{
|
||||||
var solver = new Solver(config, state);
|
var solver = new Solver(config, state);
|
||||||
solver.Search(token, config.Iterations);
|
solver.Search(config.Iterations, token);
|
||||||
var (solution_actions, solution_node) = solver.Solution();
|
var (solution_actions, solution_node) = solver.Solution();
|
||||||
return (solution_actions, solution_node.State);
|
return (solution_actions, solution_node.State);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user