1
+ from collections import deque
2
+
3
+ class Graph :
4
+ # example of adjacency list (or rather map)
5
+ # adjacency_list = {
6
+ # 'A': [('B', 1), ('C', 3), ('D', 7)],
7
+ # 'B': [('D', 5)],
8
+ # 'C': [('D', 12)]
9
+ # }
10
+
11
+ def __init__ (self , adjacency_list ):
12
+ self .adjacency_list = adjacency_list
13
+
14
+ def get_neighbors (self , v ):
15
+ return self .adjacency_list [v ]
16
+
17
+ # heuristic function with equal values for all nodes
18
+ def h (self , n ):
19
+ H = {
20
+ 'A' : 1 ,
21
+ 'B' : 1 ,
22
+ 'C' : 1 ,
23
+ 'D' : 1
24
+ }
25
+
26
+ return H [n ]
27
+
28
+ def a_star_algorithm (self , start_node , stop_node ):
29
+ # open_list is a list of nodes which have been visited, but who's neighbors
30
+ # haven't all been inspected, starts off with the start node
31
+ # closed_list is a list of nodes which have been visited
32
+ # and who's neighbors have been inspected
33
+ open_list = set ([start_node ])
34
+ closed_list = set ([])
35
+
36
+ # g contains current distances from start_node to all other nodes
37
+ # the default value (if it's not found in the map) is +infinity
38
+ g = {}
39
+
40
+ g [start_node ] = 0
41
+
42
+ # parents contains an adjacency map of all nodes
43
+ parents = {}
44
+ parents [start_node ] = start_node
45
+
46
+ while len (open_list ) > 0 :
47
+ n = None
48
+
49
+ # find a node with the lowest value of f() - evaluation function
50
+ for v in open_list :
51
+ if n == None or g [v ] + self .h (v ) < g [n ] + self .h (n ):
52
+ n = v ;
53
+
54
+ if n == None :
55
+ print ('Path does not exist!' )
56
+ return None
57
+
58
+ # if the current node is the stop_node
59
+ # then we begin reconstructin the path from it to the start_node
60
+ if n == stop_node :
61
+ reconst_path = []
62
+
63
+ while parents [n ] != n :
64
+ reconst_path .append (n )
65
+ n = parents [n ]
66
+
67
+ reconst_path .append (start_node )
68
+
69
+ reconst_path .reverse ()
70
+
71
+ print ('Path found: {}' .format (reconst_path ))
72
+ return reconst_path
73
+
74
+ # for all neighbors of the current node do
75
+ for (m , weight ) in self .get_neighbors (n ):
76
+ # if the current node isn't in both open_list and closed_list
77
+ # add it to open_list and note n as it's parent
78
+ if m not in open_list and m not in closed_list :
79
+ open_list .add (m )
80
+ parents [m ] = n
81
+ g [m ] = g [n ] + weight
82
+
83
+ # otherwise, check if it's quicker to first visit n, then m
84
+ # and if it is, update parent data and g data
85
+ # and if the node was in the closed_list, move it to open_list
86
+ else :
87
+ if g [m ] > g [n ] + weight :
88
+ g [m ] = g [n ] + weight
89
+ parents [m ] = n
90
+
91
+ if m in closed_list :
92
+ closed_list .remove (m )
93
+ open_list .add (m )
94
+
95
+ # remove n from the open_list, and add it to closed_list
96
+ # because all of his neighbors were inspected
97
+ open_list .remove (n )
98
+ closed_list .add (n )
99
+
100
+ print ('Path does not exist!' )
101
+ return None
102
+
103
+ def main ():
104
+ adjacency_list = {
105
+ 'A' : [('B' , 1 ), ('C' , 3 ), ('D' , 7 )],
106
+ 'B' : [('D' , 5 )],
107
+ 'C' : [('D' , 12 )]
108
+ }
109
+ graph1 = Graph (adjacency_list )
110
+ graph1 .a_star_algorithm ('A' , 'D' )
111
+
112
+ if __name__ == "__main__" :
113
+ main ()
0 commit comments