-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathAlgorithm.cs
116 lines (103 loc) · 3.71 KB
/
Algorithm.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using AstarGG.Structs;
namespace AStarGG
{
public class Algorithm<T, Cookie> where T : class
{
struct Step
{
public T Parent;
public int Cost;
public Step(T parent, int cost)
{
Parent = parent;
Cost = cost;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Update(T parent, int cost)
{
Parent = parent;
Cost = cost;
}
}
/// A representation of the world
readonly IMap<T, Cookie> world;
/// The nodes that are eligible for checking
readonly Dictionary<T, Step> nodes;
readonly MinHeap<T> minheap;
/// A tree where root is the origin, branches are destinations and vertices are paths
readonly PathTree<T> tree = new PathTree<T>();
/// The current node being analyzed
T current, destination;
public Algorithm(IMap<T, Cookie> world)
{
this.world = world;
nodes = new Dictionary<T, Step>();
minheap = new MinHeap<T>(null);
}
public List<T> PathToPoint(T start, T end, Cookie c, int cutoff = -1)
{
SetUp(start, end);
minheap.Comparator = (a,b) => Heuristic(b) - Heuristic(a);
UpdateOrOpenNeighbor(c, cutoff);
while (!minheap.IsEmpty && !tree.Contains(end))
MainLoop(c, cutoff);
return tree.PathTo(end); // Path or null if end not it tree
}
public PathTree<T> PathsFromPoint(T start, Cookie c, int cutoff = -1)
{
SetUp(start);
minheap.Comparator = (a,b) => nodes[b].Cost - nodes[a].Cost;
UpdateOrOpenNeighbor(c, cutoff);
while (!minheap.IsEmpty)
MainLoop(c, cutoff);
return tree;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
void SetUp(T start, T dest = null)
{
nodes.Clear();
minheap.Clear();
tree.New(start);
nodes[start] = new Step(null, 0);
current = start;
destination = dest;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
void UpdateOrOpenNeighbor(Cookie c, int cutoff)
{
var cost = nodes[current].Cost + world.MovementCost(current);
// If cannot cover more distance than the cutoff
if(cutoff >= 0 && cost > cutoff)
return;
foreach (var n in world.NeighborsOf(current, c))
{
// First time checking this node
if (!tree.Contains(n) && !nodes.ContainsKey(n))
{
nodes[n] = new Step(current, cost);
minheap.Push(n);
}
// Found better route to node
else if (nodes[n].Cost > cost)
{
if(tree.Contains(n))
tree.ParentOf[n] = current;
nodes[n].Update(current, cost);
minheap.Sort();
}
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
void MainLoop(Cookie c, int cutoff)
{
current = minheap.Pop();
tree.ParentOf[current] = nodes[current].Parent;
UpdateOrOpenNeighbor(c, cutoff);
}
/// Optimization criteria based on heuristics and the travel cost
[MethodImpl(MethodImplOptions.AggressiveInlining)]
int Heuristic(T n) => nodes[n].Cost + world.DistanceEstimation(n, destination);
}
}