论文网
English Papers
万事OK网
发表论文
 
 首页 > IT文章 > 程序设计 >
A*算法Python实现

[科技论文网] http://www.scipapers.com    2007-12-01  

    A*算法Python实现

    作者:恋花蝶

    本文由恋花蝶发表于http://blog.csdn.net/lanphaday,可以在保证全文完整的前提下任意形式自由传播,但必须保留本声明,违反必究。

     最近因为一个任务要用到A*算法,就用C++实现了一份。不过只是用A*来检测从A点到B点有无通路,不必输出路径,后来想把代码贴出来,但又觉得不如实现一个简单的寻路应用好一些,就用python写了一个版本贴上来。
     A*算法不仅仅可以用来寻路,寻路也不仅仅使用A*算法。这是使用学习和使用A*算法最要谨记的一点吧~
     A*算法用以寻路实现算不得是人工智能,他本质上是一种启发式的试探回溯算法,不过业界似乎喜欢把它称为游戏人工智能(GameAI)的一个组成部分,听起来就“豪华”得多了。A*算法需要很大的内存(相对于深度优先搜索),需要很实现比较复杂的逻辑,容易出错。
     A*过程:
     1.将开始节点放入开放列表(开始节点的F和G值都视为0);
     2.重复一下步骤:
      i.在开放列表中查找具有最小F值的节点,并把查找到的节点作为当前节点;
      ii.把当前节点从开放列表删除, 加入到封闭列表;
      iii.对当前节点相邻的每一个节点依次执行以下步骤:
       1.如果该相邻节点不可通行或者该相邻节点已经在封闭列表中,则什么操作也不执行,继续检验下一个节点;
       2.如果该相邻节点不在开放列表中,则将该节点添加到开放列表中, 并将该相邻节点的父节点设为当前节点,同时保存该相邻节点的G和F值;
       3.如果该相邻节点在开放列表中, 则判断若经由当前节点到达该相邻节点的G值是否小于原来保存的G值,若小于,则将该相邻节点的父节点设为当前节点,并重新设置该相邻节点的G和F值.
      iv.循环结束条件:
       当终点节点被加入到开放列表作为待检验节点时, 表示路径被找到,此时应终止循环;
       或者当开放列表为空,表明已无可以添加的新节点,而已检验的节点中没有终点节点则意味着路径无法被找到,此时也结束循环;
     3.从终点节点开始沿父节点遍历, 并保存整个遍历到的节点坐标,遍历所得的节点就是最后得到的路径;

     好了,废话不多说,看代码吧,带详尽注释,但可能存在bug~,另:本示例程序未作优化。

    参考资料:
    http://www.gamedev.net/reference/programming/features/astar/default.asp

    http://blog.csdn.net/win32asn/archive/2006/03/17/627098.aspx

    # -*- coding: utf-8 -*-
    import math

    #地图
    tm = [
    '############################################################',
    '#..........................................................#',
    '#.............................#............................#',
    '#.............................#............................#',
    '#.............................#............................#',
    '#.......S.....................#............................#',
    '#.............................#............................#',
    '#.............................#............................#',
    '#.............................#............................#',
    '#.............................#............................#',
    '#.............................#............................#',
    '#.............................#............................#',
    '#.............................#............................#',
    '#######.#######################################............#',
    '#....#........#............................................#',
    '#....#........#............................................#',
    '#....##########............................................#',
    '#..........................................................#',
    '#..........................................................#',
    '#..........................................................#',
    '#..........................................................#',
    '#..........................................................#',
    '#...............................##############.............#',
    '#...............................#........E...#.............#',
    '#...............................#............#.............#',
    '#...............................#............#.............#',
    '#...............................#............#.............#',
    '#...............................###########..#.............#',
    '#..........................................................#',
    '#..........................................................#',
    '############################################################']

    #因为python里string不能直接改变某一元素,所以用test_map来存储搜索时的地图
    test_map = []

    #########################################################
    class Node_Elem:
        
    """
        开放列表和关闭列表的元素类型,parent用来在成功的时候回溯路径
        
    """
        
    def __init__(self, parent, x, y, dist):
            self.parent 
    = parent
            self.x 
    = x
            self.y 
    = y
            self.dist 
    = dist
            
    class A_Star:
        
    """
        A星算法实现类
        
    """
        
    #注意w,h两个参数,如果你修改了地图,需要传入一个正确值或者修改这里的默认参数
        def __init__(self, s_x, s_y, e_x, e_y, w=60, h=30):
            self.s_x 
    = s_x
            self.s_y 
    = s_y
            self.e_x 
    = e_x
            self.e_y 
    = e_y
            
            self.width 
    = w
            self.height 
    = h
            
            self.open 
    = []
            self.close 
    = []
            self.path 
    = []
            
        
    #查找路径的入口函数
        def find_path(self):
            
    #构建开始节点
            p = Node_Elem(None, self.s_x, self.s_y, 0.0)
            
    while True:
                
    #扩展F值最小的节点
                self.extend_round(p)
                
    #如果开放列表为空,则不存在路径,返回
                if not self.open:
                    
    return
                
    #获取F值最小的节点
                idx, p = self.get_best()
                
    #找到路径,生成路径,返回
                if self.is_target(p):
                    self.make_path(p)
                    
    return
                
    #把此节点压入关闭列表,并从开放列表里删除
                self.close.append(p)
                
    del self.open[idx]
                
        
    def make_path(self,p):
            
    #从结束点回溯到开始点,开始点的parent == None
            while p:
                self.path.append((p.x, p.y))
                p 
    = p.parent
            
        
    def is_target(self, i):
            
    return i.x == self.e_x and i.y == self.e_y
            
        
    def get_best(self):
            best 
    = None
            bv 
    = 1000000 #如果你修改的地图很大,可能需要修改这个值
            bi = -1
            
    for idx, i in enumerate(self.open):
                value 
    = self.get_dist(i)#获取F值
                if value < bv:#比以前的更好,即F值更小
                    best = i
                    bv 
    = value
                    bi 
    = idx
            
    return bi, best
            
        
    def get_dist(self, i):
            
    # F = G + H
            # G 为已经走过的路径长度, H为估计还要走多远
            # 这个公式就是A*算法的精华了。
            return i.dist + math.sqrt(
                (self.e_x
    -i.x)*(self.e_x-i.x)
                
    + (self.e_y-i.y)*(self.e_y-i.y))*1.2
            
        
    def extend_round(self, p):
            
    #可以从8个方向走
            xs = (-1, 0, 1-11-1, 0, 1)
            ys 
    = (-1,-1,-1,  0, 0,  111)
            
    #只能走上下左右四个方向
    #
            xs = (0, -1, 1, 0)
    #
            ys = (-1, 0, 0, 1)
            for x, y in zip(xs, ys):
                new_x, new_y 
    = x + p.x, y + p.y
                
    #无效或者不可行走区域,则勿略
                if not self.is_valid_coord(new_x, new_y):
                    
    continue
                
    #构造新的节点
                node = Node_Elem(p, new_x, new_y, p.dist+self.get_cost(
                            p.x, p.y, new_x, new_y))
                
    #新节点在关闭列表,则忽略
                if self.node_in_close(node):
                    
    continue
                i 
    = self.node_in_open(node)
                
    if i != -1:
                    
    #新节点在开放列表
                    if self.open[i].dist > node.dist:
                        
    #现在的路径到比以前到这个节点的路径更好~
                        #则使用现在的路径
                        self.open[i].parent = p
                        self.open[i].dist 
    = node.dist
                    
    continue
                self.open.append(node)
                
        
    def get_cost(self, x1, y1, x2, y2):
            
    """
            上下左右直走,代价为1.0,斜走,代价为1.4
            
    """
            
    if x1 == x2 or y1 == y2:
                
    return 1.0
            
    return 1.4
            
        
    def node_in_close(self, node):
            
    for i in self.close:
                
    if node.x == i.x and node.y == i.y:
                    
    return True
            
    return False
            
        
    def node_in_open(self, node):
            
    for i, n in enumerate(self.open):
                
    if node.x == n.x and node.y == n.y:
                    
    return i
            
    return -1
            
        
    def is_valid_coord(self, x, y):
            
    if x < 0 or x >= self.width or y < 0 or y >= self.height:
                
    return False
            
    return test_map[y][x] != '#'
        
        
    def get_searched(self):
            l 
    = []
            
    for i in self.open:
                l.append((i.x, i.y))
            
    for i in self.close:
                l.append((i.x, i.y))
            
    return l
            
    #########################################################
    def print_test_map():
        
    """
        打印搜索后的地图
        
    """
        
    for line in test_map:
            
    print ''.join(line)

    def get_start_XY():
        
    return get_symbol_XY('S')
        
    def get_end_XY():
        
    return get_symbol_XY('E')
        
    def get_symbol_XY(s):
        
    for y, line in enumerate(test_map):
            
    try:
                x 
    = line.index(s)
            
    except:
                
    continue
            
    else:
                
    break
        
    return x, y
            
    #########################################################
    def mark_path(l):
        mark_symbol(l, 
    '*')
        
    def mark_searched(l):
        mark_symbol(l, 
    ' ')
        
    def mark_symbol(l, s):
        
    for x, y in l:
            test_map[y][x] 
    = s
        
    def mark_start_end(s_x, s_y, e_x, e_y):
        test_map[s_y][s_x] 
    = 'S'
        test_map[e_y][e_x] 
    = 'E'
        
    def tm_to_test_map():
        
    for line in tm:
            test_map.append(list(line))
            
    def find_path():
        s_x, s_y 
    = get_start_XY()
        e_x, e_y 
    = get_end_XY()
        a_star 
    = A_Star(s_x, s_y, e_x, e_y)
        a_star.find_path()
        searched 
    = a_star.get_searched()
        path 
    = a_star.path
        
    #标记已搜索区域
        mark_searched(searched)
        
    #标记路径
        mark_path(path)
        
    print "path length is %d"%(len(path))
        
    print "searched squares count is %d"%(len(searched))
        
    #标记开始、结束点
        mark_start_end(s_x, s_y, e_x, e_y)
        
    if __name__ == "__main__":
        
    #把字符串转成列表
        tm_to_test_map()
        find_path()
        print_test_map()
        来源:

声明:本文由网友推荐或作者提交,版权归原作者所有,刊登此文仅为传播知识,展示研究成果,提高文章引用率。未经原作者授权,禁止用于任何形式的商业行为。科技论文网倡导尊重知识、尊重劳动、保护原创、知识共享。由于部分论文文章来于网络,文章作者不祥,请相关的原创作者与我们联系,以便加上您的署名。

  
A*算法Python实现
下面没有链接了     森德拉姆素数筛法
最新论文
·[程序设计]A*算法Python实现
·[程序设计]森德拉姆素数筛法
·[程序设计]一种快速图形拉伸算法
·[程序设计]扫描线种子填充算法
·[程序设计]C语言实现集合的交,并,差
·[程序设计]采用链式存储结构构造哈夫曼树
·[程序设计]链表反转的两种实现方法
·[程序设计]数据结构(C语言):迷宫问题
·[程序设计]"S/P先生数学谜题"算法分析及源代码
·[程序设计]单源最短路径bellman-ford算法
 
 

搜索论文

Google
论文分类

论文网 论文发表网 论文 免费论文网 找论文网 毕业论文 中国论文网 英语论文 百度论文 聘教网 易搜
 免费发布论文    中国论文网 2008版权所有  业务联系:pinjiao@126.com