From 0b2b80d6b59f3fa3bbe447de653584bb7779c3bd Mon Sep 17 00:00:00 2001 From: Asriel Camora Date: Wed, 21 Jun 2023 06:16:57 -0700 Subject: [PATCH] More minor optimizations --- Simulator/ActionStates.cs | 10 +++++----- Simulator/Effects.cs | 28 +++++++++++++-------------- Simulator/SimulationInput.cs | 2 +- Simulator/SimulationState.cs | 4 +--- Solver/Crafty/ActionSet.cs | 14 +++++++------- Solver/Crafty/Arena.cs | 19 ++++++++++++------ Solver/Crafty/NodeData.cs | 7 +++++++ Solver/Crafty/NodeScores.cs | 15 +++++++++++---- Solver/Crafty/SimulationNode.cs | 7 +++---- Solver/Crafty/Solver.cs | 34 ++++++++++++++------------------- 10 files changed, 76 insertions(+), 64 deletions(-) create mode 100644 Solver/Crafty/NodeData.cs diff --git a/Simulator/ActionStates.cs b/Simulator/ActionStates.cs index c3210c7..c1785bc 100644 --- a/Simulator/ActionStates.cs +++ b/Simulator/ActionStates.cs @@ -2,12 +2,12 @@ using Craftimizer.Simulator.Actions; namespace Craftimizer.Simulator; -public record struct ActionStates +public struct ActionStates { - public byte TouchComboIdx { get; set; } - public byte CarefulObservationCount { get; set; } - public bool UsedHeartAndSoul { get; set; } - public bool Observed { get; set; } + public byte TouchComboIdx; + public byte CarefulObservationCount; + public bool UsedHeartAndSoul; + public bool Observed; public void MutateState(ActionType action) { diff --git a/Simulator/Effects.cs b/Simulator/Effects.cs index 6372ada..320105f 100644 --- a/Simulator/Effects.cs +++ b/Simulator/Effects.cs @@ -1,17 +1,17 @@ namespace Craftimizer.Simulator; -public record struct Effects +public struct Effects { - public byte InnerQuiet { get; set; } - public byte WasteNot { get; set; } - public byte Veneration { get; set; } - public byte GreatStrides { get; set; } - public byte Innovation { get; set; } - public byte FinalAppraisal { get; set; } - public byte WasteNot2 { get; set; } - public byte MuscleMemory { get; set; } - public byte Manipulation { get; set; } - public bool HeartAndSoul { get; set; } + public byte InnerQuiet; + public byte WasteNot; + public byte Veneration; + public byte GreatStrides; + public byte Innovation; + public byte FinalAppraisal; + public byte WasteNot2; + public byte MuscleMemory; + public byte Manipulation; + public bool HeartAndSoul; public void SetDuration(EffectType effect, byte duration) { @@ -57,7 +57,7 @@ public record struct Effects InnerQuiet++; } - public byte GetDuration(EffectType effect) => + public readonly byte GetDuration(EffectType effect) => effect switch { EffectType.InnerQuiet => (byte)(InnerQuiet != 0 ? 1 : 0), @@ -73,11 +73,11 @@ public record struct Effects _ => 0 }; - public byte GetStrength(EffectType effect) => + public readonly byte GetStrength(EffectType effect) => effect == EffectType.InnerQuiet ? InnerQuiet : (byte)(GetDuration(effect) != 0 ? 1 : 0); - public bool HasEffect(EffectType effect) => + public readonly bool HasEffect(EffectType effect) => GetDuration(effect) != 0; public void DecrementDuration() diff --git a/Simulator/SimulationInput.cs b/Simulator/SimulationInput.cs index 692768c..2f1f5a8 100644 --- a/Simulator/SimulationInput.cs +++ b/Simulator/SimulationInput.cs @@ -1,6 +1,6 @@ namespace Craftimizer.Simulator; -public record SimulationInput +public sealed class SimulationInput { public CharacterStats Stats { get; } public RecipeInfo Recipe { get; } diff --git a/Simulator/SimulationState.cs b/Simulator/SimulationState.cs index c2ae295..c337d7e 100644 --- a/Simulator/SimulationState.cs +++ b/Simulator/SimulationState.cs @@ -1,8 +1,6 @@ -using Craftimizer.Simulator.Actions; - namespace Craftimizer.Simulator; -public readonly record struct SimulationState +public readonly struct SimulationState { public SimulationInput Input { get; init; } diff --git a/Solver/Crafty/ActionSet.cs b/Solver/Crafty/ActionSet.cs index 1910bcb..ced5415 100644 --- a/Solver/Crafty/ActionSet.cs +++ b/Solver/Crafty/ActionSet.cs @@ -5,9 +5,9 @@ using System.Runtime.Intrinsics.X86; namespace Craftimizer.Solver.Crafty; -public sealed class ActionSet +public struct ActionSet { - private uint Bits { get; set; } + private uint bits; [MethodImpl(MethodImplOptions.AggressiveInlining)] private static int NthBitSet(uint value, int n) @@ -47,13 +47,13 @@ public sealed class ActionSet private static ActionType ToAction(int index) => Simulator.AcceptedActions[index]; [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool HasAction(ActionType action) => (Bits & (1u << (FromAction(action) + 1))) != 0; + public readonly bool HasAction(ActionType action) => (bits & (1u << (FromAction(action) + 1))) != 0; [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void AddAction(ActionType action) => Bits |= 1u << (FromAction(action) + 1); + public void AddAction(ActionType action) => bits |= 1u << (FromAction(action) + 1); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void RemoveAction(ActionType action) => Bits &= ~(1u << (FromAction(action) + 1)); + public void RemoveAction(ActionType action) => bits &= ~(1u << (FromAction(action) + 1)); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ActionType ElementAt(int index) => ToAction(NthBitSet(Bits, index) - 1); + public readonly ActionType ElementAt(int index) => ToAction(NthBitSet(bits, index) - 1); - public int Count => BitOperations.PopCount(Bits); + public readonly int Count => BitOperations.PopCount(bits); } diff --git a/Solver/Crafty/Arena.cs b/Solver/Crafty/Arena.cs index c80695f..7c1927b 100644 --- a/Solver/Crafty/Arena.cs +++ b/Solver/Crafty/Arena.cs @@ -4,25 +4,32 @@ namespace Craftimizer.Solver.Crafty; public class Arena where T : struct { - public readonly record struct Node + public readonly struct Node { - public T State { get; init; } - public List Children { get; init; } - public int Parent { get; init; } + public readonly T State; + public readonly List Children; + public readonly int Parent; + + public Node(T state, int parent) + { + State = state; + Children = new(); + Parent = parent; + } } private readonly List nodes = new(); public Arena(T initialState = default) { - nodes.Add(new() { Parent = -1, Children = new(), State = initialState }); + nodes.Add(new(initialState, -1)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public int Insert(int parentIndex, T state) { var index = nodes.Count; - nodes.Add(new() { Parent = parentIndex, Children = new(), State = state }); + nodes.Add(new(state, parentIndex)); nodes[parentIndex].Children.Add(index); return index; } diff --git a/Solver/Crafty/NodeData.cs b/Solver/Crafty/NodeData.cs new file mode 100644 index 0000000..36cacd4 --- /dev/null +++ b/Solver/Crafty/NodeData.cs @@ -0,0 +1,7 @@ +namespace Craftimizer.Solver.Crafty; + +public class NodeData +{ + public ActionSet AvailableActions; + public NodeScores Scores; +} diff --git a/Solver/Crafty/NodeScores.cs b/Solver/Crafty/NodeScores.cs index 1fed933..b5b868d 100644 --- a/Solver/Crafty/NodeScores.cs +++ b/Solver/Crafty/NodeScores.cs @@ -1,8 +1,15 @@ namespace Craftimizer.Solver.Crafty; -public sealed class NodeScores +public struct NodeScores { - public float ScoreSum { get; set; } - public float MaxScore { get; set; } - public float Visits { get; set; } + public float ScoreSum; + public float MaxScore; + public float Visits; + + public void Visit(float score) + { + ScoreSum += score; + MaxScore = Math.Max(MaxScore, score); + Visits++; + } } diff --git a/Solver/Crafty/SimulationNode.cs b/Solver/Crafty/SimulationNode.cs index f7031e2..27e4330 100644 --- a/Solver/Crafty/SimulationNode.cs +++ b/Solver/Crafty/SimulationNode.cs @@ -3,18 +3,17 @@ using Craftimizer.Simulator.Actions; namespace Craftimizer.Solver.Crafty; -public readonly record struct SimulationNode +public readonly struct SimulationNode { public SimulationState State { get; init; } public ActionType? Action { get; init; } - public ActionSet AvailableActions { get; init; } public CompletionState SimulationCompletionState { get; init; } public CompletionState CompletionState => - AvailableActions.Count == 0 && SimulationCompletionState == CompletionState.Incomplete ? + Data.AvailableActions.Count == 0 && SimulationCompletionState == CompletionState.Incomplete ? CompletionState.NoMoreActions : SimulationCompletionState; - public NodeScores Scores { get; init; } + public NodeData Data { get; init; } public bool IsComplete => CompletionState != CompletionState.Incomplete; diff --git a/Solver/Crafty/Solver.cs b/Solver/Crafty/Solver.cs index 01b5a77..acdd894 100644 --- a/Solver/Crafty/Solver.cs +++ b/Solver/Crafty/Solver.cs @@ -28,8 +28,7 @@ public class Solver State = state, Action = null, SimulationCompletionState = Simulator.CompletionState, - AvailableActions = Simulator.AvailableActionsHeuristic(strict), - Scores = new() + Data = new() { AvailableActions = Simulator.AvailableActionsHeuristic(strict) } }); } @@ -45,8 +44,7 @@ public class Solver State = newState, Action = action, SimulationCompletionState = Simulator.CompletionState, - AvailableActions = Simulator.AvailableActionsHeuristic(strict), - Scores = new() + Data = new() { AvailableActions = Simulator.AvailableActionsHeuristic(strict) } }; } @@ -59,9 +57,9 @@ public class Solver if (node.IsComplete) return (currentIndex, node.CompletionState); - if (!node.AvailableActions.HasAction(action)) + if (!node.Data.AvailableActions.HasAction(action)) return (currentIndex, CompletionState.InvalidAction); - node.AvailableActions.RemoveAction(action); + node.Data.AvailableActions.RemoveAction(action); currentIndex = Tree.Insert(currentIndex, Execute(node.State, action, strict)); } @@ -122,7 +120,7 @@ public class Solver for (var j = 0; j < iterCount; ++j) { - var node = Tree.Get(children[i + j]).State.Scores; + var node = Tree.Get(children[i + j]).State.Data.Scores; scoreSums[j] = node.ScoreSum; visits[j] = node.Visits; maxScores[j] = node.MaxScore; @@ -148,7 +146,7 @@ public class Solver { var selectedNode = Tree.Get(selectedIndex); - var expandable = selectedNode.State.AvailableActions.Count != 0; + var expandable = selectedNode.State.Data.AvailableActions.Count != 0; var likelyTerminal = selectedNode.Children.Count == 0; if (expandable || likelyTerminal) { @@ -156,7 +154,7 @@ public class Solver } // select the node with the highest score - selectedIndex = EvalBestChild(selectedNode.State.Scores.Visits, selectedNode.Children); + selectedIndex = EvalBestChild(selectedNode.State.Data.Scores.Visits, selectedNode.Children); } } @@ -167,8 +165,8 @@ public class Solver if (initialNode.IsComplete) return (initialIndex, initialNode.CompletionState, initialNode.CalculateScore() ?? 0); - var randomAction = initialNode.AvailableActions.ElementAt(0); - initialNode.AvailableActions.RemoveAction(randomAction); + var randomAction = initialNode.Data.AvailableActions.ElementAt(0); + initialNode.Data.AvailableActions.RemoveAction(randomAction); var expandedState = Execute(initialNode.State, randomAction, true); var expandedIndex = Tree.Insert(initialIndex, expandedState); @@ -179,7 +177,7 @@ public class Solver { if (currentState.IsComplete) break; - randomAction = currentState.AvailableActions.ElementAt(0); + randomAction = currentState.Data.AvailableActions.ElementAt(0); actions.Add(randomAction); currentState = Execute(currentState.State, randomAction, true); } @@ -188,7 +186,7 @@ public class Solver var score = currentState.CalculateScore() ?? 0; if (currentState.CompletionState == CompletionState.ProgressComplete) { - if (score >= ScoreStorageThreshold && score >= Tree.Get(0).State.Scores.MaxScore) + if (score >= ScoreStorageThreshold && score >= Tree.Get(0).State.Data.Scores.MaxScore) { (var terminalIndex, _) = ExecuteActions(expandedIndex, actions, true); return (terminalIndex, currentState.CompletionState, score); @@ -203,11 +201,7 @@ public class Solver while (true) { var currentNode = Tree.Get(currentIndex); - var currentScores = currentNode.State.Scores; - currentScores.Visits++; - currentScores.ScoreSum += score; - if (currentScores.MaxScore < score) - currentScores.MaxScore = score; + currentNode.State.Data.Scores.Visit(score); if (currentIndex == targetIndex) break; @@ -233,7 +227,7 @@ public class Solver var node = Tree.Get(0); while (node.Children.Count != 0) { - var next_index = RustMaxBy(node.Children, n => Tree.Get(n).State.Scores.MaxScore); + var next_index = RustMaxBy(node.Children, n => Tree.Get(n).State.Data.Scores.MaxScore); node = Tree.Get(next_index); if (node.State.Action != null) actions.Add(node.State.Action.Value); @@ -264,7 +258,7 @@ public class Solver solver.Search(0); var (solution_actions, solution_node) = solver.Solution(); - if (solution_node.Scores.MaxScore >= 1.0) + if (solution_node.Data.Scores.MaxScore >= 1.0) { actions.AddRange(solution_actions); return (actions, solution_node.State);