代码片段(2)
[代码] A星
001 | #coding:utf-8 |
002 | ''' |
003 | Created on 2011-11-11 |
004 | 准备工作: |
005 | 1.构建节点元素类(父节点,节点X坐标,节点Y坐标,A*关键元素:F,G,H F=G+H) |
006 | 2.构建A*搜索类(起点,终点的坐标,搜索格子大小,开放列表,关闭列表,保持路径的列表) |
007 | |
008 | A*过程: |
009 | 1.构建开始节点,将开始节点放入开放列表(开始节点的F和G值都视为0); |
010 | while True: #第2,3步骤如下 |
011 | 2.选择起点作为当前节点并向四周扩展节点,循环遍历周围的节点 |
012 | i. 循环遍历周围的节点,保存他的F,G,H,判断是否在地图内,是否可通行(或你自己的其他条件), |
013 | 如果不满足条件则向下一个方向的节点扩展,如果满足则构建节点的元素(坐标,F,G,H,父节点) |
014 | ii.判断节点是否在在关闭列表,在关闭列表就不执行,继续遍历扩展下一个节点 |
015 | iii.如果节点不在开放列表,则将该节点添加到开放列表中, 并将该当前节点设为他的父节点,同时保存他的G,H和F值 |
016 | iv.如果该节点在开放列表中,则判断若经过当前节点到达该节点的G值是否小于原来保存的G值,若小于 |
017 | 将当前节点设为他的父节点,同时保存他的G,H和F值,继续下一节点的搜索 |
018 | 3.判断开放列表是否为空,若为空则没到目的地,退出;如果不为空,则执行以下操作 |
019 | i.对开放列表从小到大排序,选择第一个节点作为当前节点(用一变量保持),判断当前节点是否到达了终点, |
020 | 如果是,那就根据当前节点的父节点回溯到开始节点,这就是要找到的路径 |
021 | ii.如果当前节点不是终点,那将当前节点添加到关闭列表,并从开放列表中删除 |
022 | iii.把保存的当前节点作为当前节点向四周扩散(执行第2个步骤,直到开发列表为空或到达终点) |
023 | |
024 | 循环结束条件: |
025 | 当终点节点被加入到开放列表作为待检验节点时, 表示路径被找到,此时应终止循环; |
026 | 或者当开放列表为空,表明已无可以添 |
027 | 加的新节点,而已检验的节点中没有终点节点则意味着路径无法被找到,此时也结束循环; |
028 | @author: G0561 |
029 | ''' |
030 | global BLOCK_XROW #地图格子的行数 |
031 | global BLOCK_YCOL #地图格子的列数 |
032 | BLOCK_XROW = 60 |
033 | BLOCK_YCOL = 31 |
034 | tm = [ |
035 | '############################################################' , |
036 | '#.............................#............................#' , |
037 | '#.............................#............................#' , |
038 | '#.............................#............................#' , |
039 | '#.............................#............................#' , |
040 | '#.............................#............................#' , |
041 | '#.............................#............................#' , |
042 | '#.............................#............................#' , |
043 | '#.............................#............................#' , |
044 | '#.............................#............................#' , |
045 | '#.............................#............................#' , |
046 | '#.............................#............................#' , |
047 | '#.............................#............................#' , |
048 | '#######.#######################################............#' , |
049 | '#....#........#............................................#' , |
050 | '#....#........#............................................#' , |
051 | '#....######.###............................................#' , |
052 | '#..........................................................#' , |
053 | '#..........................................................#' , |
054 | '#..........................................................#' , |
055 | '#..........................................................#' , |
056 | '#..........................................................#' , |
057 | '#...............................##############.............#' , |
058 | '#...............................#............#.............#' , |
059 | '#...............................#............#.............#' , |
060 | '#...............................#............#.............#' , |
061 | '#...............................#............#.............#' , |
062 | '#...............................###########..#.............#' , |
063 | '#..........................................................#' , |
064 | '#..........................................................#' , |
065 | '############################################################' ] |
066 | test_map = [] #测试用 |
067 | class Node(): |
068 | """节点类 |
069 | parent:当前节点的父节点 |
070 | r,c:当前节点的行,列坐标 |
071 | F: 当前点到起点,当前点到终点的总消耗(距离) |
072 | G:当前点到起点的距离 |
073 | H: 当前点到终点的距离 |
074 | """ |
075 | def __init__( self , parent, r, c, F, G, H): |
076 | self .parent = parent |
077 | self .xrow = r |
078 | self .ycol = c |
079 | self .F = F |
080 | self .G = G |
081 | self .H = H |
082 | |
083 | |
084 | class Astar(): |
085 | """A星算法实现类 |
086 | sr,sc:起点的行,列 |
087 | er,ec:目标点得行列 |
088 | BLOCK_XROW,BLOCK_YCOL:地图格子总的行和列 |
089 | open,close,path:寻路中的开启,关闭,路径列表 |
090 | """ |
091 | global BLOCK_XROW, BLOCK_YCOL |
092 | def __init__( self , sr, sc, er, ec, BLOCK_XROW, BLOCK_YCOL): |
093 | self .starXrow = sr |
094 | self .starYcol = sc |
095 | self .endXrow = er |
096 | self .endYcol = ec |
097 | self .totalXrow = BLOCK_XROW |
098 | self .totalYcol = BLOCK_YCOL |
099 | |
100 | self . open = [] |
101 | self .close = [] |
102 | self .path = [] |
103 | |
104 | def judgeInMap( self , r, c): |
105 | """判断是否在地图内 |
106 | r,c:节点的行列坐标 这里可以添加你的判断,比如地形什么的 |
107 | """ |
108 | if (r < 0 or r > = BLOCK_XROW or c < 0 or c > = BLOCK_YCOL): #地图外面 |
109 | return False |
110 | return test_map[c][r] ! = '#' #针对当前寻路的判断 |
111 | |
112 | def judgeToTarget( self , node): |
113 | """判断是否到达目标节点 |
114 | node为一个节点 |
115 | """ |
116 | return (node.xrow = = self .endXrow and node.ycol = = self .endYcol) |
117 | |
118 | def judgeNodeisInOpen( self , node): #判断当前节点是否在开启列表中 |
119 | for i, n in enumerate ( self . open ): |
120 | if (n.xrow = = node.xrow and n.ycol = = node.ycol): |
121 | return i |
122 | return - 1 |
123 | |
124 | def judgeNodeisInClose( self , node): #判断当前节点是否在关闭列表中 |
125 | |
126 | for n in self .close: |
127 | if (n.xrow = = node.xrow and n.ycol = = node.ycol): |
128 | return True |
129 | return False |
130 | |
131 | def get_cost( self , parent_row, parent_col, cur_row, cur_col): |
132 | """获得当前节点到父节点的消耗,1.4为大概值,这样设置是为增加效率 |
133 | 直线方向(上下左右)为1.0,对角方向为1.4 |
134 | """ |
135 | if (cur_row = = parent_row or cur_col = = parent_col): |
136 | return 1.0 |
137 | return 1.4 |
138 | |
139 | def getCurToEnd( self , currow, curcol): |
140 | """曼哈顿方法求当前节点到终点的距离(消耗) 概率方法 |
141 | 曼哈顿方法:它计算从当前格到目的格之间水平和垂直的方格的数量总和,忽略对角线方向。然后把结果乘以1 |
142 | """ |
143 | r = abs ( self .endXrow - currow) |
144 | c = abs ( self .endYcol - curcol) |
145 | return (r + c) * 1 |
146 | |
147 | def compare( self , a, b): |
148 | """ |
149 | 用于sort函数排序用,根据F值来进行 用于对open(开启列表)进行排序 |
150 | """ |
151 | if a.F > b.F: |
152 | return 1 |
153 | elif a.F < b.F: |
154 | return - 1 |
155 | return 0 |
156 | |
157 | |
158 | def extend_node( self , node): |
159 | """向四周扩展节点 |
160 | node 为当前节点 |
161 | """ |
162 | #可以从8个方向走 |
163 | #xs = (-1, 0, 1, -1, 1, -1, 0, 1) |
164 | #ys = (-1, -1, -1, 0, 0, 1, 1, 1) |
165 | #只能走上下左右四个方向 |
166 | xs = ( 0 , - 1 , 1 , 0 ) |
167 | ys = ( - 1 , 0 , 0 , 1 ) |
168 | |
169 | print "当前节点坐标:" , node.xrow, node.ycol |
170 | i = 0 |
171 | for row, col in zip (xs, ys): #遍历方向扩展节点 |
172 | new_row = node.xrow + row |
173 | new_col = node.ycol + col |
174 | |
175 | i + = 1 |
176 | print "扩展节点%d: %d %d" % (i, new_row, new_col) |
177 | |
178 | #求新建节点的F,H,G |
179 | G = node.G + self .get_cost(node.xrow, node.ycol, new_row, new_col) #当前节点(node)到起点的距离 |
180 | H = self .getCurToEnd(new_row, new_col) #当前节点(node)到终点的距离 |
181 | F = G + H #总消耗 |
182 | |
183 | #如果不在地图内则忽略 这里还可增加其其它的条件,可通过则构造新的节点 |
184 | if not self .judgeInMap(new_row, new_col): |
185 | continue |
186 | newnode = Node(node, new_row, new_col, F, G, H) #构建新节点 |
187 | |
188 | #如果当前节点在关闭列表中,则忽略 |
189 | if self .judgeNodeisInClose(newnode): |
190 | continue |
191 | |
192 | i = self .judgeNodeisInOpen(newnode) #新节点在开放列表 |
193 | |
194 | if i ! = - 1 : |
195 | """ |
196 | 如果新的G值更低,那就把相邻方格的父节点改为目前选中的方格,对应的H,G也跟着变化 |
197 | """ |
198 | if self . open [i].G > newnode.G: |
199 | self . open [i].parent = node |
200 | self . open [i].G = G |
201 | self . open [i].H = H |
202 | continue |
203 | #如果新节点不在开发列表,则将其添加到开发列表 |
204 | self . open .append(newnode) |
205 | """#测试代码 |
206 | print "当前开放列表坐标如下:" |
207 | for i in xrange(len(self.open)): |
208 | print "%c%d%c%d%c" % ('(' , self.open[i].xrow, ',', self.open[i].ycol , ')') |
209 | #print "当前关闭列表坐标如下:" |
210 | #for i in xrange(len(self.close)): |
211 | # print "%c%d%c%d%c" % ('(' , self.close[i].xrow, ',', self.close[i].ycol , ')') |
212 | """ |
213 | |
214 | def findPath( self ): |
215 | """寻找路径 |
216 | """ |
217 | startnode = Node( None , self .starXrow, self .starYcol, 0 , 0 , 0 ) #起点 |
218 | self . open .append(startnode) |
219 | |
220 | while True : |
221 | self .extend_node(startnode) #扩展节点 |
222 | |
223 | if len ( self . open ) = = 0 : #开启列表为空 |
224 | print "没有路径到达" |
225 | return |
226 | #对开启列表节点从大到小排序 |
227 | self . open .sort( cmp = self .compare) |
228 | """ 测试代码 |
229 | print "open排序后 " |
230 | for i in xrange(len(self.open)): |
231 | if self.open[i].parent == None: |
232 | continue |
233 | print (self.open[i].parent.xrow, self.open[i].parent.ycol, self.open[i].xrow, self.open[i].ycol, self.open[i].F, self.open[i].G, self.open[i].H) |
234 | |
235 | """ |
236 | |
237 | #获取开启列表中F值最小的节点 每次都要对开启列表排序 |
238 | startnode = self . open [ 0 ] |
239 | if self .judgeToTarget(startnode): #到达终点 |
240 | print "到达终点啦" |
241 | self .get_path(startnode) |
242 | #self.printPath() #打印搜到的坐标 |
243 | return |
244 | |
245 | print "被删除:" , ( self . open [ 0 ].xrow, self . open [ 0 ].ycol) |
246 | |
247 | #将节点压入关闭列表 |
248 | self .close.append(startnode) |
249 | del self . open [ 0 ] |
250 | |
251 | #break |
252 | |
253 | def get_path( self , node): |
254 | """ |
255 | #从结束点开始回溯到开始节点,开始点的parent == None,获得正确的路径 |
256 | """ |
257 | while node: |
258 | self .path.append(node) |
259 | node = node.parent |
260 | |
261 | #--------------------------------测试代码-------------------------------------------- |
262 | def printPath( self ): |
263 | #打印已经搜到到的路径坐标 |
264 | for i in xrange ( len ( self .path)): |
265 | print "%c%d%c%d%c" % ( '(' , self .path[i].xrow, ',' , self .path[i].ycol, ')' ) |
266 | def print_test_map( self ): |
267 | """ |
268 | 打印搜索后的地图 将搜到的路径坐标打印 这个坐标要注意了 |
269 | test_map 每行都是一列表 |
270 | """ |
271 | for i in xrange ( len ( self .path)): |
272 | test_map[ self .path[i].ycol][ self .path[i].xrow] = '*' |
273 | #将已经搜索的路径弄成"*" |
274 | for line in test_map: |
275 | print ''.join(line) |
276 | #--------------------------------测试代码-------------------------------------------- |
277 | #--------------------------------测试代码-------------------------------------------- |
278 | def tm_to_test_map(): |
279 | #将tm每行变成列表的形式 |
280 | for line in tm: |
281 | test_map.append( list (line)) |
282 | |
283 | |
284 | def find_path(): |
285 | tm_to_test_map() #创建格子 |
286 | a_star = Astar( 8 , 5 , 37 , 25 , 60 , 31 ) #建立对象 |
287 | a_star.findPath() #搜索路径 |
288 | a_star.print_test_map() #打印搜的路径坐标 |
289 | |
290 | |
291 | if __name__ = = "__main__" : |
292 | find_path() |
[图片] A.png
![](https://i-blog.csdnimg.cn/blog_migrate/af90ac0a98f46def070163bd12f35469.png)