Merge branch 'micro-optimizations' into main
This commit is contained in:
@@ -90,7 +90,9 @@ jobs:
|
|||||||
- name: Setup .NET
|
- name: Setup .NET
|
||||||
uses: actions/setup-dotnet@v3
|
uses: actions/setup-dotnet@v3
|
||||||
with:
|
with:
|
||||||
dotnet-version: '7.0'
|
dotnet-version: |
|
||||||
|
7.0
|
||||||
|
8.0
|
||||||
|
|
||||||
- name: Download Dalamud
|
- name: Download Dalamud
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
+19
-7
@@ -1,15 +1,27 @@
|
|||||||
using BenchmarkDotNet.Attributes;
|
using BenchmarkDotNet.Attributes;
|
||||||
using BenchmarkDotNet.Diagnostics.dotTrace;
|
using BenchmarkDotNet.Diagnostics.dotTrace;
|
||||||
|
using BenchmarkDotNet.Jobs;
|
||||||
using Craftimizer.Simulator;
|
using Craftimizer.Simulator;
|
||||||
using Craftimizer.Solver;
|
using Craftimizer.Solver;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
namespace Craftimizer.Benchmark;
|
namespace Craftimizer.Benchmark;
|
||||||
|
|
||||||
[SimpleJob(iterationCount: 10)]
|
[SimpleJob(RuntimeMoniker.Net70, baseline: true)]
|
||||||
|
[SimpleJob(RuntimeMoniker.Net80)]
|
||||||
[MinColumn, Q1Column, Q3Column, MaxColumn]
|
[MinColumn, Q1Column, Q3Column, MaxColumn]
|
||||||
[DotTraceDiagnoser]
|
[DotTraceDiagnoser]
|
||||||
public class Bench
|
public class Bench
|
||||||
{
|
{
|
||||||
|
public record struct SHAWrapper<T>(T Data) where T : notnull
|
||||||
|
{
|
||||||
|
public static implicit operator T(SHAWrapper<T> wrapper) => wrapper.Data;
|
||||||
|
|
||||||
|
public override readonly string ToString() =>
|
||||||
|
Convert.ToHexString(SHA256.HashData(Encoding.UTF8.GetBytes(Data.ToString()!)));
|
||||||
|
}
|
||||||
|
|
||||||
private static SimulationInput[] Inputs { get; } = new SimulationInput[] {
|
private static SimulationInput[] Inputs { get; } = new SimulationInput[] {
|
||||||
// https://craftingway.app/rotation/loud-namazu-jVe9Y
|
// https://craftingway.app/rotation/loud-namazu-jVe9Y
|
||||||
// Chondrite Saw
|
// Chondrite Saw
|
||||||
@@ -68,22 +80,22 @@ public class Bench
|
|||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
public static IEnumerable<SimulationState> States => Inputs.Select(i => new SimulationState(i));
|
public static IEnumerable<SHAWrapper<SimulationState>> States => Inputs.Select(i => new SHAWrapper<SimulationState>(new(i)));
|
||||||
|
|
||||||
public static IEnumerable<SolverConfig> Configs => new SolverConfig[]
|
public static IEnumerable<SHAWrapper<SolverConfig>> Configs => new SHAWrapper<SolverConfig>[]
|
||||||
{
|
{
|
||||||
new()
|
new(new()
|
||||||
{
|
{
|
||||||
Algorithm = SolverAlgorithm.Stepwise,
|
Algorithm = SolverAlgorithm.Stepwise,
|
||||||
Iterations = 30_000,
|
Iterations = 30_000,
|
||||||
}
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
[ParamsSource(nameof(States))]
|
[ParamsSource(nameof(States))]
|
||||||
public SimulationState State { get; set; }
|
public SHAWrapper<SimulationState> State { get; set; }
|
||||||
|
|
||||||
[ParamsSource(nameof(Configs))]
|
[ParamsSource(nameof(Configs))]
|
||||||
public SolverConfig Config { get; set; }
|
public SHAWrapper<SolverConfig> Config { get; set; }
|
||||||
|
|
||||||
[Benchmark]
|
[Benchmark]
|
||||||
public async Task<float> Solve()
|
public async Task<float> Solve()
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using Craftimizer.Simulator;
|
using Craftimizer.Simulator;
|
||||||
using Craftimizer.Simulator.Actions;
|
using Craftimizer.Simulator.Actions;
|
||||||
using Craftimizer.Solver;
|
using Craftimizer.Solver;
|
||||||
|
using ObjectLayoutInspector;
|
||||||
|
|
||||||
namespace Craftimizer.Benchmark;
|
namespace Craftimizer.Benchmark;
|
||||||
|
|
||||||
@@ -63,8 +64,11 @@ internal static class Program
|
|||||||
|
|
||||||
private static async Task RunOther()
|
private static async Task RunOther()
|
||||||
{
|
{
|
||||||
//TypeLayout.PrintLayout<ArenaNode<SimulationNode>>(true);
|
TypeLayout.PrintLayout<SimulationState>(true);
|
||||||
//return;
|
TypeLayout.PrintLayout<Simulator.Simulator>(true);
|
||||||
|
TypeLayout.PrintLayout<BaseAction>(true);
|
||||||
|
TypeLayout.PrintLayout<SimulationNode>(true);
|
||||||
|
return;
|
||||||
|
|
||||||
var input = new SimulationInput(
|
var input = new SimulationInput(
|
||||||
new CharacterStats
|
new CharacterStats
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ public abstract class BaseComboAction : BaseAction
|
|||||||
protected bool BaseCanUse(Simulator s) =>
|
protected bool BaseCanUse(Simulator s) =>
|
||||||
base.CanUse(s);
|
base.CanUse(s);
|
||||||
|
|
||||||
private static bool VerifyDurability2(int durabilityA, int durability, Effects effects)
|
private static bool VerifyDurability2(int durabilityA, int durability, in Effects effects)
|
||||||
{
|
{
|
||||||
var wasteNots = effects.HasEffect(EffectType.WasteNot) || effects.HasEffect(EffectType.WasteNot2);
|
var wasteNots = effects.HasEffect(EffectType.WasteNot) || effects.HasEffect(EffectType.WasteNot2);
|
||||||
// -A
|
// -A
|
||||||
@@ -23,13 +23,10 @@ public abstract class BaseComboAction : BaseAction
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool VerifyDurability2(SimulationState s, int durabilityA) =>
|
|
||||||
VerifyDurability2(durabilityA, s.Durability, s.ActiveEffects);
|
|
||||||
|
|
||||||
public static bool VerifyDurability2(Simulator s, int durabilityA) =>
|
public static bool VerifyDurability2(Simulator s, int durabilityA) =>
|
||||||
VerifyDurability2(durabilityA, s.Durability, s.ActiveEffects);
|
VerifyDurability2(durabilityA, s.Durability, s.ActiveEffects);
|
||||||
|
|
||||||
public static bool VerifyDurability3(int durabilityA, int durabilityB, int durability, Effects effects)
|
public static bool VerifyDurability3(int durabilityA, int durabilityB, int durability, in Effects effects)
|
||||||
{
|
{
|
||||||
var wasteNots = Math.Max(effects.GetDuration(EffectType.WasteNot), effects.GetDuration(EffectType.WasteNot2));
|
var wasteNots = Math.Max(effects.GetDuration(EffectType.WasteNot), effects.GetDuration(EffectType.WasteNot2));
|
||||||
var manips = effects.HasEffect(EffectType.Manipulation);
|
var manips = effects.HasEffect(EffectType.Manipulation);
|
||||||
@@ -56,7 +53,4 @@ public abstract class BaseComboAction : BaseAction
|
|||||||
|
|
||||||
public static bool VerifyDurability3(Simulator s, int durabilityA, int durabilityB) =>
|
public static bool VerifyDurability3(Simulator s, int durabilityA, int durabilityB) =>
|
||||||
VerifyDurability3(durabilityA, durabilityB, s.Durability, s.ActiveEffects);
|
VerifyDurability3(durabilityA, durabilityB, s.Durability, s.ActiveEffects);
|
||||||
|
|
||||||
public static bool VerifyDurability3(SimulationState s, int durabilityA, int durabilityB) =>
|
|
||||||
VerifyDurability3(durabilityA, durabilityB, s.Durability, s.ActiveEffects);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ public record struct SimulationState
|
|||||||
public ActionStates ActionStates;
|
public ActionStates ActionStates;
|
||||||
|
|
||||||
// https://github.com/ffxiv-teamcraft/simulator/blob/0682dfa76043ff4ccb38832c184d046ceaff0733/src/model/tables.ts#L2
|
// https://github.com/ffxiv-teamcraft/simulator/blob/0682dfa76043ff4ccb38832c184d046ceaff0733/src/model/tables.ts#L2
|
||||||
private static readonly int[] HQPercentTable = {
|
private static ReadOnlySpan<int> HQPercentTable => new[] {
|
||||||
1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8,
|
1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8,
|
||||||
9, 9, 9, 10, 10, 10, 11, 11, 11, 12, 12, 12, 13, 13, 13, 14, 14, 14, 15, 15, 15, 16, 16, 17, 17,
|
9, 9, 9, 10, 10, 10, 11, 11, 11, 12, 12, 12, 13, 13, 13, 14, 14, 14, 15, 15, 15, 16, 16, 17, 17,
|
||||||
17, 18, 18, 18, 19, 19, 20, 20, 21, 22, 23, 24, 26, 28, 31, 34, 38, 42, 47, 52, 58, 64, 68, 71,
|
17, 18, 18, 18, 19, 19, 20, 20, 21, 22, 23, 24, 26, 28, 31, 34, 38, 42, 47, 52, 58, 64, 68, 71,
|
||||||
|
|||||||
@@ -35,17 +35,17 @@ public class Simulator
|
|||||||
|
|
||||||
public IEnumerable<ActionType> AvailableActions => ActionUtils.AvailableActions(this);
|
public IEnumerable<ActionType> AvailableActions => ActionUtils.AvailableActions(this);
|
||||||
|
|
||||||
public Simulator(SimulationState state)
|
public Simulator(in SimulationState state)
|
||||||
{
|
{
|
||||||
State = state;
|
State = state;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetState(SimulationState state)
|
public void SetState(in SimulationState state)
|
||||||
{
|
{
|
||||||
State = state;
|
State = state;
|
||||||
}
|
}
|
||||||
|
|
||||||
public (ActionResponse Response, SimulationState NewState) Execute(SimulationState state, ActionType action)
|
public (ActionResponse Response, SimulationState NewState) Execute(in SimulationState state, ActionType action)
|
||||||
{
|
{
|
||||||
State = state;
|
State = state;
|
||||||
return (Execute(action), State);
|
return (Execute(action), State);
|
||||||
@@ -75,7 +75,7 @@ public class Simulator
|
|||||||
return ActionResponse.UsedAction;
|
return ActionResponse.UsedAction;
|
||||||
}
|
}
|
||||||
|
|
||||||
public (ActionResponse Response, SimulationState NewState, int FailedActionIdx) ExecuteMultiple(SimulationState state, IEnumerable<ActionType> actions)
|
public (ActionResponse Response, SimulationState NewState, int FailedActionIdx) ExecuteMultiple(in SimulationState state, IEnumerable<ActionType> actions)
|
||||||
{
|
{
|
||||||
State = state;
|
State = state;
|
||||||
var i = 0;
|
var i = 0;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ namespace Craftimizer.Simulator;
|
|||||||
|
|
||||||
public class SimulatorNoRandom : Simulator
|
public class SimulatorNoRandom : Simulator
|
||||||
{
|
{
|
||||||
public SimulatorNoRandom(SimulationState state) : base(state)
|
public SimulatorNoRandom(in SimulationState state) : base(state)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -9,7 +9,7 @@ public struct ActionSet
|
|||||||
{
|
{
|
||||||
private uint bits;
|
private uint bits;
|
||||||
|
|
||||||
public static readonly ActionType[] AcceptedActions = new[]
|
internal static ReadOnlySpan<ActionType> AcceptedActions => new[]
|
||||||
{
|
{
|
||||||
ActionType.StandardTouchCombo,
|
ActionType.StandardTouchCombo,
|
||||||
ActionType.AdvancedTouchCombo,
|
ActionType.AdvancedTouchCombo,
|
||||||
|
|||||||
@@ -20,6 +20,12 @@
|
|||||||
<ProjectReference Include="..\Simulator\Craftimizer.Simulator.csproj" />
|
<ProjectReference Include="..\Simulator\Craftimizer.Simulator.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleToAttribute">
|
||||||
|
<_Parameter1>Craftimizer.Test</_Parameter1>
|
||||||
|
</AssemblyAttribute>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(IS_BENCH)'=='1'">
|
<PropertyGroup Condition="'$(IS_BENCH)'=='1'">
|
||||||
<DefineConstants>$(DefineConstants);IS_DETERMINISTIC</DefineConstants>
|
<DefineConstants>$(DefineConstants);IS_DETERMINISTIC</DefineConstants>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|||||||
+6
-6
@@ -17,7 +17,7 @@ public sealed class MCTS
|
|||||||
|
|
||||||
public float MaxScore => rootScores.MaxScore;
|
public float MaxScore => rootScores.MaxScore;
|
||||||
|
|
||||||
public MCTS(MCTSConfig config, SimulationState state)
|
public MCTS(in MCTSConfig config, in SimulationState state)
|
||||||
{
|
{
|
||||||
this.config = config;
|
this.config = config;
|
||||||
var sim = new Simulator(state, config.MaxStepCount);
|
var sim = new Simulator(state, config.MaxStepCount);
|
||||||
@@ -30,7 +30,7 @@ public sealed class MCTS
|
|||||||
rootScores = new();
|
rootScores = new();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static SimulationNode Execute(Simulator simulator, SimulationState state, ActionType action, bool strict)
|
private static SimulationNode Execute(Simulator simulator, in SimulationState state, ActionType action, bool strict)
|
||||||
{
|
{
|
||||||
(_, var newState) = simulator.Execute(state, action);
|
(_, var newState) = simulator.Execute(state, action);
|
||||||
return new(
|
return new(
|
||||||
@@ -61,7 +61,7 @@ public sealed class MCTS
|
|||||||
|
|
||||||
[Pure]
|
[Pure]
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private static (int arrayIdx, int subIdx) ChildMaxScore(ref NodeScoresBuffer scores)
|
private static (int arrayIdx, int subIdx) ChildMaxScore(in NodeScoresBuffer scores)
|
||||||
{
|
{
|
||||||
var length = scores.Count;
|
var length = scores.Count;
|
||||||
var vecLength = Vector<float>.Count;
|
var vecLength = Vector<float>.Count;
|
||||||
@@ -111,7 +111,7 @@ public sealed class MCTS
|
|||||||
float explorationConstant,
|
float explorationConstant,
|
||||||
float maxScoreWeightingConstant,
|
float maxScoreWeightingConstant,
|
||||||
int parentVisits,
|
int parentVisits,
|
||||||
ref NodeScoresBuffer scores)
|
in NodeScoresBuffer scores)
|
||||||
{
|
{
|
||||||
var length = scores.Count;
|
var length = scores.Count;
|
||||||
var vecLength = Vector<float>.Count;
|
var vecLength = Vector<float>.Count;
|
||||||
@@ -168,7 +168,7 @@ public sealed class MCTS
|
|||||||
return node;
|
return node;
|
||||||
|
|
||||||
// select the node with the highest score
|
// select the node with the highest score
|
||||||
var at = EvalBestChild(explorationConstant, maxScoreWeightingConstant, nodeVisits, ref node.ChildScores);
|
var at = EvalBestChild(explorationConstant, maxScoreWeightingConstant, nodeVisits, in node.ChildScores);
|
||||||
nodeVisits = node.ChildScores.GetVisits(at);
|
nodeVisits = node.ChildScores.GetVisits(at);
|
||||||
node = node.ChildAt(at)!;
|
node = node.ChildAt(at)!;
|
||||||
}
|
}
|
||||||
@@ -320,7 +320,7 @@ public sealed class MCTS
|
|||||||
|
|
||||||
while (node.Children.Count != 0)
|
while (node.Children.Count != 0)
|
||||||
{
|
{
|
||||||
node = node.ChildAt(ChildMaxScore(ref node.ChildScores))!;
|
node = node.ChildAt(ChildMaxScore(in node.ChildScores))!;
|
||||||
|
|
||||||
if (node.State.Action != null)
|
if (node.State.Action != null)
|
||||||
actions.Add(node.State.Action.Value);
|
actions.Add(node.State.Action.Value);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Craftimizer.Solver;
|
namespace Craftimizer.Solver;
|
||||||
|
|
||||||
@@ -21,7 +21,7 @@ public readonly record struct MCTSConfig
|
|||||||
public float ScoreCP { get; init; }
|
public float ScoreCP { get; init; }
|
||||||
public float ScoreSteps { get; init; }
|
public float ScoreSteps { get; init; }
|
||||||
|
|
||||||
public MCTSConfig(SolverConfig config)
|
public MCTSConfig(in SolverConfig config)
|
||||||
{
|
{
|
||||||
MaxStepCount = config.MaxStepCount;
|
MaxStepCount = config.MaxStepCount;
|
||||||
MaxRolloutStepCount = config.MaxRolloutStepCount;
|
MaxRolloutStepCount = config.MaxRolloutStepCount;
|
||||||
|
|||||||
@@ -7,11 +7,11 @@ namespace Craftimizer.Solver;
|
|||||||
// Adapted from https://github.com/dtao/ConcurrentList/blob/4fcf1c76e93021a41af5abb2d61a63caeba2adad/ConcurrentList/ConcurrentList.cs
|
// Adapted from https://github.com/dtao/ConcurrentList/blob/4fcf1c76e93021a41af5abb2d61a63caeba2adad/ConcurrentList/ConcurrentList.cs
|
||||||
public struct NodeScoresBuffer
|
public struct NodeScoresBuffer
|
||||||
{
|
{
|
||||||
public sealed class ScoresBatch
|
public readonly struct ScoresBatch
|
||||||
{
|
{
|
||||||
public Memory<float> ScoreSum;
|
public readonly Memory<float> ScoreSum;
|
||||||
public Memory<float> MaxScore;
|
public readonly Memory<float> MaxScore;
|
||||||
public Memory<int> Visits;
|
public readonly Memory<int> Visits;
|
||||||
|
|
||||||
public ScoresBatch()
|
public ScoresBatch()
|
||||||
{
|
{
|
||||||
@@ -40,9 +40,10 @@ public struct NodeScoresBuffer
|
|||||||
|
|
||||||
var idx = Count++;
|
var idx = Count++;
|
||||||
|
|
||||||
var (arrayIdx, _) = GetArrayIndex(idx);
|
var (arrayIdx, subIdx) = GetArrayIndex(idx);
|
||||||
|
|
||||||
Data[arrayIdx] ??= new();
|
if (subIdx == 0)
|
||||||
|
Data[arrayIdx] = new();
|
||||||
}
|
}
|
||||||
|
|
||||||
public readonly void Visit((int arrayIdx, int subIdx) at, float score)
|
public readonly void Visit((int arrayIdx, int subIdx) at, float score)
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ public struct SimulationNode
|
|||||||
|
|
||||||
public readonly bool IsComplete => CompletionState != CompletionState.Incomplete;
|
public readonly bool IsComplete => CompletionState != CompletionState.Incomplete;
|
||||||
|
|
||||||
public SimulationNode(SimulationState state, ActionType? action, CompletionState completionState, ActionSet actions)
|
public SimulationNode(in SimulationState state, ActionType? action, CompletionState completionState, ActionSet actions)
|
||||||
{
|
{
|
||||||
State = state;
|
State = state;
|
||||||
Action = action;
|
Action = action;
|
||||||
@@ -32,10 +32,10 @@ public struct SimulationNode
|
|||||||
CompletionState.NoMoreActions :
|
CompletionState.NoMoreActions :
|
||||||
simCompletionState;
|
simCompletionState;
|
||||||
|
|
||||||
public readonly float? CalculateScore(MCTSConfig config) =>
|
public readonly float? CalculateScore(in MCTSConfig config) =>
|
||||||
CalculateScoreForState(State, SimulationCompletionState, config);
|
CalculateScoreForState(State, SimulationCompletionState, config);
|
||||||
|
|
||||||
public static float? CalculateScoreForState(SimulationState state, CompletionState completionState, MCTSConfig config)
|
public static float? CalculateScoreForState(in SimulationState state, CompletionState completionState, MCTSConfig config)
|
||||||
{
|
{
|
||||||
if (completionState != CompletionState.ProgressComplete)
|
if (completionState != CompletionState.ProgressComplete)
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
+1
-1
@@ -20,7 +20,7 @@ internal sealed class Simulator : SimulatorNoRandom
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Simulator(SimulationState state, int maxStepCount) : base(state)
|
public Simulator(in SimulationState state, int maxStepCount) : base(state)
|
||||||
{
|
{
|
||||||
this.maxStepCount = maxStepCount;
|
this.maxStepCount = maxStepCount;
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -35,7 +35,7 @@ public sealed class Solver : IDisposable
|
|||||||
// Always called when a new step is generated.
|
// Always called when a new step is generated.
|
||||||
public event NewActionDelegate? OnNewAction;
|
public event NewActionDelegate? OnNewAction;
|
||||||
|
|
||||||
public Solver(SolverConfig config, SimulationState state)
|
public Solver(in SolverConfig config, in SimulationState state)
|
||||||
{
|
{
|
||||||
Config = config;
|
Config = config;
|
||||||
State = state;
|
State = state;
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
using Craftimizer.Simulator.Actions;
|
|
||||||
using Craftimizer.Simulator;
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Craftimizer.Solver;
|
namespace Craftimizer.Solver;
|
||||||
@@ -71,4 +69,4 @@ public readonly record struct SolverConfig
|
|||||||
FurcatedActionCount = Environment.ProcessorCount / 2,
|
FurcatedActionCount = Environment.ProcessorCount / 2,
|
||||||
Algorithm = SolverAlgorithm.StepwiseForked
|
Algorithm = SolverAlgorithm.StepwiseForked
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ public readonly record struct SolverSolution {
|
|||||||
public readonly IEnumerable<ActionType> ActionEnumerable { init => actions = SanitizeCombos(value).ToList(); }
|
public readonly IEnumerable<ActionType> ActionEnumerable { init => actions = SanitizeCombos(value).ToList(); }
|
||||||
public readonly SimulationState State { get; init; }
|
public readonly SimulationState State { get; init; }
|
||||||
|
|
||||||
public SolverSolution(IEnumerable<ActionType> actions, SimulationState state)
|
public SolverSolution(IEnumerable<ActionType> actions, in SimulationState state)
|
||||||
{
|
{
|
||||||
ActionEnumerable = actions;
|
ActionEnumerable = actions;
|
||||||
State = state;
|
State = state;
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
using Craftimizer.Simulator.Actions;
|
|
||||||
|
|
||||||
namespace Craftimizer.Test.Solver;
|
namespace Craftimizer.Test.Solver;
|
||||||
|
|
||||||
[TestClass]
|
[TestClass]
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
global using Microsoft.VisualStudio.TestTools.UnitTesting;
|
global using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
global using Craftimizer.Solver;
|
global using Craftimizer.Solver;
|
||||||
global using Craftimizer.Simulator;
|
global using Craftimizer.Simulator;
|
||||||
|
global using Craftimizer.Simulator.Actions;
|
||||||
|
|||||||
Reference in New Issue
Block a user