转:用Python实现A*算法
1 # -*- coding: utf-8 -*- 2 """ 3 Created on Mon Jul 30 15:20:32 2018 4 5 @author: caicai 6 """ 7 import sys 8 #定义变量 9 #1.边界 10 map_border=() 11 #接收地图 12 Map=[] 13 #开表 14 open_dic={} 15 #闭表 16 close_dic={} 17 #路径终点 18 endP=None 19 #路径起点 20 startP=None 21 #路径列表 22 listPath=[] 23 24 #定义路径的小点点类 25 class Point(object): 26 def __init__(self,x,y,parent): 27 if x<0 or x>=map_border[0] or y<0 or y>=map_border[1]: 28 raise Exception("坐标错误") 29 self.x=x;#横坐标 30 self.y=y;#纵坐标 31 self.parent=parent;#路径上的父节点 32 #A*公式 :F=G+H 33 34 if parent==None: 35 self.G=0 36 self.H=0 37 self.F=0 38 39 else: 40 self.G=parent.G+1 41 self.H=abs(endP.x-self.x)+abs(endP.y-self.y) 42 self.F=self.G+self.H 43 def setP(self,g,parent): 44 self.G=g+1 45 self.parent=parent 46 self.F=self.G+self.H 47 #将地图上走不通的点加入闭表 48 def construct_Close(): 49 global cose_dic,Map 50 """ 51 _map是一个二维数组 52 1.遍历整张地图的每一行 53 2.遍历每一行的每个点 54 3.如果这个点的值是1,则初始化为点类对象,加入闭表 55 """ 56 rowN=-1 57 for list1 in Map: 58 rowN=rowN+1 59 corN=0 60 for list2 in list1: 61 if list2==1: 62 close_dic[rowN,corN]=Point(rowN,corN,None) 63 64 corN=corN+1 65 66 67 68 #计算open表中F值最近的一个点 69 def evaluateF(): 70 global open_dic 71 """ 72 !ATTENTION:如果open表为空呢??? 73 遍历open表 74 找到具有最小F值的点点 返回 75 """ 76 #当open表为空的情况 77 if len(open_dic)==0: 78 raise Exception("路径找不到") 79 80 #在一个字典里找到最小值 81 min_num=9999 82 current_key=(0,0); 83 84 for k,v in open_dic.items(): 85 if v.F<min_num: 86 min_num=v.F 87 current_key=k 88 return open_dic[current_key] 89 90 def construct_open(current_P): 91 global endP,close_dic,open_dic 92 """ 93 1.将当前的点的所有邻接点变成点类对象放入邻接表中 94 **补充:需要将当前节点从开表中移除并加入闭表中!! 95 2.遍历邻接表 96 如果这个点正好是终点,则将终点构造为点类对象,结束,返回true 97 如果有点在close表中,不管它 98 如果有点在open表中,将重新计算它新的h值与以前的h值做比较 99 如果比以前h值小则重新设置h值和父节点 100 既不在close表又不在open表,加入open表中 101 102 3.结束 返回false 103 """ 104 105 close_dic[(current_P.x,current_P.y)]=current_P#将当前节点加入到闭表中 106 open_dic.pop((current_P.x,current_P.y))#以下为原作者方法 107 ''' 108 adjacent=[] 109 110 #添加相邻节点的时候要注意边界 111 #上 112 try: 113 adjacent.append(Point(current_P.x,current_P.y-1,current_P)) 114 except Exception as err: 115 pass 116 #下 117 try: 118 adjacent.append(Point(current_P.x+1,current_P.y,current_P)) 119 except Exception as err: 120 pass 121 #左 122 try: 123 adjacent.append(Point(current_P.x-1,current_P.y,current_P)) 124 except Exception as err: 125 pass 126 #右 127 try: 128 adjacent.append(Point(current_P.x,current_P.y+1,current_P)) 129 except Exception as err: 130 pass 131 132 #检查每一个相邻的点 133 for a in adjacent: 134 #如果是终点,结束 135 if (a.x,a.y)==(endP.x,endP.y): 136 new_G=current_P.G+1 137 endP.setP(new_G,current_P) 138 return True 139 #如果在close_list中,不去理他 140 if (a.x,a.y) in close_dic: 141 continue 142 #如果不在open_list中,则添加进去 143 if (a.x,a.y) not in open_dic: 144 open_dic[(a.x,a.y)]=a 145 #如果存在在open_list中,通过G值判断这个点是否更近 146 else: 147 exist_node=open_dic[(a.x,a.y)] 148 new_G=current_P.G+1 149 if new_G<exist_node.G: 150 exist_node.setP(new_G,current_P) 151 152 return False 153 #将当前节点从开表中移除 154 ''' 155 adje_dic={}#邻接表 156 #将邻接点加入邻接表中时注意exception so.. 157 #注意 try except的使用 158 try: 159 adje_dic[(current_P.x+1,current_P.y)]=Point(current_P.x+1,current_P.y,current_P) 160 except Exception as err: 161 pass 162 163 try: 164 adje_dic[(current_P.x-1,current_P.y)]=Point(current_P.x-1,current_P.y,current_P) 165 except Exception as err: 166 pass 167 168 try: 169 adje_dic[(current_P.x,current_P.y-1)]=Point(current_P.x,current_P.y-1,current_P) 170 except Exception as err: 171 pass 172 try: 173 adje_dic[(current_P.x,current_P.y+1)]=Point(current_P.x,current_P.y+1,current_P) 174 except Exception as err: 175 pass 176 #遍历邻接表 177 for k,v in adje_dic.items(): 178 if k==(endP.x,endP.y):#如果正好是终点 179 endP.setP(v.G,v.parent) 180 return True 181 if k in close_dic: 182 continue 183 elif k in open_dic: 184 if v.H>open_dic[k].H: 185 open_dic[k].setP(v.H,current_P) 186 else: 187 open_dic[k]=v 188 return False 189 190 #获取文件信息到地图中 191 def constructMap(url): 192 global Map,map_border 193 194 f=open(url)#获取文件对象 195 #第一行是文件的行数和列数 196 strr=f.readline() 197 lst=strr.split() 198 199 map_border=tuple(map(int,lst)) 200 x=0 201 while x<=map_border[0]: 202 strr=f.readline() 203 lis=strr.split() 204 lineN=list(map(int,lis)) 205 Map.append(lineN) 206 x=x+1 207 208 209 210 def findWay(startP,endP): 211 global open_dic 212 #先将起点加入到open表中 213 open_dic[(startP.x,startP.y)]=startP 214 p=startP 215 216 try: 217 while not construct_open(p): 218 p=evaluateF() 219 #需要考虑路径找不到的情况 220 except Exception as erro: 221 222 print (erro) 223 return False 224 225 return True 226 227 228 def construct_Path(P): 229 global listPath 230 #ATTENTION!:递归需要先写停止条件!!! 231 if P.parent==None: 232 return 233 234 235 236 if P.x>P.parent.x: 237 listPath.append("右") 238 if P.x<P.parent.x: 239 listPath.append("左") 240 if P.y<P.parent.y: 241 listPath.append("上") 242 if P.y>P.parent.y: 243 listPath.append("下") 244 construct_Path(P.parent) 245 246 if __name__=='__main__': 247 ''' 248 if len(sys.argv)<6: 249 print(len(sys.argv)) 250 raise Exception('参数格式:文件名 x1 y1 x2 y2 其中x1 y1代表开始坐标,x2 y2代表目标坐标') 251 print(len(sys.argv)) 252 else: 253 #从控制台读取参数 254 255 constructMap(sys.argv[1]) 256 start_x=int(sys.argv[2]) 257 start_y=int(sys.argv[3]) 258 end_x=int(sys.argv[4]) 259 end_y=int(sys.argv[5]) 260 startP=Point(start_x,start_y,None) 261 endP=Point(end_x,end_y,None) 262 263 ''' 264 url=str(input("please input the adress of the file: ")) 265 266 constructMap(url) 267 268 start_x=int(input("please input the x of the startP: ")) 269 start_y=int(input("please input the y of the startP: ")) 270 end_x=int(input("please input the x of the endP: ")) 271 end_y=int(input("please input the y of the endP: ")) 272 startP=Point(start_x,start_y,None) 273 endP=Point(end_x,end_y,None) 274 275 276 construct_Close() 277 278 279 #判断起点终点是否符合要求 280 if (startP.x,startP.y) in close_dic or (endP.x,endP.y) in close_dic: 281 282 raise Exception('输入的坐标不可走') 283 284 if findWay(startP,endP): 285 construct_Path(endP) 286 287 #列表方向调整为起点开始 288 listPath.reverse() 289 str_ori='' 290 for o in listPath: 291 str_ori=str_ori+o+' ' 292 print(str_ori) 293 294 295 296
原文章地址:https://www.cnblogs.com/jin521/p/8969521.html