-
Notifications
You must be signed in to change notification settings - Fork 0
/
astar.py
119 lines (88 loc) · 3.26 KB
/
astar.py
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
import numpy as np
import time
import math
from heapq import *
# 1 represents obstacle
field = np.array([
[0,0,0,0,1,0,0,0,0,0,0,0],
[0,0,0,0,1,0,0,0,0,0,0,0],
[0,0,0,1,1,1,1,1,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,1,1,1,0,0,0,0,0],
[0,0,0,0,1,0,1,0,0,0,0,0],
[0,0,0,0,0,0,1,0,0,0,0,0]])
# start/goal position
si, sj = 9, 5
gi, gj = 0, 5
# dir
r, l, up, dn = (0, 1), (0, -1), (1, 0), (-1, 0)
# cost(n,n')
one_step_cost = 1
# heuristic, Euclidean distance
def h_Eu(curr, dest):
return math.sqrt(pow((dest[0] - curr[0]), 2) + pow((dest[1] - curr[1]), 2))
# A* search
def astar(field, start, goal):
adj_dir = [r, l, up, dn] # possible move dir to adjacent blocks
closed = set() # set, format: ((cell), ...)
actual_path = {} # dictionary, format: {(child):(parent), ...}
g = {start:0} # format: {(cell):g(n), ...}
f = {start:h_Eu(start, goal)} # format: {(cell):h(n), ...}
op_heap = [] # a list (of tuples, eventually)
# Step1
heappush(op_heap, (f[start], start)) # append start node to open list
while op_heap: #Step5(loop)
# Step2
current = heappop(op_heap)[1]
if current == goal:
# trace
trace = []
while current in actual_path:
trace.append(current)
trace.append("->")
current = actual_path[current]
trace.append(current)
return trace
# Step3
closed.add(current)
for i, j in adj_dir:
adj_cell = current[0] + i, current[1] + j
tent_g = g[current] + one_step_cost # calculating cost, alternative; h_Eu(current, adj_cell)
if 0 <= adj_cell[0] < field.shape[0]: # as long as i is in the field
if 0 <= adj_cell[1] < field.shape[1]: # as long as j is in the field
if field[adj_cell[0]][adj_cell[1]] == 1: # skip if the cell is an obstacle
continue
else:
continue
else:
continue
# Step4
# if there is the same node with worse cost in closed list, then skip it
if adj_cell in closed and g.get(adj_cell, 0) <= tent_g:
continue
# if there is the same node with better cost in open list or there is no same node
if tent_g < g.get(adj_cell, 0) or adj_cell not in (i[1] for i in op_heap):
actual_path[adj_cell] = current
g[adj_cell] = tent_g
f[adj_cell] = tent_g + h_Eu(adj_cell, goal) # f = g + h
heappush(op_heap, (f[adj_cell], adj_cell))
# search failed
return False
'''
field: numpy array
astar(array, start, destination) -> returns a list of tuples (shortest path)
'''
def main():
print("Shortest path by A*;")
start = time.time()
path = astar(field, (si, sj), (gi, gj))
elapsed_time = time.time() - start
path.reverse()
print path
print('elapsed time: '+ str(elapsed_time) + '[sec]')
if __name__ == '__main__':
main()