讲师中心 微信公众号
AI工具推荐 视频效率加速

使用 Python 实现网格地图 A* 路径规划教程

云晨大大_6531

云晨大大_6531

发布时间:2025-11-07 11:40:41

|

1075人浏览过

|

来源于php中文网

原创

使用 Python 实现网格地图 A* 路径规划教程

本教程详细介绍了如何在 python 中实现网格地图的路径规划。利用类似广度优先搜索的策略,从起点开始,逐步将可通行节点标记为指向起点的方向。一旦到达目标点,即可通过回溯这些方向,高效地重建出从起点到目标的最优路径。文章包含示例代码,帮助读者理解并应用此寻路方法。

1. 简介与问题定义

路径规划是人工智能和计算机科学中的一个基本问题,广泛应用于游戏开发、机器人导航和物流优化等领域。本教程将重点介绍如何在二维网格地图中寻找从起点到终点的最短路径。

我们的地图表示为一个嵌套列表(即二维数组),其中包含以下几种值:

  • 0: 代表墙壁或不可通行区域。
  • 1: 代表空地或可通行区域。
  • 2, 3, 4: 代表不同类型的障碍物,但同样不可通行。
  • *: 代表路径的起点。
  • $$$: 代表路径的终点。

目标是编写一个 Python 函数,能够:

  1. 从起点开始,在地图中填充表示回溯方向的符号,直到到达终点。
  2. 从终点开始,沿着这些方向符号回溯,以重建出最短路径。
  3. 返回包含该路径的地图(路径上的节点被特殊符号标记)。

需要注意的是,尽管问题提及 A* 算法,但针对无权图(即所有可通行路径的成本相同,例如本例中每一步移动成本都视为1)寻找最短路径时,广度优先搜索(BFS)是一种简单且有效的算法,它能够保证找到最短路径。本教程将基于 BFS 的思想实现路径填充和回溯。

立即学习“Python免费学习笔记(深入)”;

python学习
python学习

Python 编程学习助手 skill,面向零基础用户。 当用户表达以下意图时触发: - 学习 Python 基础概念(变量、数据类型、循环、函数、类等) - 请求 Python 练习题或测验 - 请求审查或调试 Python 代码 - 请求 Python 项目实战指导(爬虫、数据分析、Web 开发等入门项目) - 泛化表述如"教我 Python""我想学编程""Python 怎么写""帮我学 Python" 此 skill

下载

2. 地图表示与基本设置

首先,我们定义一个示例地图和一些常量,包括起点、终点以及用于标记方向的符号。

mapList = [ # 示例地图,你可以根据需要修改
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    [0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0],
    [0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0],
    [0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 2, 2, 1, 1, 2, 2, 0, 0],
    [0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 2, 2, 1, 1, 2, 2, 0, 0],
    [0, 0, 1, 1, 2, 2, 3, 3, 1, 1, 3, 3, 1, 1, 1, 1, 1, 1, 0, 0],
    [0, 0, 1, 1, 2, 2, 3, 3, 1, 1, 3, 3, 1, 1, 1, 1, 1, 1, 0, 0],
    [0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 0, 0],
    [0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 0, 0],
    [0, 0, 2, 2, 2, 2, 1, 1, 2, 2, 3, 3, 1, 1, 1, 1, 1, 1, 0, 0],
    [0, 0, 2, 2, 2, 2, 1, 1, 2, 2, 3, 3, 1, 1, 1, 1, 1, 1, 0, 0],
    [0, 0, 1, 1, 2, 2, 1, 1, 3, 3, 1, 1, 1, 1, 1, 1, 2, 2, 0, 0],
    [0, 0, 1, 1, 2, 2, 1, 1, 3, 3, 1, 1, 1, 1, 1, 1, 2, 2, 0, 0],
    [0, 0, 1, 1, 2, 2, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 0, 0],
    [0, 0, 1, 1, 2, 2, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 0, 0],
    [0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0],
    [0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0],
    [0, 0, 1, 1, 3, 3, 3, 3, 1, 1, 1, 1, 3, 3, 1, 1, 1, 1, 0, 0],
    [0, 0, 1, 1, 3, 3, 3, 3, 1, 1, 1, 1, 3, 3, 1, 1, 1, 1, 0, 0],
    [0, 0, 1, 1, 3, 3, 3, 3, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 0, 0],
    [0, 0, 1, 1, 3, 3, 3, 3, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 0, 0],
    [0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 0, 0],
    [0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 0, 0],
    [0, 0, 1, 1, 3, 3, 3, 3, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 0, 0],
    [0, 0, 1, 1, 3, 3, 3, 3, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 0, 0],
    [0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 0, 0],
    [0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 0, 0],
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
]

# 定义起点和终点坐标及符号
sourceRow, sourceColumn = 6, 2
destinationRow, destinationColumn = 2, 15
sourceSymbol = "*"
destinationSymbol = "$$$"

# 定义方向符号
up = "^"
down = "v"
right = ">"
left = "<"

# 在地图上标记起点和终点
mapList[sourceRow][sourceColumn] = sourceSymbol
mapList[destinationRow][destinationColumn] = destinationSymbol

def print_map(map_data):
    """辅助函数:打印地图"""
    for row in map_data:
        print(" ".join(map(str, row)))
    print("-" * 40)

print("--- 初始地图 ---")
print_map(mapList)

3. 路径填充:广度优先搜索 (BFS) 策略

这一步的目标是从起点开始,向所有可通行的相邻节点扩散,并用方向符号标记这些节点。每个方向符号都指向其父节点(即扩散过程中上一步到达的节点),这样最终我们可以从终点沿着这些符号回溯到起点。

我们使用一个队列 tempList 来实现 BFS。每次从队列中取出一个点,检查其四个相邻点:

  • 如果相邻点是终点,则停止扩散。
  • 如果相邻点是可通行区域 (1),则将其标记为指向当前点的方向,并加入队列。
# 用于 BFS 队列
tempList = [(sourceRow, sourceColumn)]

def fill_with_directions(current_point: tuple, current_map: list):
    """
    从当前点开始,向四周可通行区域填充方向符号。
    方向符号指示从该点回溯到父节点(即当前点)的方向。
    """
    r, c = current_point

    # 定义四个方向的偏移量:(dr, dc)
    # (1, 0) -> 下, (-1, 0) -> 上, (0, 1) -> 右, (0, -1) -> 左
    neighbor_offsets = [(-1, 0), (1, 0), (0, -1), (0, 1)] # 上,下,左,右

    for dr, dc in neighbor_offsets:
        nr, nc = r + dr, c + dc # 相邻点的坐标

        # 检查边界
        if not (0 <= nr < len(current_map) and 0 <= nc < len(current_map[0])):
            continue

        # 如果到达终点
        if current_map[nr][nc] == destinationSymbol:
            return True # 找到终点,返回True

        # 如果相邻点是可通行区域 (1)
        if current_map[nr][nc] == 1:
            # 根据相对位置填充方向符号
            if dr == -1: # 相邻点在上方,当前点在下方,所以相邻点应指向下
                current_map[nr][nc] = down
            elif dr == 1: # 相邻点在下方,当前点在上方,所以相邻点应指向上
                current_map[nr][nc] = up
            elif dc == -1: # 相邻点在左方,当前点在右方,所以相邻点应指向右
                current_map[nr][nc] = right
            elif dc == 1: # 相邻点在右方,当前点在左方,所以相邻点应指向左
                current_map[nr][nc] = left

            # 将新填充的点加入队列,以便后续探索
            tempList.append((nr, nc))
    return False # 未找到终点

# 执行 BFS 扩散
while tempList:
    current_point = tempList.pop(0) # 取出队列中的第一个点
    if fill_with_directions(current_point, mapList):
        print("--- 填充方向后的地图 (到达终点) ---")
        print_map(mapList)
        break # 找到终点,停止扩散

4. 路径回溯与重建

当 fill_with_directions 函数返回 True 时,表示我们已经从起点扩散到了终点。此时,地图上除了起点和终点,所有路径上的可通行节点都被标记了方向符号。接下来,我们将从终点开始,沿着这些方向符号反向追踪,直到回到起点,并将路径上的节点标记为 *。

# 从终点开始回溯
current_path_point = None

# 首先找到终点周围哪个点被标记了方向,作为回溯的起点
# 定义四个方向的偏移量
neighbor_offsets = [(-1, 0), (1, 0), (0, -1), (0, 1)] # 上,下,左,右
possible_signs = [up, down, left, right]

for dr, dc in neighbor_offsets:
    nr, nc = destinationRow + dr, destinationColumn + dc
    # 检查边界
    if not (0 <= nr < len(mapList) and 0 <= nc < len(mapList[0])):
        continue

    if mapList[nr][nc] in possible_signs:
        current_path_point = (nr, nc)
        break

# 回溯并标记路径
while current_path_point:
    r, c = current_path_point
    current_item = mapList[r][c]

    # 如果回溯到起点,则停止
    if current_item == sourceSymbol:
        current_path_point = None
        break

    # 将当前点标记为路径的一部分
    mapList[r][c] = '*'

    # 根据当前点的方向符号,移动到下一个回溯点(即其父节点)
    if current_item == up: # 当前点指向父节点上方,说明父节点在当前点下方
        current_path_point = (r + 1, c)
    elif current_item == down: # 当前点指向父节点下方,说明父节点在当前点上方
        current_path_point = (r - 1, c)
    elif current_item == left: # 当前点指向父节点左方,说明父节点在当前点右方
        current_path_point = (r, c + 1)
    elif current_item == right: # 当前点指向父节点右方,说明父节点在当前点左方
        current_path_point = (r, c - 1)
    else:
        # 理论上不应该发生,除非路径断裂或遇到非方向符号的可通行区域
        print(f"Error: Encountered unexpected item {current_item} at {current_path_point}")
        break

print("--- 最终路径地图 ---")
print_map(mapList)

5. 完整函数封装

为了方便使用,我们可以将上述逻辑封装到一个函数中。

def find_path_in_map(initial_map: list, start_coords: tuple, end_coords: tuple):
    """
    在网格地图中寻找从起点到终点的最短路径。

    Args:
        initial_map (list): 嵌套列表表示的地图。
                            0: 墙壁, 1: 可通行, 2/3/4: 障碍物。
        start_coords (tuple): 起点坐标 (row, column)。
        end_coords (tuple): 终点坐标 (row, column)。

    Returns:
        list: 包含标记路径的地图,如果找不到路径则返回None。
    """
    # 创建地图的深拷贝,避免修改原始地图
    current_map = [row[:] for row in initial_map]

    sourceRow, sourceColumn = start_coords
    destinationRow, destinationColumn = end

热门AI工具

更多
二狗PPT
二狗PPT Hot

一款AI演示文稿工具,主要用于专为中式职场打造的AI PPT生成工具,适合需要提升相关任务效率的用户。

立刻MV
立刻MV Hot

立刻MV是一款AI文本写作工具,AI 音乐视频(MV)创作工具。

WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

UpDream
UpDream Hot

一款AI视频创作工具,主要用于哔哩哔哩推出的自研AI视频创作工具,适合需要提升相关任务效率的用户。

讯飞智作

讯飞智作是一款AI视频创作工具,AI文本配音工具,数字人课程、营销视频制作。

Seko
Seko Hot

一款AI视频创作工具,主要用于商汤科技推出的创编一体的AI短视频创作Agent,适合需要提升相关任务效率的用户。

讯飞绘文

讯飞绘文是一款由科大讯飞推出的一站式 AIGC 内容运营平台。

相关专题

更多
java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

6164

2023.10.24

页面置换算法
页面置换算法

页面置换算法是操作系统中用来决定在内存中哪些页面应该被换出以便为新的页面提供空间的算法。本专题为大家提供页面置换算法的相关文章,大家可以免费体验。

6236

2023.08.14

Gradle插件开发入门教程
Gradle插件开发入门教程

本专题介绍Gradle插件开发的基本流程,涵盖插件类编写、自定义任务注册、扩展参数设计和插件应用方法,帮助你理解插件如何组织构建逻辑,减少多个项目之间的重复配置。

60

2026.10.22

Gradle Wrapper配置教程
Gradle Wrapper配置教程

本专题介绍Gradle Wrapper的基本作用,涵盖文件组成、生成方法、版本配置和任务调用,帮助你理解项目如何使用指定的Gradle版本,减少不同开发环境带来的构建差异。

40

2026.10.22

Golangci-lint检查器使用教程
Golangci-lint检查器使用教程

本专题整理Golangci-lint常用Linters的用途与配置方法,覆盖错误处理、无效代码、安全、复杂度、命名和依赖检查,帮助项目合理选规则。

40

2026.10.22

Gradle怎么构建Java项目
Gradle怎么构建Java项目

本专题介绍Gradle Java项目构建方法,涵盖Java插件配置、依赖声明、源码编译、测试执行和打包检查,帮助你理解各阶段的任务关系,逐步完成项目构建。

20

2026.10.22

PHP时间戳漏洞修复教程
PHP时间戳漏洞修复教程

本专题汇总PHP常见时间戳漏洞,包括2038年溢出、时区漂移、时间戳伪造、重放攻击、时间盲注与日志审计失效等,并给出升级64位环境、使用 DateTimeImmutable、统一UTC、严格超时校验、预处理绑定、hash_equals 比对等修复方案,帮助开发者快速排查和加固时间相关代码。

40

2026.10.22

Golangci-lint配置文件与规则设置
Golangci-lint配置文件与规则设置

本专题聚焦Golangci-lint YAML配置文件,讲清运行参数、规则启停、目录排除、问题过滤及严重级别设置,便于团队统一检查标准。

20

2026.10.22

Golangci-lint安装与入门教程
Golangci-lint安装与入门教程

本专题讲解Golangci-lint的安装、初始化、基础命令和首次代码检查,覆盖本地环境、Docker及多平台用法,帮助Go开发者快速上手。

20

2026.10.22

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Uvicorn官方安装与入门手册
Uvicorn官方安装与入门手册

共0课时 | 0人学习

Python uv官方项目管理指南
Python uv官方项目管理指南

共0课时 | 0人学习

Python uv官方安装与入门文档
Python uv官方安装与入门文档

共0课时 | 0人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn