A星寻路算法,附python源码

小时候我们都玩过推箱子,把箱子从一个点推到指定地点,碰到墙的时候就推不动了,这个游戏大家小时候肯定玩的不亦乐乎,废了不少功夫一关一关的过,其实这个游戏用代码实现还是很简单的,今天就给大家讲讲A星寻路算法,A星寻路算法是一种用于寻找有效路径的算法。

在这里插入图片描述
A星寻路算法需要两个列表和一个公式:

open_list——可到达的格子
close_list——已走过的格子

公式:
F = G + H

每一个格子都具有F,G,H这3个属性,如图
在这里插入图片描述

G: 从起点走到当前格子一共走了几步
H: 在不考虑障碍的情况下,从当前格子走到目标格子需要的步数
F:综合权重,G和H的相加的值,F = G+H

假设我们有一个7*5大小的迷宫,从绿色点走到红色点,黑色为墙壁,每一步只能上,下,左,右移动一格,如图:
在这里插入图片描述
怎么才能从绿点走到黄点呢,其实并不难:(grid:格子)
1.把起点放入open_list列表中,open_list:grid(1,2) ,close_list:
2.起点直接放在open_list中,这时open_list只有这一个点,然后把起点移除open_list,放入close_list中,代表这个格子检查过了。
3.找出当前方格,上,下,左,右所有可到达的格子,看他们是否在open_list和close_list当中,如果不在,则将他们加入open_list中,计算相应的G,H,F值,并把所在的格子作为父节点。(父节点用来记录上一个格子的位置,在输出最终路线会用到)

open_list:grid(1,1),grid(0,2),grid(2,2),grid(1,3)
close_list:grid(1,2)
在这里插入图片描述

5.找出open_list中F值最小的方格,即方格grid(2,2),F值为4,将它作为当前方格,并把当前方格移除open_list,放入close_list,代表这个格子检查过了。剩下的就是以前面的方式继续迭代,直到open_list中出现终点为止,寻路算法就结束了,我们只要顺着终点方格找到它的父亲,在找到父亲的父亲,如此回溯,就找到一条最佳路径。

主要思路:

1.初始化迷宫地图
2.设置其实点和终点
3.path列表记录走过路径的点
4.使用查找终点方法找到终点,然后回溯路径,用path添加当前路径
5.一个写了5个方法和一个节点类实现:查找终点方法,找F值最小格子的方法,找领近格子方法,验证是否越界墙壁方法,验证走过格子方法

代码如下:

扫描二维码关注公众号,回复: 13045729 查看本文章
def a_star_search(start, end):
    """
    寻路方法,找到终点返回终点grid,否则返回None
    :param start:
    :param end:
    :return:
    """

    #待访问的格子
    open_list = []
    #已访问的格子
    close_list = []
    #把起点加入open_list中
    open_list.append(start)
    #主循环,每一轮检查一个当前方格节点
    while len(open_list) > 0:
        #在open_list中查找F值最小的节点作为当前方格节点
        current_grid = find_min_gird(open_list)
        #将F值最小的节点从open_list中删除
        open_list.remove(current_grid)
        ##将F值最小的节点加入到close_list中
        close_list.append(current_grid)
        #找到当前节点的所有领近节点
        neighbors = find_neighbors(current_grid, open_list, close_list)
        for grid in neighbors:
            if grid not in open_list:
                #如果当前节点不在open_list中,标记为父节点,并放入open_list中
                grid.init_grid(current_grid, end)
                open_list.append(grid)
            #如果终点在open_list中,直接返回终点格子
            for grid in open_list:
                if (grid.x == end.x) and (grid.y == end.y):
                    return grid
        #遍历完open_list,仍然找不到终点,说明还没到终点,返回空
    return None


def find_min_gird(open_list=[]):
    """
    寻找F值最小的格子的方法
    :param open_list:
    :return:
    """
    temp_grid = open_list[0]
    for grid in open_list:
        if grid.f < temp_grid.f:
            temp_grid = grid
    return temp_grid


def find_neighbors(grid,open_list=[],close_list=[]):
    """
    寻找当前格子领近格子的方法
    :param grid:
    :param open_list:
    :param close_list:
    :return:
    """
    grid_list = []
    if is_valid_grid(grid.x,grid.y-1,open_list,close_list):
        grid_list.append(Grid(grid.x,grid.y-1))
    if is_valid_grid(grid.x,grid.y+1,open_list,close_list):
        grid_list.append(Grid(grid.x,grid.y+1))
    if is_valid_grid(grid.x-1,grid.y,open_list,close_list):
        grid_list.append(Grid(grid.x-1,grid.y))
    if is_valid_grid(grid.x+1,grid.y,open_list,close_list):
        grid_list.append(Grid(grid.x+1,grid.y))
    return grid_list


def is_valid_grid(x,y,open_list=[],close_list=[]):
    """
    判断是否越界和障碍物方法
    :param x:
    :param y:
    :param open_list:
    :param close_list:
    :return:
    """
    #判断是否越界
    if x < 0 or x >=len(MAZE) or y < 0 or y >= len(MAZE[0]):
        return False
    #判断是否有障碍物
    if MAZE[x][y] == 1:
        return False
    #是否已经在open_list中
    if contain_grid(open_list,x,y):
        return False
    # 是否已经在close_list中
    if contain_grid(close_list,x,y):
        return False
    return True


def contain_grid(grids, x, y):
    for grid in grids:
        if (grid.x == x) and (grid.y == y):
            return True
    return False


class Grid:
    def __init__(self, x, y):
        self.x = x
        self.y = y
        self.f = 0
        self.g = 0
        self.h = 0
        self.parent = None

    def init_grid(self, parent, end):
        self.parent = parent
        if parent is not None:
            self.g = parent.g + 1
        else:
            self.g = 1
        self.h = abs(self.x - end.x) + abs(self.y - end.y)
        self.f = self.g + self.h


#迷宫地图
MAZE = [
    [0,0,0,0,0,0,0],
    [0,0,0,1,0,0,0],
    [0,0,0,1,0,0,0],
    [0,0,0,1,0,0,0],
    [0,0,0,0,0,0,0],
]

#设置起始点和终点
start_grid = Grid(2, 1)
end_grid = Grid(2, 5)
#搜索迷宫终点
result_grid = a_star_search(start_grid, end_grid)
#回溯迷宫路径
path = []
while result_grid is not None:
    path.append(Grid(result_grid.x, result_grid.y))
    result_grid = result_grid.parent
#输出迷宫和路径,路径用*号表示
for i in range(0,len(MAZE)):
    for j in range(0,len(MAZE[0])):
        if contain_grid(path, i, j):
            print("*, ", end='')
        else:
            print(str(MAZE[i][j]) + ", ", end='')
    print()

结果图:
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_43697214/article/details/108710027