• Python3 A*寻路算法实现


    # -*- coding: utf-8 -*-
    import math
    import random
    import copy
    import time
    import sys
    import tkinter
    import threading
    
    # 地图
    tm = [
    '############################################################',
    '#S............................#............#.....#.........#',
    '#..........#..................#......#.....#.....#.........#',
    '#..........#..................#......#.....#.....#.........#',
    '#..........#..................#......#.....#.....#.........#',
    '#..........#.........................#.....#.....#.........#',
    '#..........#..................#......#.....#...............#',
    '#..#########..................#......#.....#.....#.........#',
    '#..#..........................#......#.....#.....#.........#',
    '#..#..........................#......#.....#.....#.........#',
    '#..############################......#.....#.....#.........#',
    '#.............................#......#.....#.....#.........#',
    '#.............................#......#...........#.........#',
    '#######.##################################################.#',
    '#....#........#.................#.............#............#',
    '#....#........#........#........#.............#............#',
    '#....####.#####........#........#.............#............#',
    '#.........#............#........#.............#............#',
    '#.........#............#........#.............#............#',
    '#.........#............#........#.............#............#',
    '#.........#............#........#.............#............#',
    '#.........#............#........#.............#............#',
    '#.........#............#........####.#######.##............#',
    '#.........#............#........#....#.......#.............#',
    '#.........#............#........#....#.......#.............#',
    '#......................#........#....#.......#.............#',
    '#.........#............#........##.########..#.............#',
    '#.........#............#..................#..########.######',
    '#.........#............#..................#...............E#',
    '############################################################']
    
    # 存储搜索时的地图
    test_map = []
    
    
    #----------- 开放列表和关闭列表的元素类型,parent用来在成功的时候回溯路径 -----------
    class Node_Elem:
    
        def __init__(self, parent, x, y, dist):
            self.parent = parent  # 回溯父节点
            self.x = x  # x坐标
            self.y = y  # y坐标
            self.dist = dist  # 从起点到此位置的实际距离
    
    
    #----------- A*算法 -----------
    class A_Star:
        
        def __init__(self, root, s_x, s_y, e_x, e_y, w=60, h=30):
    
            self.s_x = s_x  # 起点x
            self.s_y = s_y  # 起点y
            self.e_x = e_x  # 终点x
            self.e_y = e_y  # 终点y
            
            self.open = []  # open表
            self.close = []  # close表
            self.path = []  # path表
    
            # 创建画布
            self.root = root  # 画布根节点
            self.width = w  # 地图w,默认60
            self.height = h  # 地图h,默认30
            self.__r = 3  # 半径
            # Tkinter.Canvas
            self.canvas = tkinter.Canvas(
                    root,
                    width=self.width * 10 + 100,
                    height=self.height * 10 + 100,
                    bg="#EBEBEB",  # 背景白色 
                    xscrollincrement=1,
                    yscrollincrement=1
                )
            self.canvas.pack(expand=tkinter.YES, fill=tkinter.BOTH)
            self.title("A*迷宫算法(e:开始搜索或退出)")
            self.__bindEvents()
            self.new()
    
        # 按键响应程序
        def __bindEvents(self):
    
            self.root.bind("e", self.quite)  # 退出程序
    
        # 退出程序
        def quite(self, evt):
            self.root.destroy()
    
        # 更改标题
        def title(self, s):
            self.root.title(s)
    
        # 初始化
        def new(self):
    
            node = self.canvas.create_oval(100 - self.__r,
                                20 - self.__r, 100 + self.__r, 20 + self.__r,
                                fill="#ff0000",
                                outline="#ffffff",
                                tags="node",
                            )
            self.canvas.create_text(130, 20,
                                text=u'Wall',
                                fill='black'
                            )
            node = self.canvas.create_oval(200 - self.__r,
                                20 - self.__r, 200 + self.__r, 20 + self.__r,
                                fill="#00ff00",
                                outline="#ffffff",
                                tags="node",
                            )
            self.canvas.create_text(230, 20,
                                text=u'Path',
                                fill='black'
                            )
            node = self.canvas.create_oval(300 - self.__r,
                                20 - self.__r, 300 + self.__r, 20 + self.__r,
                                fill="#AAAAAA",
                                outline="#ffffff",
                                tags="node",
                            )
            self.canvas.create_text(330, 20,
                                text=u'Searched',
                                fill='black'
                            )
    
            for i in range(self.width):
                for j in range(self.height):
                    # 生成障碍节点,半径为self.__r
                    if test_map[j][i] == '#':
                        node = self.canvas.create_oval(i * 10 + 50 - self.__r,
                                j * 10 + 50 - self.__r, i * 10 + 50 + self.__r, j * 10 + 50 + self.__r,
                                fill="#ff0000",  # 填充红色
                                outline="#ffffff",  # 轮廓白色
                                tags="node",
                            )
                    # 显示起点
                    if test_map[j][i] == 'S':
                        node = self.canvas.create_oval(i * 10 + 50 - self.__r,
                                j * 10 + 50 - self.__r, i * 10 + 50 + self.__r, j * 10 + 50 + self.__r,
                                fill="#00ff00",  # 填充绿色
                                outline="#ffffff",  # 轮廓白色
                                tags="node",
                            )
                        self.canvas.create_text(i * 10 + 50, j * 10 + 50 - 20,  # 使用create_text方法在坐标处绘制文字  
                                text=u'Start',  # 所绘制文字的内容  
                                fill='black'  # 所绘制文字的颜色为灰色
                            )
                    # 显示终点
                    if test_map[j][i] == 'E':
                        node = self.canvas.create_oval(i * 10 + 50 - self.__r,
                                j * 10 + 50 - self.__r, i * 10 + 50 + self.__r, j * 10 + 50 + self.__r,
                                fill="#00ff00",  # 填充绿色
                                outline="#ffffff",  # 轮廓白色
                                tags="node",
                            )
                        self.canvas.create_text(i * 10 + 50, j * 10 + 50 + 20,  # 使用create_text方法在坐标处绘制文字  
                                text=u'End',  # 所绘制文字的内容  
                                fill='black'  # 所绘制文字的颜色为灰色
                            )
                    # 生成路径节点,半径为self.__r
                    if test_map[j][i] == '*':
                        node = self.canvas.create_oval(i * 10 + 50 - self.__r,
                                j * 10 + 50 - self.__r, i * 10 + 50 + self.__r, j * 10 + 50 + self.__r,
                                fill="#0000ff",  # 填充蓝色
                                outline="#ffffff",  # 轮廓白色
                                tags="node",
                            )
                    # 生成搜索区域,半径为self.__r
                    if test_map[j][i] == ' ':
                        node = self.canvas.create_oval(i * 10 + 50 - self.__r,
                                j * 10 + 50 - self.__r, i * 10 + 50 + self.__r, j * 10 + 50 + self.__r,
                                fill="#AAAAAA",  # 填充白色
                                outline="#ffffff",  # 轮廓白色
                                tags="node",
                            )
            
        # 查找路径的入口函数
        def find_path(self):
            # 构建开始节点
            p = Node_Elem(None, self.s_x, self.s_y, 0.0)
            while True:
                # 扩展节点
                self.extend_round(p)
                # 如果open表为空,则不存在路径,返回
                if not self.open:
                    return
                # 取F值最小的节点
                idx, p = self.get_best()
                # 到达终点,生成路径,返回
                if self.is_target(p):
                    self.make_path(p)
                    return
                # 把此节点加入close表,并从open表里删除
                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
    
        # 取F值最小的节点
        def get_best(self):
            best = None
            bv = 10000000  # MAX值
            bi = -1
            for idx, i in enumerate(self.open):
                value = self.get_dist(i)
                if value < bv:
                    best = i
                    bv = value
                    bi = idx
            return bi, best
            
        # 求距离
        def get_dist(self, i):
            # F = G + H
            # G 为当前路径长度,H为估计长度
            return i.dist + math.sqrt((self.e_x - i.x) * (self.e_x - i.x)) + math.sqrt((self.e_y - i.y) * (self.e_y - i.y))
    
        # 扩展节点
        def extend_round(self, p):
            # 八个方向移动
            xs = (-1, 0, 1, -1, 1, -1, 0, 1)
            ys = (-1, -1, -1, 0, 0, 1, 1, 1)
            # 上下左右四个方向移动
            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)
                # 新节点在open表
                if i != -1:
                    # 当前路径距离更短
                    if self.open[i].dist > node.dist:
                        # 更新距离
                        self.open[i].parent = p
                        self.open[i].dist = node.dist
                    continue
                # 否则加入open表
                self.open.append(node)
    
        # 移动距离,直走1.0,斜走1.4
        def get_cost(self, x1, y1, x2, y2):
            if x1 == x2 or y1 == y2:
                return 1.0
            return 1.4
        
        # 检查节点是否在close表
        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
        
        # 检查节点是否在open表,返回序号  
        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 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*算法
        a_star = A_Star(tkinter.Tk(), s_x, s_y, e_x, e_y)
        a_star.root.mainloop()
        a_star.find_path()
        searched = a_star.get_searched()
        path = a_star.path
        # 标记已搜索过的位置
        mark_searched(searched)
        # 标记路径位置 
        mark_path(path)
        # 标记起点和终点
        mark_start_end(s_x, s_y, e_x, e_y)
        print(u"路径长度:%d" % (len(path)))
        print(u"搜索过的区域:%d" % (len(searched)))
        a_star = A_Star(tkinter.Tk(), s_x, s_y, e_x, e_y)
        a_star.root.mainloop()
        
    #----------- 程序的入口处 -----------
    
                    
    if __name__ == '__main__':
    
        print (u""" 
    --------------------------------------------------------
        程序:A*迷宫问题程序 
        作者:Gm
        日期:2019-7-08
        语言:Python 3.7 
    -------------------------------------------------------- 
        """)
        # 载入地图
        tm_to_test_map()
        # 寻找路径
        find_path()
    
    

    在这里插入图片描述

  • 相关阅读:
    fscanf_s与scanf_s的宽度参数与缓冲区参数分析
    C语言小程序——推箱子(窄字符和宽字符)
    setlocale()函数详解——C语言
    在源文件(.c)和头文件(.h)中声明和定义的区别——C语言
    枚举类型enum详解——C语言
    宽字符————_T、_TEXT、L、TEXT之间的区别
    宽字符wchar_t和窄字符char——putwchar、wprintf
    extern的使用详解(多文件编程)——C语言
    编程的时候命名词穷了怎么办
    [C#/UI] 使用 await 实现业务对 UI 的控制反转
  • 原文地址:https://www.cnblogs.com/gmhappy/p/11863943.html
Copyright © 2020-2023  润新知