-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathastar-impl.go
83 lines (69 loc) · 2.21 KB
/
astar-impl.go
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
package astar
import "container/heap"
type NodeToPriorityItemMap map[Node]*PriorityQueueAStarItem
func AStar(start, end Node) (distance float64, path []Node) {
// set up open/closed sets
nodeToPriorityQueueItem := NodeToPriorityItemMap{}
priorityQueue := &PriorityQueue{}
heap.Init(priorityQueue)
// add start node to open set
startNode := nodeToPriorityQueueItem.get(start)
startNode.open = true
startNode.estimatedTotalCost = startNode.node.EstimatedCost(end)
heap.Push(priorityQueue, startNode)
for priorityQueue.Len() > 0 {
current := heap.Pop(priorityQueue).(*PriorityQueueAStarItem)
current.open = false
current.closed = true
if current == nodeToPriorityQueueItem.get(end) {
return costAndPathToGoal(current)
}
for _, adjacent := range current.node.AdjacentNodes() {
adjacentNode := nodeToPriorityQueueItem.get(adjacent)
cost := current.cost + current.node.Cost(adjacent)
if (adjacentNode.closed) {
continue
}
// TODO: remove duplicated code
if (!adjacentNode.open) {
adjacentNode.cost = cost
adjacentNode.open = true
adjacentNode.estimatedTotalCost = cost + adjacent.EstimatedCost(end)
adjacentNode.parent = current
// node never visited before, should be PUSHED to heap
heap.Push(priorityQueue, adjacentNode)
} else if (cost < adjacentNode.cost) {
adjacentNode.cost = cost
adjacentNode.open = true
adjacentNode.estimatedTotalCost = cost + adjacent.EstimatedCost(end)
adjacentNode.parent = current
// node already visited, heap should be fixed, as node value has changed
heap.Fix(priorityQueue, adjacentNode.index)
}
}
}
return -1, nil
}
func costAndPathToGoal(from *PriorityQueueAStarItem) (float64, []Node) {
path := []Node{}
curr := from
for curr != nil {
path = append(path, curr.node)
curr = curr.parent
}
reverse(path)
return from.cost, path
}
func reverse(path []Node) {
for left, right := 0, len(path) - 1; left < right; left, right = left + 1, right - 1 {
path[left], path[right] = path[right], path[left]
}
}
func (nodeToPqItem NodeToPriorityItemMap) get(node Node) *PriorityQueueAStarItem {
n, ok := nodeToPqItem[node]
if !ok {
n = &PriorityQueueAStarItem{node: node }
nodeToPqItem[node] = n
}
return n
}