-
Notifications
You must be signed in to change notification settings - Fork 43
/
Copy pathshortest-path-obstacle-avoidance.py
112 lines (83 loc) · 3.56 KB
/
shortest-path-obstacle-avoidance.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
'''Find the shortest path between two points in an nxn matrix with obstacles. The starting point A can be anywhere in
the matrix, and the end point B can be anywhere in the matrix. The matrix is filled with Os and Xs. Os represent open
spaces that can be moved to, and Xs represent obstacles that are not available. Valid movements are
left, right, up, or down.'''
from data_structures.graphs.adjacency_matrix import AdjacencyMatrix
import operator
import sys
def gridToGraph(matrix):
'''Converts 2D array to adjacency matrix'''
n = len(matrix)
graph = AdjacencyMatrix(n)
for i in range(n):
for j in range(n):
if matrix[i][j] == "O":
graph.addEdge(i, j)
return graph
def heuristic(start, end):
'''Manhattan Distance heuristic'''
return abs(start[0]-end[0]) + abs(start[1]-end[1])
def path(cameFrom, current):
'''Recreates path'''
totalPath = [current]
while current in cameFrom.keys():
current = cameFrom[current]
totalPath.append(current)
return totalPath
def aStar(start, end, graph):
'''A* Search Algorithm'''
# Evaluated nodes
closedSet = set()
# Unevaluated nodes
openSet = set()
openSet.add(start)
# Most efficient way to reach node
cameFrom = {}
# Cost of getting to each node from start node
# Initially cost of getting to any node is infinite, except for start
gScore = {}
for i in range(len(graph)):
for j in range(len(graph)):
gScore[(i, j)] = sys.maxsize
# Cost of getting to goal node from start node
fScore = gScore
gScore[start] = 0
fScore[start] = heuristic(start, end)
while openSet is not None:
current = None
tmp = sorted(fScore.items(), key=operator.itemgetter(1))
for i in tmp:
if i[0] in openSet:
current = i[0]
break
#current = min(key for key, value in fScore.items() if key in openSet)
if current == end:
return path(cameFrom, current)
openSet.remove(current)
closedSet.add(current)
currentNeighbors = [(current[0]+1, current[1]), (current[0], current[1]+1),(current[0]-1, current[1]), \
(current[0], current[1]-1),]
for neighbor in currentNeighbors:
if neighbor in closedSet:
continue # Ignore evaluated neighbors
if not graph.hasEdge(neighbor[0], neighbor[1]):
continue
if neighbor[0] < 0 or neighbor[1] < 0 or neighbor[0] > len(graph)-1 or neighbor[1] > len(graph)-1:
continue
tmp_gScore = gScore[current]+1 # Assumption is that graph is unweighted
# If graph is weighted, adjust tmp_gScore to variable cost
if neighbor not in openSet: # New node discovered
openSet.add(neighbor)
elif tmp_gScore >= gScore[neighbor]: # Ignore more expensive paths
continue
# Running best path
cameFrom[neighbor] = current
gScore[neighbor] = tmp_gScore
fScore[neighbor] = gScore[neighbor] + heuristic(neighbor, end)
return -1
# Example test case
if __name__ == "__main__":
testMatrix = [['X', 'X', 'O', 'X', 'X', 'X'], ['O', 'O', 'O', 'X', 'X', 'O'], ['O', 'X', 'O', 'O', 'O', 'O'], \
['O', 'X', 'X', 'O', 'X', 'X'], ['O', 'O', 'O', 'O', 'X', 'O'], ['O', 'X', 'O', 'O', 'O', 'O']]
test = gridToGraph(testMatrix)
print(aStar((0,2), (5,5), test))