A*:python实现A星寻路算法可视化

A星寻路算法可视化

效果

确定起点终点,画障碍,空格启动
红色是探索过的,绿色是当前可探索的。
在这里插入图片描述

算法流程

先介绍几个概念

名词解释
open列表可探索的方块
closed列表已探索的方块
方块分数FF = G + H
G从起点到当前点的距离
H自己定义的当前点到终点的距离
邻接节点本例中指上下左右4个节点

我对H的理解是这样的:
H就相当于机器学习里的正则化惩罚,就是一个限制,可以自己确定,比如使用曼哈顿距离或者欧式距离,添加这个的目的是为了使寻路的方向向终点靠拢。(感谢舍友指点)

流程:

  1. 将起点添加到open列表中
  2. 从open列表中寻找F最小的节点,称为current。若current是终点,则停止。将current从open列表移除,然后添加current到closed列表中。
  3. 对于与current的每一个邻接节点neighbor:
    . 如果neighbor在closed列表中:pass
    . 如果neighbor不在open列表中:添加neighbor到open列表然后计算它的F
    . 如果neighbor已经在open列表中:当我们使用当前生成的路径到达那里时,(这一步相当于dijkstra)检查F是否更小。如果是,更新它的F和它的前继
  4. 回到 2

代码

import pygame
import sys
import math
from tkinter import *
from tkinter import ttk
from tkinter import messagebox
import os

screen = pygame.display.set_mode((800,800))

class spot:
    def __init__(self,x,y):
        #坐标
        self.i = x
        self.j = y
        #分数
        self.f = 0
        self.g = 0
        self.h = 0
        #父节点
        self.previous = None
        #是不是障碍
        self.obs = False
        #选择状态
        self.closed = False
        #权
        self.value = 1
        #相邻节点
        self.neighbors = []

    def show(self,color,st):
        if self.closed == False:
            pygame.draw.rect(screen,color,(self.i*w,self.j*h,w,h),st)
            pygame.display.update()
    
    def path(self,color,st):
            pygame.draw.rect(screen,color,(self.i*w,self.j*h,w,h),st)
            pygame.display.update()

    def addNeighbors(self):
        i = self.i
        j = self.j
        if i < rows-1 and grid[i+1][j].obs == False:
            self.neighbors.append(grid[i+1][j])
        if i > 0 and grid[i-1][j].obs == False:
            self.neighbors.append(grid[i-1][j])
        if j < cols-1 and grid[i][j+1].obs == False:
            self.neighbors.append(grid[i][j+1])
        if j > 0 and grid[i][j-1].obs == False:
            self.neighbors.append(grid[i][j-1])

#行列数
cols = 50
rows = 50



#颜色
red = (255,0,0)
green = (0,255,0)
blue = (0,0,255)
grey = (220,220,220)

#格子长宽
w = 800/cols
h = 800/rows

#父节点列表
cameFrom = []

#创建节点
grid = [0 for i in range(cols)]
for i in range(cols):
    grid[i] = [0 for i in range(rows)]

for i in range(rows):
    for j in range(cols):
        grid[i][j] = spot(i,j)

#默认起点、终点
start = grid[5][5]
end = grid[7][19]



#画界面
for i in range(rows):
    for j in range(cols):
        grid[i][j].show((255,255,255),1)

#画围墙 
for i in range(rows):
    grid[i][0].show(grey,0)
    grid[i][cols-1].show(grey,0)
    grid[0][i].show(grey,0)
    grid[cols-1][i].show(grey,0)
    grid[i][0].show(grey,0)
    grid[i][cols-1].show(grey,0)
    grid[0][i].show(grey,0)
    grid[cols-1][i].show(grey,0)
    grid[i][0].obs = True
    grid[i][cols-1].obs = True
    grid[0][i].obs = True
    grid[cols-1][i].obs = True
    grid[i][0].obs = True
    grid[i][cols-1].obs = True
    grid[0][i].obs = True
    grid[cols-1][i].obs = True

def onsubmit():
    global start
    global end
    st = startBox.get().split(',')
    ed = endBox.get().split(',')
    start = grid[int(st[0])][int(st[1])]
    end = grid[int(ed[0])][int(ed[1])]
    window.quit()
    window.destroy()

#输入界面
window = Tk()
window.title('请输入')
label_1 = Label(window,text = '起点坐标(x,y): ')
startBox = Entry(window)
label_2 = Label(window,text = '终点坐标(x,y): ')
endBox = Entry(window)
var = IntVar()
showPath = ttk.Checkbutton(window,text = '显示每一步',onvalue=1,offvalue=0,variable=var)
submit = Button(window,text='提交',command=onsubmit)

#布局
label_1.grid(row = 0,column = 0,pady = 3)
label_2.grid(row = 1,column = 0,pady = 3)
startBox.grid(row = 0,column = 1,pady = 3)
endBox.grid(row = 1,column = 1,pady = 3)
showPath.grid(columnspan = 2,row = 2)
submit.grid(columnspan = 2,row = 3)

#启动输入界面
mainloop()

#两个表
openSet = [start]
closeSet = []

#显示起点终点
start.show((255,8,127),0)
end.show((255,8,127),0)

#监听鼠标位置
def mousePress(x):
    t = x[0]
    w = x[1]
    #判断在第几个格子
    g1 = t//(800//cols)
    g2 = w//(800//rows)
    #设置障碍
    set_obs = grid[g1][g2]
    if set_obs != start and set_obs!= end:
        set_obs.obs = True
        set_obs.show(grey,0)

#画障碍
loop = True
while loop:
    ev = pygame.event.poll()
    if pygame.mouse.get_pressed()[0]:
        try:
            pos = pygame.mouse.get_pos()
            mousePress(pos)
        except AttributeError:
            pass
    if ev.type == pygame.QUIT:
        pygame.quit()
    elif ev.type == pygame.KEYDOWN:
        if ev.key == pygame.K_SPACE:
            loop = False

#画好障碍后,初始邻接节点列表
for i in range(rows):
    for j in range(cols):
        grid[i][j].addNeighbors()

#启发式方法
def heurisitic(n,e):
    d = math.sqrt((n.i - e.i)**2 + (n.j - e.j)**2)
    return d

def main():
    #openSet初始化时已经包含起点
    #从中选择f分数最小的
    if(len(openSet) > 0):
        lowestIndex = 0
        for i in range(len(openSet)):
            if(openSet[i].f < openSet[lowestIndex].f):
                lowestIndex = i
    
    #对当前节点操作
        current = openSet[lowestIndex]
        #找到 打印路径
        if current == end:
            temp = current.f
            while current != start:
                current.closed = False
                current.show(blue, 0)
                current = current.previous
            end.show(red, 0)

            Tk().wm_withdraw()
            result = messagebox.askokcancel('Program Finished', ('The program finished, the shortest distance \n to the path is ' + str(temp) + ' blocks away, \n would you like to re run the program?'))
            if result == True:
                os.execl(sys.executable,sys.executable, *sys.argv)
            else:
                ag = True
                while ag:
                    ev = pygame.event.get()
                    for event in ev:
                        if event.type == pygame.KEYDOWN:
                            ag = False
                            break
            pygame.quit()
    
        openSet.pop(lowestIndex)
        closeSet.append(current)

        neighbors = current.neighbors
        for i in range(len(neighbors)):
            neighbor = neighbors[i]
            if neighbor not in closeSet:
                tmpG = current.g + current.value
                if neighbor in openSet:
                    if neighbor.g > tmpG:
                        neighbor.g = tmpG
                        neighbor.previous = current
                else:
                    neighbor.g = tmpG
                    openSet.append(neighbor)
                    neighbor.previous = current

            neighbor.h = heurisitic(neighbor,end)
            neighbor.f = neighbor.g + neighbor.h

    if var.get():
        for i in range(len(openSet)):
            openSet[i].show(green,0)
        
        for i in range(len(closeSet)):
            if closeSet[i] != start:
                closeSet[i].show(red,0)
    current.closed = True
    


while True:
    ev = pygame.event.poll()
    if ev.type == pygame.QUIT:
        pygame.quit()
    main()

在这里插入图片描述

  • 8
    点赞
  • 87
    收藏
    觉得还不错? 一键收藏
  • 10
    评论
### 回答1: Python代码实现A寻路算法可以使用以下代码:def astar(start, goal): closedset = set() openset = set([start]) came_from = {} gscore = {start: 0} fscore = {start: heuristic_cost_estimate(start, goal)} while openset: current = min(openset, key=fscore.get) if current == goal: return reconstruct_path(came_from, current) openset.remove(current) closedset.add(current) for neighbor in get_neighbors(current): if neighbor in closedset: continue tentative_gscore = gscore[current] + dist_between(current, neighbor) if neighbor not in openset: openset.add(neighbor) elif tentative_gscore >= gscore[neighbor]: continue came_from[neighbor] = current gscore[neighbor] = tentative_gscore fscore[neighbor] = gscore[neighbor] + heuristic_cost_estimate(neighbor, goal) return False ### 回答2: A寻路算法是一种常用的路径规划算法,可以在给定的地图中找到最短路径。下面是用Python实现A寻路算法的代码示例: ```python import heapq # 定义节点类 class Node: def __init__(self, row, col, g, h): self.row = row self.col = col self.g = g self.h = h def __lt__(self, other): return self.g + self.h < other.g + other.h # 计算启发式代价(h值) def heuristic(row, col, target_row, target_col): return abs(target_row - row) + abs(target_col - col) # A寻路算法 def astar_search(start, target, grid): directions = [(-1, 0), (1, 0), (0, -1), (0, 1)] # 上下左右四个方向 rows, cols = len(grid), len(grid[0]) visited = set() # 已访问的节点集合 pq = [] # 优先队列,用来选择下一个节点 heapq.heappush(pq, start) while pq: curr_node = heapq.heappop(pq) row, col = curr_node.row, curr_node.col visited.add((row, col)) if row == target.row and col == target.col: return curr_node.g for d in directions: new_row, new_col = row + d[0], col + d[1] if 0 <= new_row < rows and 0 <= new_col < cols and grid[new_row][new_col] != 1: new_g = curr_node.g + 1 new_h = heuristic(new_row, new_col, target.row, target.col) new_node = Node(new_row, new_col, new_g, new_h) if (new_row, new_col) not in visited: heapq.heappush(pq, new_node) return -1 # 示例 grid = [[0, 0, 0], [1, 1, 0], [0, 0, 0]] start = Node(0, 0, 0, 0) target = Node(2, 2, 0, 0) result = astar_search(start, target, grid) print(result) ``` 以上代码实现了A寻路算法,并可用于寻找给定地图中起点到目标点的最短路径。其中,`grid`是二维列表表示地图,在地图中,0表示可通过的节点,1表示不可通过的节点。`start`表示起点,`target`表示目标点。通过调用`astar_search`函数,将起点、目标点和地图作为参数进行传递,即可得到最短路径的长度。 ### 回答3: A寻路算法是一种常用于寻找最短路径的算法,广泛应用于游戏开发、路径规划等领域。下面是使用Python实现A寻路算法的代码: ```python # 定义地图和起终点 map = [ [0, 0, 0, 0, 0, 0, 0], [0, 1, 1, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0, 0], [0, 0, 1, 1, 1, 1, 0], [0, 0, 0, 0, 0, 1, 0], [0, 0, 0, 0, 0, 1, 0], [0, 0, 0, 0, 0, 0, 0] ] start = (1, 1) # 起点坐标 goal = (6, 5) # 终点坐标 # 定义辅助函数 def heuristic(pos1, pos2): # 估算两点之间的距离(启发函数) x1, y1 = pos1 x2, y2 = pos2 return abs(x1 - x2) + abs(y1 - y2) def get_neighbors(pos): # 获取当前位置的邻近位置 x, y = pos neighbors = [] for dx in [-1, 0, 1]: for dy in [-1, 0, 1]: if dx == dy == 0: # 排除当前位置 continue new_x, new_y = x + dx, y + dy if 0 <= new_x < len(map) and 0 <= new_y < len(map[0]) and map[new_x][new_y] == 0: neighbors.append((new_x, new_y)) return neighbors # 定义A算法函数 def astar_search(start, goal): # 初始化起点和终点 open_list = [start] # 待探索的节点 came_from = {} # 记录路径中每个节点的上一个节点 g_score = {start: 0} # 起点到每个节点的实际代价 f_score = {start: heuristic(start, goal)} # 起点到每个节点的估算代价(f_score = g_score + h_score) while open_list: current = min(open_list, key=lambda x: f_score[x]) # 获取f_score最小的节点 if current == goal: # 已到达终点 path = [] while current in came_from: path.append(current) current = came_from[current] path.append(start) path.reverse() return path open_list.remove(current) for neighbor in get_neighbors(current): g_temp = g_score[current] + 1 # 节点到邻近节点的代价为1 if neighbor not in g_score or g_temp < g_score[neighbor]: came_from[neighbor] = current g_score[neighbor] = g_temp f_score[neighbor] = g_temp + heuristic(neighbor, goal) if neighbor not in open_list: open_list.append(neighbor) return [] # 未找到路径 # 在地图上运行A算法 path = astar_search(start, goal) print("路径: ", path) ``` 该代码首先定义了一个地图,使用0表示可行走的区域,使用1表示障碍物。将起点和终点设定好后,通过`heuristic`函数计算两点间的估算距离。`get_neighbors`函数用于获取当前位置的邻近位置。 `astar_search`函数是实现A算法的核心部分。其中,`open_list`用于存放待探索的节点,`came_from`用于记录路径中每个节点的上一个节点,`g_score`用于记录起点到每个节点的实际代价,`f_score`用于记录起点到每个节点的估算代价。算法使用一个循环不断探索下一个最有可能的节点,直到找到终点或无法找到路径为止。 最后,在地图上运行A算法,并输出结果路径。
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值