forked from RemoteTechnologiesGroup/RemoteTech
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathNetworkPathfinder.cs
More file actions
101 lines (90 loc) · 4.09 KB
/
Copy pathNetworkPathfinder.cs
File metadata and controls
101 lines (90 loc) · 4.09 KB
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
using System;
using System.Collections.Generic;
using RemoteTech.SimpleTypes;
namespace RemoteTech
{
public static class NetworkPathfinder
{
// All sorting related data is immutable.
public static NetworkRoute<T> Solve<T>(T start, T goal,
Func<T, IEnumerable<NetworkLink<T>>> neighborsFunction,
Func<T, NetworkLink<T>, double> costFunction,
Func<T, T, double> heuristicFunction) where T : class
{
var nodeMap = new Dictionary<T, Node<NetworkLink<T>>>();
var priorityQueue = new PriorityQueue<Node<NetworkLink<T>>>();
var nStart = new Node<NetworkLink<T>>(new NetworkLink<T>(start, null, LinkType.None), 0, heuristicFunction.Invoke(start, goal), null, false);
nodeMap[start] = nStart;
priorityQueue.Enqueue(nStart);
while (priorityQueue.Count > 0)
{
var current = priorityQueue.Dequeue();
if (current.Closed) continue;
current.Closed = true;
if (current.Item.Target.Equals(goal))
{
// Return path and cost
var reversePath = new List<NetworkLink<T>>();
for (var node = current; node.From != null; node = node.From)
{
reversePath.Add(node.Item);
}
reversePath.Reverse();
return new NetworkRoute<T>(start, reversePath, current.Cost);
}
foreach (var link in neighborsFunction.Invoke(current.Item.Target))
{
double new_cost = current.Cost + costFunction.Invoke(current.Item.Target, link);
// Todo: Dennis: i use the fix from Taste83 #139 and i'll look closer if i'm more related to the Pathfinder
if (new_cost == current.Cost)
{
continue;
}
// If the item has a node, it will either be in the closedSet, or the openSet
if (nodeMap.ContainsKey(link.Target))
{
Node<NetworkLink<T>> n = nodeMap[link.Target];
if (new_cost <= n.Cost)
{
// Cost via current is better than the old one, discard old node, queue new one.
var new_node = new Node<NetworkLink<T>>(n.Item, new_cost, n.Heuristic, current, false);
n.Closed = true;
nodeMap[link.Target] = new_node;
priorityQueue.Enqueue(new_node);
}
}
else
{
// It is not in the openSet, create a node and add it
var new_node = new Node<NetworkLink<T>>(link, new_cost,
heuristicFunction.Invoke(link.Target, goal), current,
false);
priorityQueue.Enqueue(new_node);
nodeMap[link.Target] = new_node;
}
}
}
return NetworkRoute.Empty<T>(start);
}
private class Node<T> : IComparable<Node<T>>
{
public Node<T> From { get; set; }
public bool Closed { get; set; }
public int CompareTo(Node<T> node)
{
return (Cost + Heuristic).CompareTo(node.Cost + node.Heuristic);
}
public readonly double Cost;
public readonly double Heuristic;
public readonly T Item;
public Node(T item, double cost, double heuristic, Node<T> from, bool closed)
{
Item = item;
Cost = cost;
Heuristic = heuristic;
From = from;
Closed = closed;
}
}
}
}