-
Notifications
You must be signed in to change notification settings - Fork 0
/
a_star.py
121 lines (103 loc) · 3.23 KB
/
a_star.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
119
120
121
import heapq
import random
def main():
n = 5
p = FindPath(n)
print('Start')
p.print_grid()
print()
print('Output')
p.a_star()
class Point:
def __init__(self, row, col):
self.f = float('inf')
self.g = float('inf')
self.h = 0
self.row = row
self.col = col
self.val = 0
# adds obstacles at random points with a certain prob
# sets the value of every obstacle to -1
if random.randint(1, 10) < 3:
self.val = -1
class FindPath:
def __init__(self, n):
# builds the grid and initializes it with Points
self.grid = self.build_grid(n)
# initializes start and end points
self.start = self.grid[0][0]
self.end = self.grid[-1][-1]
# sets heuristic values for all points on the grid
self.set_heuristic_val()
# initializes start and end points
self.init_std_points()
# min-heap that includes all points to be processed
self.openset = []
# includes points that are finished to be processed
self.closedset = set()
# maintains the path from start to end
self.came_from = {}
#add start point in the min_heap
heapq.heappush(self.openset, (self.start.f, 0, 0))
def set_heuristic_val(self):
# euclidean distance to find hval
for row in range(len(self.grid)):
for col in range(len(self.grid[0])):
self.grid[row][col].h = (row - len(self.grid))**2 + (col - len(self.grid[0]))**2
def init_std_points(self):
# initializes g and f values for start
self.start.g = 0
self.start.f = self.start.h
# overrides value for start and end to not be an obstacle
self.start.val = 1
self.end.val = 1
def print_path(self):
# prints final path from end to start
curr = self.end
while curr in self.came_from:
curr.val = 1
curr = self.came_from[curr]
self.print_grid()
def a_star(self):
while self.openset:
# smallest f-val from all the points to be processed
fval, row, col = heapq.heappop(self.openset)
point = self.grid[row][col]
# base-condition when point == end
if point == self.end:
self.print_path()
print()
print('Done!')
return
# add curr_point to closedSet
self.closedset.add(point)
# 8 directions
neighbors = [(-1,0),(-1,1),(0,1),(1,1),(1,0),(1,-1),(0,-1),(-1,-1)]
for nei in neighbors:
x = point.row + nei[0]
y = point.col + nei[1]
if x >= 0 and x < len(self.grid) and y >= 0 and y < len(self.grid[0]) and self.grid[x][y].val != -1:
tmp_g = point.g + self.dist(point, self.grid[x][y])
# if the dist from start to nei via curr_point is less, update values
if tmp_g < self.grid[x][y].g:
self.came_from[self.grid[x][y]] = point
self.grid[x][y].g = tmp_g
self.grid[x][y].f = self.grid[x][y].g + self.grid[x][y].h
if self.grid[x][y] not in self.closedset:
heapq.heappush(self.openset, (self.grid[x][y].f, x,y))
print('End cannot be reached')
def dist(self, src, dest):
# weight of the edge from source to dest
# currently all weights are 1
return 1
def print_grid(self):
for row in range(len(self.grid)):
for col in range(len(self.grid)):
print(self.grid[row][col].val, end = '\t')
print()
def build_grid(self,n):
# builds a n * n - grid matrix with the given dimension
grid = [[Point(row, col) for col in range(n)] for row in range(n)]
return grid
if __name__ == '__main__':
main()