-
Notifications
You must be signed in to change notification settings - Fork 1
/
AStar.cs
129 lines (107 loc) · 4.52 KB
/
AStar.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
117
118
119
120
121
122
123
124
125
126
127
128
129
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
// F = G + H
namespace Algorithms.GraphTraversal
{
public class AStar
{
class PriorityQueue<TPriority, TItem> : IEnumerable<KeyValuePair<TPriority, TItem>>
{
readonly SortedDictionary<TPriority, Queue<TItem>> _subqueues;
public PriorityQueue()
{
_subqueues = new SortedDictionary<TPriority, Queue<TItem>>(Comparer<TPriority>.Default);
}
public void Enqueue(TPriority priority, TItem item)
{
if (!_subqueues.ContainsKey(priority))
{
_subqueues.Add(priority, new Queue<TItem>());
}
_subqueues[priority].Enqueue(item);
}
public KeyValuePair<TPriority, TItem> Dequeue()
{
if (_subqueues.Any())
{
var first = _subqueues.First();
var nextItem = first.Value.Dequeue();
if (!first.Value.Any())
{
_subqueues.Remove(first.Key);
}
return new KeyValuePair<TPriority, TItem>(first.Key, nextItem);
}
else
throw new InvalidOperationException("The queue is empty");
}
public IEnumerator<KeyValuePair<TPriority, TItem>> GetEnumerator()
{
var q = _subqueues.SelectMany(pair => pair.Value.Select(item => new KeyValuePair<TPriority, TItem>(pair.Key, item)));
return q.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return ((IEnumerable)_subqueues).GetEnumerator();
}
}
public static IEnumerable<T> Explore<T>(T start, Func<T, IEnumerable<T>> getNeighbours, Func<T, T, int> getCost, Func<T, double> heuristic, Func<T, bool> isEnd = null)
{
return astar(start, getNeighbours, getCost, heuristic, false, isEnd);
}
private static IEnumerable<T> astar<T>(T start, Func<T, IEnumerable<T>> getNeighbours, Func<T, T, int> getCost, Func<T, double> heuristic, bool pathOnly,
Func<T, bool> isEnd = null)
{
var visitedFromAndCost = new Dictionary<T, Tuple<T, int>>();
var toVisit = new PriorityQueue<double, T>();
toVisit.Enqueue(0, start);
visitedFromAndCost.Add(start, new Tuple<T, int>(default(T), 0));
while (toVisit.Any())
{
var currentNode = toVisit.Dequeue();
var current = currentNode.Value;
var currentCost = currentNode.Key;
if (!pathOnly)
{
yield return current;
}
if (isEnd != null && isEnd(current))
{
if (pathOnly)
{
var path = new Queue<T>();
while (!current.Equals(start))
{
path.Enqueue(current);
current = visitedFromAndCost[current].Item1;
}
path.Enqueue(current);
while (path.Any())
{
yield return path.Dequeue();
}
}
yield break;
}
var neighboursWithCost = getNeighbours(current)
.Select(n => new { Neighbour = n, NewCost = visitedFromAndCost[current].Item2 + getCost(current, n) })
.Where(x =>
!visitedFromAndCost.ContainsKey(x.Neighbour)
|| x.NewCost < visitedFromAndCost[x.Neighbour].Item2)
.ToList();
foreach (var x in neighboursWithCost)
{
var priority = x.NewCost + heuristic(x.Neighbour);
toVisit.Enqueue(priority, x.Neighbour);
visitedFromAndCost[x.Neighbour] = new Tuple<T, int>(current, x.NewCost);
}
}
}
public static IEnumerable<T> FindPath<T>(T start, Func<T, IEnumerable<T>> getNeighbours, Func<T, T, int> getCost, Func<T, double> heuristic, Func<T, bool> isEnd = null)
{
return astar(start, getNeighbours, getCost, heuristic, true, isEnd);
}
}
}