More minor optimizations
This commit is contained in:
@@ -2,12 +2,12 @@ using Craftimizer.Simulator.Actions;
|
|||||||
|
|
||||||
namespace Craftimizer.Simulator;
|
namespace Craftimizer.Simulator;
|
||||||
|
|
||||||
public record struct ActionStates
|
public struct ActionStates
|
||||||
{
|
{
|
||||||
public byte TouchComboIdx { get; set; }
|
public byte TouchComboIdx;
|
||||||
public byte CarefulObservationCount { get; set; }
|
public byte CarefulObservationCount;
|
||||||
public bool UsedHeartAndSoul { get; set; }
|
public bool UsedHeartAndSoul;
|
||||||
public bool Observed { get; set; }
|
public bool Observed;
|
||||||
|
|
||||||
public void MutateState(ActionType action)
|
public void MutateState(ActionType action)
|
||||||
{
|
{
|
||||||
|
|||||||
+14
-14
@@ -1,17 +1,17 @@
|
|||||||
namespace Craftimizer.Simulator;
|
namespace Craftimizer.Simulator;
|
||||||
|
|
||||||
public record struct Effects
|
public struct Effects
|
||||||
{
|
{
|
||||||
public byte InnerQuiet { get; set; }
|
public byte InnerQuiet;
|
||||||
public byte WasteNot { get; set; }
|
public byte WasteNot;
|
||||||
public byte Veneration { get; set; }
|
public byte Veneration;
|
||||||
public byte GreatStrides { get; set; }
|
public byte GreatStrides;
|
||||||
public byte Innovation { get; set; }
|
public byte Innovation;
|
||||||
public byte FinalAppraisal { get; set; }
|
public byte FinalAppraisal;
|
||||||
public byte WasteNot2 { get; set; }
|
public byte WasteNot2;
|
||||||
public byte MuscleMemory { get; set; }
|
public byte MuscleMemory;
|
||||||
public byte Manipulation { get; set; }
|
public byte Manipulation;
|
||||||
public bool HeartAndSoul { get; set; }
|
public bool HeartAndSoul;
|
||||||
|
|
||||||
public void SetDuration(EffectType effect, byte duration)
|
public void SetDuration(EffectType effect, byte duration)
|
||||||
{
|
{
|
||||||
@@ -57,7 +57,7 @@ public record struct Effects
|
|||||||
InnerQuiet++;
|
InnerQuiet++;
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte GetDuration(EffectType effect) =>
|
public readonly byte GetDuration(EffectType effect) =>
|
||||||
effect switch
|
effect switch
|
||||||
{
|
{
|
||||||
EffectType.InnerQuiet => (byte)(InnerQuiet != 0 ? 1 : 0),
|
EffectType.InnerQuiet => (byte)(InnerQuiet != 0 ? 1 : 0),
|
||||||
@@ -73,11 +73,11 @@ public record struct Effects
|
|||||||
_ => 0
|
_ => 0
|
||||||
};
|
};
|
||||||
|
|
||||||
public byte GetStrength(EffectType effect) =>
|
public readonly byte GetStrength(EffectType effect) =>
|
||||||
effect == EffectType.InnerQuiet ? InnerQuiet :
|
effect == EffectType.InnerQuiet ? InnerQuiet :
|
||||||
(byte)(GetDuration(effect) != 0 ? 1 : 0);
|
(byte)(GetDuration(effect) != 0 ? 1 : 0);
|
||||||
|
|
||||||
public bool HasEffect(EffectType effect) =>
|
public readonly bool HasEffect(EffectType effect) =>
|
||||||
GetDuration(effect) != 0;
|
GetDuration(effect) != 0;
|
||||||
|
|
||||||
public void DecrementDuration()
|
public void DecrementDuration()
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
namespace Craftimizer.Simulator;
|
namespace Craftimizer.Simulator;
|
||||||
|
|
||||||
public record SimulationInput
|
public sealed class SimulationInput
|
||||||
{
|
{
|
||||||
public CharacterStats Stats { get; }
|
public CharacterStats Stats { get; }
|
||||||
public RecipeInfo Recipe { get; }
|
public RecipeInfo Recipe { get; }
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
using Craftimizer.Simulator.Actions;
|
|
||||||
|
|
||||||
namespace Craftimizer.Simulator;
|
namespace Craftimizer.Simulator;
|
||||||
|
|
||||||
public readonly record struct SimulationState
|
public readonly struct SimulationState
|
||||||
{
|
{
|
||||||
public SimulationInput Input { get; init; }
|
public SimulationInput Input { get; init; }
|
||||||
|
|
||||||
|
|||||||
@@ -5,9 +5,9 @@ using System.Runtime.Intrinsics.X86;
|
|||||||
|
|
||||||
namespace Craftimizer.Solver.Crafty;
|
namespace Craftimizer.Solver.Crafty;
|
||||||
|
|
||||||
public sealed class ActionSet
|
public struct ActionSet
|
||||||
{
|
{
|
||||||
private uint Bits { get; set; }
|
private uint bits;
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private static int NthBitSet(uint value, int n)
|
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];
|
private static ActionType ToAction(int index) => Simulator.AcceptedActions[index];
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[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)]
|
[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)]
|
[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)]
|
[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);
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-6
@@ -4,25 +4,32 @@ namespace Craftimizer.Solver.Crafty;
|
|||||||
|
|
||||||
public class Arena<T> where T : struct
|
public class Arena<T> where T : struct
|
||||||
{
|
{
|
||||||
public readonly record struct Node
|
public readonly struct Node
|
||||||
{
|
{
|
||||||
public T State { get; init; }
|
public readonly T State;
|
||||||
public List<int> Children { get; init; }
|
public readonly List<int> Children;
|
||||||
public int Parent { get; init; }
|
public readonly int Parent;
|
||||||
|
|
||||||
|
public Node(T state, int parent)
|
||||||
|
{
|
||||||
|
State = state;
|
||||||
|
Children = new();
|
||||||
|
Parent = parent;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly List<Node> nodes = new();
|
private readonly List<Node> nodes = new();
|
||||||
|
|
||||||
public Arena(T initialState = default)
|
public Arena(T initialState = default)
|
||||||
{
|
{
|
||||||
nodes.Add(new() { Parent = -1, Children = new(), State = initialState });
|
nodes.Add(new(initialState, -1));
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public int Insert(int parentIndex, T state)
|
public int Insert(int parentIndex, T state)
|
||||||
{
|
{
|
||||||
var index = nodes.Count;
|
var index = nodes.Count;
|
||||||
nodes.Add(new() { Parent = parentIndex, Children = new(), State = state });
|
nodes.Add(new(state, parentIndex));
|
||||||
nodes[parentIndex].Children.Add(index);
|
nodes[parentIndex].Children.Add(index);
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
namespace Craftimizer.Solver.Crafty;
|
||||||
|
|
||||||
|
public class NodeData
|
||||||
|
{
|
||||||
|
public ActionSet AvailableActions;
|
||||||
|
public NodeScores Scores;
|
||||||
|
}
|
||||||
@@ -1,8 +1,15 @@
|
|||||||
namespace Craftimizer.Solver.Crafty;
|
namespace Craftimizer.Solver.Crafty;
|
||||||
|
|
||||||
public sealed class NodeScores
|
public struct NodeScores
|
||||||
{
|
{
|
||||||
public float ScoreSum { get; set; }
|
public float ScoreSum;
|
||||||
public float MaxScore { get; set; }
|
public float MaxScore;
|
||||||
public float Visits { get; set; }
|
public float Visits;
|
||||||
|
|
||||||
|
public void Visit(float score)
|
||||||
|
{
|
||||||
|
ScoreSum += score;
|
||||||
|
MaxScore = Math.Max(MaxScore, score);
|
||||||
|
Visits++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,18 +3,17 @@ using Craftimizer.Simulator.Actions;
|
|||||||
|
|
||||||
namespace Craftimizer.Solver.Crafty;
|
namespace Craftimizer.Solver.Crafty;
|
||||||
|
|
||||||
public readonly record struct SimulationNode
|
public readonly struct SimulationNode
|
||||||
{
|
{
|
||||||
public SimulationState State { get; init; }
|
public SimulationState State { get; init; }
|
||||||
public ActionType? Action { get; init; }
|
public ActionType? Action { get; init; }
|
||||||
public ActionSet AvailableActions { get; init; }
|
|
||||||
public CompletionState SimulationCompletionState { get; init; }
|
public CompletionState SimulationCompletionState { get; init; }
|
||||||
public CompletionState CompletionState =>
|
public CompletionState CompletionState =>
|
||||||
AvailableActions.Count == 0 && SimulationCompletionState == CompletionState.Incomplete ?
|
Data.AvailableActions.Count == 0 && SimulationCompletionState == CompletionState.Incomplete ?
|
||||||
CompletionState.NoMoreActions :
|
CompletionState.NoMoreActions :
|
||||||
SimulationCompletionState;
|
SimulationCompletionState;
|
||||||
|
|
||||||
public NodeScores Scores { get; init; }
|
public NodeData Data { get; init; }
|
||||||
|
|
||||||
public bool IsComplete => CompletionState != CompletionState.Incomplete;
|
public bool IsComplete => CompletionState != CompletionState.Incomplete;
|
||||||
|
|
||||||
|
|||||||
+14
-20
@@ -28,8 +28,7 @@ public class Solver
|
|||||||
State = state,
|
State = state,
|
||||||
Action = null,
|
Action = null,
|
||||||
SimulationCompletionState = Simulator.CompletionState,
|
SimulationCompletionState = Simulator.CompletionState,
|
||||||
AvailableActions = Simulator.AvailableActionsHeuristic(strict),
|
Data = new() { AvailableActions = Simulator.AvailableActionsHeuristic(strict) }
|
||||||
Scores = new()
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,8 +44,7 @@ public class Solver
|
|||||||
State = newState,
|
State = newState,
|
||||||
Action = action,
|
Action = action,
|
||||||
SimulationCompletionState = Simulator.CompletionState,
|
SimulationCompletionState = Simulator.CompletionState,
|
||||||
AvailableActions = Simulator.AvailableActionsHeuristic(strict),
|
Data = new() { AvailableActions = Simulator.AvailableActionsHeuristic(strict) }
|
||||||
Scores = new()
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,9 +57,9 @@ public class Solver
|
|||||||
if (node.IsComplete)
|
if (node.IsComplete)
|
||||||
return (currentIndex, node.CompletionState);
|
return (currentIndex, node.CompletionState);
|
||||||
|
|
||||||
if (!node.AvailableActions.HasAction(action))
|
if (!node.Data.AvailableActions.HasAction(action))
|
||||||
return (currentIndex, CompletionState.InvalidAction);
|
return (currentIndex, CompletionState.InvalidAction);
|
||||||
node.AvailableActions.RemoveAction(action);
|
node.Data.AvailableActions.RemoveAction(action);
|
||||||
|
|
||||||
currentIndex = Tree.Insert(currentIndex, Execute(node.State, action, strict));
|
currentIndex = Tree.Insert(currentIndex, Execute(node.State, action, strict));
|
||||||
}
|
}
|
||||||
@@ -122,7 +120,7 @@ public class Solver
|
|||||||
|
|
||||||
for (var j = 0; j < iterCount; ++j)
|
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;
|
scoreSums[j] = node.ScoreSum;
|
||||||
visits[j] = node.Visits;
|
visits[j] = node.Visits;
|
||||||
maxScores[j] = node.MaxScore;
|
maxScores[j] = node.MaxScore;
|
||||||
@@ -148,7 +146,7 @@ public class Solver
|
|||||||
{
|
{
|
||||||
var selectedNode = Tree.Get(selectedIndex);
|
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;
|
var likelyTerminal = selectedNode.Children.Count == 0;
|
||||||
if (expandable || likelyTerminal)
|
if (expandable || likelyTerminal)
|
||||||
{
|
{
|
||||||
@@ -156,7 +154,7 @@ public class Solver
|
|||||||
}
|
}
|
||||||
|
|
||||||
// select the node with the highest score
|
// 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)
|
if (initialNode.IsComplete)
|
||||||
return (initialIndex, initialNode.CompletionState, initialNode.CalculateScore() ?? 0);
|
return (initialIndex, initialNode.CompletionState, initialNode.CalculateScore() ?? 0);
|
||||||
|
|
||||||
var randomAction = initialNode.AvailableActions.ElementAt(0);
|
var randomAction = initialNode.Data.AvailableActions.ElementAt(0);
|
||||||
initialNode.AvailableActions.RemoveAction(randomAction);
|
initialNode.Data.AvailableActions.RemoveAction(randomAction);
|
||||||
var expandedState = Execute(initialNode.State, randomAction, true);
|
var expandedState = Execute(initialNode.State, randomAction, true);
|
||||||
var expandedIndex = Tree.Insert(initialIndex, expandedState);
|
var expandedIndex = Tree.Insert(initialIndex, expandedState);
|
||||||
|
|
||||||
@@ -179,7 +177,7 @@ public class Solver
|
|||||||
{
|
{
|
||||||
if (currentState.IsComplete)
|
if (currentState.IsComplete)
|
||||||
break;
|
break;
|
||||||
randomAction = currentState.AvailableActions.ElementAt(0);
|
randomAction = currentState.Data.AvailableActions.ElementAt(0);
|
||||||
actions.Add(randomAction);
|
actions.Add(randomAction);
|
||||||
currentState = Execute(currentState.State, randomAction, true);
|
currentState = Execute(currentState.State, randomAction, true);
|
||||||
}
|
}
|
||||||
@@ -188,7 +186,7 @@ public class Solver
|
|||||||
var score = currentState.CalculateScore() ?? 0;
|
var score = currentState.CalculateScore() ?? 0;
|
||||||
if (currentState.CompletionState == CompletionState.ProgressComplete)
|
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);
|
(var terminalIndex, _) = ExecuteActions(expandedIndex, actions, true);
|
||||||
return (terminalIndex, currentState.CompletionState, score);
|
return (terminalIndex, currentState.CompletionState, score);
|
||||||
@@ -203,11 +201,7 @@ public class Solver
|
|||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
var currentNode = Tree.Get(currentIndex);
|
var currentNode = Tree.Get(currentIndex);
|
||||||
var currentScores = currentNode.State.Scores;
|
currentNode.State.Data.Scores.Visit(score);
|
||||||
currentScores.Visits++;
|
|
||||||
currentScores.ScoreSum += score;
|
|
||||||
if (currentScores.MaxScore < score)
|
|
||||||
currentScores.MaxScore = score;
|
|
||||||
|
|
||||||
if (currentIndex == targetIndex)
|
if (currentIndex == targetIndex)
|
||||||
break;
|
break;
|
||||||
@@ -233,7 +227,7 @@ public class Solver
|
|||||||
var node = Tree.Get(0);
|
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);
|
var next_index = RustMaxBy(node.Children, n => Tree.Get(n).State.Data.Scores.MaxScore);
|
||||||
node = Tree.Get(next_index);
|
node = Tree.Get(next_index);
|
||||||
if (node.State.Action != null)
|
if (node.State.Action != null)
|
||||||
actions.Add(node.State.Action.Value);
|
actions.Add(node.State.Action.Value);
|
||||||
@@ -264,7 +258,7 @@ public class Solver
|
|||||||
solver.Search(0);
|
solver.Search(0);
|
||||||
var (solution_actions, solution_node) = solver.Solution();
|
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);
|
actions.AddRange(solution_actions);
|
||||||
return (actions, solution_node.State);
|
return (actions, solution_node.State);
|
||||||
|
|||||||
Reference in New Issue
Block a user