转:用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

posted @ 2018-08-02 14:22  是甜甜啊  阅读(3361)  评论(0编辑  收藏  举报