Skip to content

Commit 5c22b20

Browse files
committed
Clear and reuse NodeSet
1 parent a15dd5b commit 5c22b20

File tree

4 files changed

+46
-34
lines changed

4 files changed

+46
-34
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ Parametric actions are supported; they are concise and type safe. Check the [Bak
9494

9595
Quick and simple Unity integration via [GameAI.cs](Runtime/GameAI.cs) - for details, [read here](Documentation/BakerUnity.md).
9696

97-
Ready to GOAP? [follow the guide](Documentation/Overview.md).
97+
Ready to GOAP? [Follow the guide](Documentation/Overview.md).
9898

9999
## Getting involved
100100

Runtime/Details/NodeSet.cs

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -12,39 +12,34 @@ public class NodeSet<T> : Base{
1212
HashSet<T> states = new HashSet<T>();
1313
List<Node<T>> list = new List<Node<T>>();
1414

15-
public NodeSet(T x, Heuristic<T> h, bool sorted = true,
16-
int capacity = 128,
17-
float precision = 0){
15+
public NodeSet(){}
16+
17+
public NodeSet<T> Init(T x, Heuristic<T> h, bool sorted = true,
18+
int capacity = 128,
19+
float precision = 0){
20+
if(visited > 0 || count > 0)
21+
throw new Exception("Clear NodeSet first");
1822
this.h = h;
1923
this.sorted = sorted;
2024
this.capacity = capacity;
2125
this.precision = precision;
2226
states.Add(Assert(x, "Initial state"));
2327
list.Add(new Node<T>(INITIAL_STATE, x));
28+
return this;
2429
}
2530

26-
public bool capacityExceeded => count > capacity;
27-
2831
public static implicit operator bool(NodeSet<T> self)
2932
=> self.count > 0 && self.count <= self.capacity;
3033

31-
internal int count => list.Count;
34+
public bool capacityExceeded => count > capacity;
35+
public int visited => states.Count;
36+
public int count => list.Count;
3237

3338
public bool Insert(Node<T> n){
3439
if(!states.Add(n.state)) return false;
3540
if(sorted){
3641
n.value = n.cost + (h != null ? h(n.state) : 0);
3742
if(precision > 0) n.value = (int)(n.value / precision);
38-
// NOTE: In actual use, tested 4x faster than SortedSet;
39-
// Likely bottleneck with SortedSet is the API, not the
40-
// algorithm; SortedSet needs total, ordering:
41-
// - a.CompareTo(a) == 0
42-
// - a.CompareTo(b) must positive if b.CompareTo(a) is
43-
// negative.
44-
// Superficially these rules are sound. In practice to
45-
// just order elements by cost, this is overkill.
46-
// Also getting Min/Max item is cheap, but there's no way
47-
// to combine this with a 'pop'
4843
for(int i = list.Count-1; i >= 0; i--){
4944
if(n.value <= list[i].value){
5045
list.Insert(i + 1, n);
@@ -55,8 +50,12 @@ public bool Insert(Node<T> n){
5550
}
5651

5752
public Node<T> Pop(){
58-
int i = list.Count-1; var n = list[i]; list.RemoveAt(i);
53+
int i = list.Count-1;
54+
var n = list[i];
55+
list.RemoveAt(i);
5956
return n;
6057
}
6158

59+
public void Clear(){ states.Clear(); list.Clear(); }
60+
6261
}}

Runtime/Solver.cs

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public class Solver<T> : SolverStats where T : class{
1717
T initialState;
1818
Dish<T> dish;
1919
Goal<T> goal;
20-
NodeSet<T> avail = null;
20+
NodeSet<T> avail = new NodeSet<T>();
2121

2222
public bool isRunning => status == S.Running;
2323

@@ -27,8 +27,7 @@ public Node<T> Next(T s, in Goal<T> goal, int cap=-1){
2727
initialState = s;
2828
this.goal = goal;
2929
iteration = 0;
30-
avail = new NodeSet<T>(s, goal.h, !brfs, maxNodes,
31-
tolerance);
30+
avail.Init(s, goal.h, !brfs, maxNodes, tolerance);
3231
return Iterate(cap);
3332
}
3433

@@ -41,19 +40,18 @@ public Node<T> Iterate(int cap=-1){
4140
var current = avail.Pop();
4241
if(goal.match(current.state)){
4342
status = S.Done;
43+
avail.Clear();
4444
return current;
4545
}
4646
ExpandActions(current, avail);
4747
ExpandMethods(current, avail);
4848
if(avail.count > peak) peak = avail.count;
4949
}
50-
if(avail.capacityExceeded){
51-
status = S.CapacityExceeded;
52-
}else{
53-
status = avail
50+
status = avail.capacityExceeded ? S.CapacityExceeded
51+
: status = avail
5452
? (iteration < maxIter ? S.Running : S.MaxIterExceeded)
5553
: S.Failed;
56-
}
54+
if(status != S.Running) avail.Clear();
5755
return null;
5856
}
5957

Tests/Editor/NodeSetTest.cs

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,22 @@ public class NodeSetTest : TestBase{
99
Idler idler = new Idler();
1010

1111
[SetUp] public void Setup()
12-
=> x = new NodeSet<Idler>(idler, null);
12+
=> x = new NodeSet<Idler>().Init(idler, null);
13+
14+
[Test] public void NeedsClearBeforeInit()
15+
=> Assert.Throws<Exception>( () => x.Init(idler, null) );
1316

1417
[Test] public void InitStateMustExist ()
1518
=> Assert.Throws<NullReferenceException>(
16-
() => new NodeSet<Idler>(null, null));
19+
() => new NodeSet<Idler>().Init(null, null));
1720

1821
[Test] public void TrueWithinCapacity()
1922
{ if(x){ } else Assert.Fail(); }
2023

21-
[Test] public void FalseOverCapacity()
22-
{ o((bool)new NodeSet<Idler>(idler, null, capacity: 0), false); }
24+
[Test] public void FalseOverCapacity(){
25+
o((bool)new NodeSet<Idler>().Init(idler, null, capacity: 0),
26+
false);
27+
}
2328

2429
[Test] public void FalseWhenEmpty()
2530
{ x.Pop(); o( (bool)x, false); }
@@ -28,20 +33,30 @@ [Test] public void InsertAndSkipExisting()
2833
{ x.Insert(new Node<Idler>("x", idler)); o( x.count, 1); }
2934

3035
[Test] public void InsertUnsorted(){
31-
var z = new NodeSet<T>(new T(), null);
36+
var z = newWith_T;
3237
z.sorted = false;
33-
z.Insert(new Node<T>("x", new T())); o( z.count, 2);
38+
z.Insert(newNode_T); o( z.count, 2);
3439
}
3540

3641
[Test] public void InsertAndSort(){
37-
var z = new NodeSet<T>(new T(), null);
38-
z.Insert(new Node<T>("x", new T())); o( z.count, 2); }
42+
var z = newWith_T;
43+
z.Insert(newNode_T); o( z.count, 2); }
3944

4045
[Test] public void Pop(){
4146
var z = x.Pop(); o( x.count, 0 ); o( z.state is Idler );
4247
o( z.action, INITIAL_STATE);
4348
}
4449

50+
[Test] public void Clear(){
51+
var z = newWith_T;
52+
o( z.count, 1 ); o( z.visited, 1 );
53+
x.Clear();
54+
o( x.count, 0 ); o( x.visited, 0 );
55+
}
56+
57+
NodeSet<T> newWith_T => new NodeSet<T>().Init(new T(), null);
58+
Node<T> newNode_T => new Node<T>("x", new T());
59+
4560
class T{
4661
int x = 0; public T() {} public T(int x){ this.x = x; }
4762
}

0 commit comments

Comments
 (0)