当前位置: 首页 > article >正文

A* 算法学习

在游戏中有一个很常见地需求就是要让一个角色从A点走向B点我们期望是让角色走最少的路。嗯大家可能会说直线就是最短的。没错但大多数时候A到B中间都会出现一些角色无法穿越的东西比如墙、坑等障碍物。这个时候怎么办呢是的我们需要有一个算法来解决这个问题算法的目标就是计算出两点之间的最短路径而且要能避开障碍物。1. A*简介A算法是启发式算法重要的一种主要是用于在两点之间选择一个最优路径而A的实现也是通过一个估值函数。2. FGHG表示该点到起始点位所需要的代价H表示该点到终点的曼哈顿距离。F就是G和H的总和而最优路径也就是选择最小的F值进行下一步移动后边会做详细介绍3. 曼哈顿距离上图中这个熊到树叶的曼哈顿距离就是蓝色线所表示的距离这其中不考虑障碍物假如上图每一个方格长度为1那么此时的熊的曼哈顿距离就为9。起点 (X1, Y1)终点 (X2, Y2)H|X2-X1||Y2-Y1|我们也可以通过几何坐标点来算出曼哈顿距离还是以上图为例左下角为(0, 0)点熊的位置为(1, 4)树叶的位置为(7, 1)那么H|7-1||1-4|9。4. 算法流程A算法现在被广泛应用与电脑游戏中的路径规划问题。我们就以此为例来介绍A算法的具体实施步骤。如下图所示其中A表示起点B表示终点黑色的实心方块表示障碍物。此外我们假设水平或垂直方向上相邻的两个方块之间距离是10那么对角线方向上相邻的两个方块距离就约是14。算法开始我们首先搜索A相邻的所有可能的移动位置对应于图中的绿色方块。每个方块左上角的值G表示该点到A的距离右上角值为H注意H不能大于该点到B的距离所以这里的H就取其到B的距离。最后还要计算一个F值FHG。然后像Dijkstra算法一样我们选一个F值最小的节点来做继续搜索。也就是上图中A的邻域中位于左上角的值F42。然后更新该节点的领域值。这时你会发现出现了三个F值都等于48的节点。到底应该选择哪一个来继续接下来的搜索呢这时需要考察它们中的那个H值最小结果发现H24是最小的所以下面就要从该点出发继续搜索。于是更新该节点的邻域方块中的值。这个时候再找出全局F值最小的点结果发现有两个为48而且它们的H值也相当于是随机选取一个作为新的出发点并更新其邻域值例如选择右上方的方块然后在从全局选取F最小的更新其邻域值于是有此时全局F最小的值为54而且F54的节点有两个所以我们还是选择其中H值最小的来做更新。于是更新该节点邻域方块中的值。这里你需要注意的一个地方是F54的红色节点下方邻域 (F68) 的方块中G38。但是从A到该节点的最短路径应该是30。这是因为目前程序所选择的路径是下图中紫色线路所规程出来的路径其G的增长序列是14→24→38。不过不要紧只要继续执行算法更新全局F值为最小节点 (F54) 的方块上面的G值就会给更新为正确的值了。此时全局F值最小的方块中F60所以更新该节点邻域方块中的值。现在全局F值最小的有两个都为68此时先更新H最小的。这是其实程序已经发现左侧F68的节点并不能引导一条更短的路径。于是接下来就要转向右侧F68的节点并以此为新起点搜索路径。最终反复执行上述过程你就会得到如下图中蓝色方块所示的一条最短路径。5. Python实现5.1. 算法思路A*算法实际是由广度优先遍历和Dijkstra算法演变而来的广度优先遍历主要是通过从起点依次遍历周围的点而寻找最优的路径Dijkstra基本思路跟广度优先遍历一样只不过给每次遍历的点增加了一个权值用于表明当前移动了多少距离然后每次从移动最短距离的点开始遍历A*在Dijkstra算法增加了一个期望值启发函数h最优化遍历节点的数量。广度优先遍历-Dijkstra算法-A*算法。其他寻路相关的算法也很多如JPS跳点算法但解决问题的侧重点不同关键是针对具体问题选择合适的算法。我们先来看一下地图橙点为起始点和终点本文中g为已走过的距离h为期望距离、启发值。文中会频繁使用这两个概念。A*算法中的h根据实际地图的拓扑结构可选用以下三种距离假设A与B点横纵坐标距离x和y曼哈顿距离只允许4个方向移动AB的距离为x y对角距离允许8方向移动AB的距离为x y (sqrt(2) - 2) * min(x, y)欧几里得距离允许任意方向移动AB的距离为sqrt(pow2(x) pow2(y))网格结构常用的便是8方向移动所以我们这边会选择对角距离作为h。5.2. 数据结构我在处理程序问题一般是先定义数据结构然后再补充算法本体。我们这次先从底层的数据结构逐级往上定义。从点、路径到整个地图我这边只展示关键的数据结构代码# 点的定义 class Vector2: x 0 y 0 def __init__(self, x, y): self.x x self.y y # 树结构用于回溯路径 class Vector2Node: pos None # 当前的x、y位置 frontNode None # 当前节点的前置节点 childNodes None # 当前节点的后置节点们 g 0 # 起点到当前节点所经过的距离 h 0 # 启发值 D 1 def __init__(self, pos): self.pos pos self.childNodes [] def f(self): return self.g self.h # 地图 class Map: map None # 地图0是空位1是障碍 startPoint None # 起始点 endPoint None # 终点 tree None # 已经搜寻过的节点是closed的集合 foundEndNode None # 寻找到的终点用于判断算法结束 def __init__(self, startPoint, endPoint): self.startPoint startPoint self.endPoint endPoint row [0]*MAP_SIZE self.map [] for i in range(MAP_SIZE): self.map.append(row.copy()) # 判断当前点是否超出范围 def isOutBound(self, pos): return pos.x 0 or pos.y 0 or pos.x MAP_SIZE or pos.y MAP_SIZE # 判断当前点是否是障碍点 def isObstacle(self, pos): return self.map[pos.y][pos.x] 1 # 判断当前点是否已经遍历过 def isClosedPos(self, pos): if self.tree None: return False nodes [] nodes.append(self.tree) while len(nodes) ! 0: node nodes.pop() if node.pos pos: return True if node.childNodes ! None: for nodeTmp in node.childNodes: nodes.append(nodeTmp) return False5.3. 具体实现A*算法的大概思路是从起始点开始遍历周围的点专业点的说法是放到了一个open集合中而我们这边的变量名叫做willProcessNodes从open集合中寻找估值即使用 Vector2Node.f() 函数计算的值最小的点作为下一个遍历的对象重复上面的步骤直到找到了终点。具体实现# 地图 class Map: def process(self): # 初始化open集合并把起始点放入 willProcessNodes deque() self.tree Vector2Node(self.startPoint) willProcessNodes.append(self.tree) # 开始迭代直到找到终点或找完了所有能找的点 while self.foundEndNode None and len(willProcessNodes) ! 0: # 寻找下一个最合适的点这里是最关键的函数决定了使用什么算法 node self.popLowGHNode(willProcessNodes) if self.addNodeCallback ! None: self.addNodeCallback(node.pos) # 获取合适点周围所有的邻居 neighbors self.getNeighbors(node.pos) for neighbor in neighbors: # 初始化邻居并计算g和h childNode Vector2Node(neighbor) childNode.frontNode node childNode.calcGH(self.endPoint) node.childNodes.append(childNode) # 添加到open集合中 willProcessNodes.append(childNode) # 找到了终点 if neighbor self.endPoint : self.foundEndNode childNode # 广度优先直接弹出先遍历到的节点 def popLeftNode(self, willProcessNodes): return willProcessNodes.popleft() # dijkstra寻找g最小的节点 def popLowGNode(self, willProcessNodes): foundNode None for node in willProcessNodes: if foundNode None: foundNode node else: if node.g foundNode.g: foundNode node if foundNode ! None: willProcessNodes.remove(foundNode) return foundNode # A*寻找f g h最小的节点 def popLowGHNode(self, willProcessNodes): foundNode None for node in willProcessNodes: if foundNode None: foundNode node else: if node.f() foundNode.f(): foundNode node if foundNode ! None: willProcessNodes.remove(foundNode) return foundNode我们可以看到在寻找点的时候使用了popLowGHNode这是使用A*的关键函数可以替换成上面两个函数使用不同的算法。以下展示使用不同算法的效果。广度优先遍历绿点代表遍历过的蓝点代表路径结果Dijkstra算法A*算法在A*的实现中h的计算也是个重要的参数像是本文上面中使用真实的预估距离作为h为了方便我们称该值为dh 0即Dijkstra算法h d预估值有一定的用处但相比 h d 而言性能较差h d性能最优并且能找到最佳路径h d性能可能进一步优化也可能更差但不一定是最优路径h g变成了最佳优先搜索。可以尝试调节Vector2Node.D查看效果。6. MATLAB实现function [route,numExpanded] AStarGrid(input_map, start_coords, dest_coords) % Run A* algorithm on a grid. % Inputs : % input_map : a logical array where the freespace cells are false or 0 and % the obstacles are true or 1 % start_coords and dest_coords : Coordinates of the start and end cell % respectively, the first entry is the row and the second the column. % Output : % route : An array containing the linear indices of the cells along the % shortest route from start to dest or an empty array if there is no % route. This is a single dimensional vector % numExpanded: Remember to also return the total number of nodes % expanded during your search. Do not count the goal node as an expanded node. % set up color map for display用一个map矩阵来表示每个点的状态 % 1 - white - clear cell % 2 - black - obstacle % 3 - red visited 相当于CLOSED列表的作用 % 4 - blue - on list 相当于OPEN列表的作用 % 5 - green - start % 6 - yellow - destination cmap [1 1 1; ... 0 0 0; ... 1 0 0; ... 0 0 1; ... 0 1 0; ... 1 1 0; ... 0.5 0.5 0.5]; colormap(cmap); % variable to control if the map is being visualized on every % iteration drawMapEveryTime true; [nrows, ncols] size(input_map); % map - a table that keeps track of the state of each grid cell用来上色的 map zeros(nrows,ncols); map(~input_map) 1; % Mark free cells map(input_map) 2; % Mark obstacle cells % Generate linear indices of start and dest nodes将下标转换为线性的索引值 start_node sub2ind(size(map), start_coords(1), start_coords(2)); dest_node sub2ind(size(map), dest_coords(1), dest_coords(2)); map(start_node) 5; map(dest_node) 6; % meshgrid will replicate grid vectors nrows and ncols to produce % a full grid % type help meshgrid in the Matlab command prompt for more information parent zeros(nrows,ncols);%用来记录每个节点的父节点 % [X, Y] meshgrid (1:ncols, 1:nrows); xd dest_coords(1); yd dest_coords(2); % Evaluate Heuristic function, H, for each grid cell % Manhattan distance用曼哈顿距离作为启发式函数 H abs(X - xd) abs(Y - yd); H H; % Initialize cost arrays f Inf(nrows,ncols); g Inf(nrows,ncols); g(start_node) 0; f(start_node) H(start_node); % keep track of the number of nodes that are expanded numExpanded 0; % Main Loop while true % Draw current map map(start_node) 5; map(dest_node) 6; % make drawMapEveryTime true if you want to see how the % nodes are expanded on the grid. if (drawMapEveryTime) image(1.5, 1.5, map); grid on; axis image; drawnow; end % Find the node with the minimum f value,其中的current是index值需要转换 [min_f, current] min(f(:)); if ((current dest_node) || isinf(min_f)) break; end; % Update input_map map(current) 3; f(current) Inf; % remove this node from further consideration numExpandednumExpanded1; % Compute row, column coordinates of current node [i, j] ind2sub(size(f), current); % ********************************************************************* % ALL YOUR CODE BETWEEN THESE LINES OF STARS % Visit all of the neighbors around the current node and update the % entries in the map, f, g and parent arrays % action[-1 0; 1 0; 0 -1; 0 1];%上下左右 for a1:4 expand[i,j]action(a,:); expand1expand(1,1); expand2expand(1,2); %不超出边界不穿越障碍不在CLOSED列表里也不是起点则进行扩展 if ( expand11 expand1nrows expand21 expand2nrows map(expand1,expand2)~2 map(expand1,expand2)~3 map(expand1,expand2)~5) if ( g(expand1,expand2) g(i,j)1 ) g(expand1,expand2) g(i,j)1; f(expand1,expand2) g(expand1,expand2)H(expand1,expand2); parent(expand1,expand2)current; map(expand1,expand2)4; end end end %********************************************************************* end %% Construct route from start to dest by following the parent links if (isinf(f(dest_node))) route []; else route [dest_node]; while (parent(route(1)) ~ 0) route [parent(route(1)), route]; end % Snippet of code used to visualize the map and the path for k 2:length(route) - 1 map(route(k)) 7; pause(0.1); image(1.5, 1.5, map); grid on; axis image; end end end参考文献[Unity] A-Star(A星)寻路算法 - 我爱我家喵喵 - 博客园A*算法详细讲解以及实现_zha_zha_wei的博客-CSDN博客_a*算法实现Python A*算法的简单实现_暗光之痕的博客-CSDN博客_a*算法python实现

相关文章:

A* 算法学习

在游戏中,有一个很常见地需求,就是要让一个角色从A点走向B点,我们期望是让角色走最少的路。嗯,大家可能会说,直线就是最短的。没错,但大多数时候,A到B中间都会出现一些角色无法穿越的东西&#…...

AI智能体编排框架AgentCadence:用工作流与状态机提升复杂任务执行效率

1. 项目概述:当AI智能体学会“节奏感”最近在AI智能体(Agent)的开发圈里,一个名为“AgentCadence”的项目引起了我的注意。这个由开发者toddwyl开源的库,名字直译过来是“智能体节奏”,听起来有点抽象&…...

ORB-SLAM2 从理论到代码实现(十五):KeyFrameDatabase 类

1. 该类是关键帧的数据库 构建关键帧数据库,可以联系链表等常用数据结构的构建过程:创建、增加元素、删除元素、清理。 首先需要明确数据存储的数据类型:以关键帧作为数据库的元素。 这个地方需要理解两个概念:单词&#xff08…...

ORB-SLAM2 从理论到代码实现(十四):KeyFrame 类

1. 原理分析 KeyFrame为关键帧,关键帧之所以存在是因为优化需要,所以KeyFrame的几乎所有内容都是位优化服务的。该类中的函数较多,我们需要归类梳理一下,明白其功能原理,才能真正弄懂它的内容。 图优化需要构建节点和…...

ORB-SLAM2 从理论到代码实现(十三):MapPoint 类

MapPoint是地图中的特征点,它自身的参数是三维坐标和描述子,在这个类中它需要完成的主要工作有以下方面: (1) 维护关键帧之间的共视关系 (2) 通过计算描述向量之间的距离,在多个关键帧的特征点中找最匹配的特征点 (3) 在闭环完…...

天龙八部单机版GM工具:从手动修改到一键管理的革命

天龙八部单机版GM工具:从手动修改到一键管理的革命 【免费下载链接】TlbbGmTool 某网络游戏的单机版本GM工具 项目地址: https://gitcode.com/gh_mirrors/tl/TlbbGmTool 还在为《天龙八部》单机版的数据管理而头疼吗?每次修改角色属性都要手动编辑…...

如何在Windows上快速安装安卓应用:APK Installer完整实战指南

如何在Windows上快速安装安卓应用:APK Installer完整实战指南 【免费下载链接】APK-Installer An Android Application Installer for Windows 项目地址: https://gitcode.com/GitHub_Trending/ap/APK-Installer 你是否厌倦了笨重的安卓模拟器?是…...

探索 MCP 协议:连接 AI 模型与外部工具的新标准

探索 MCP 协议:连接 AI 模型与外部工具的新标准 引言 在大型语言模型(LLM)快速发展的今天,如何让模型安全、高效地访问外部数据源和工具,成为了 AI Agent 落地应用中的关键挑战。Model Context Protocol (MCP) 的出现&…...

通达信缠论插件快速入门:3步实现自动化技术分析,告别手动画线烦恼

通达信缠论插件快速入门:3步实现自动化技术分析,告别手动画线烦恼 【免费下载链接】ChanlunX 缠中说禅炒股缠论可视化插件 项目地址: https://gitcode.com/gh_mirrors/ch/ChanlunX 缠论技术分析是股票交易中极具价值的理论体系,但传统…...

怎样用Stretchly打造你的专属健康办公节奏:5分钟快速上手指南

怎样用Stretchly打造你的专属健康办公节奏:5分钟快速上手指南 【免费下载链接】stretchly The break time reminder app 项目地址: https://gitcode.com/gh_mirrors/st/stretchly 在数字办公时代,健康屏幕时间管理已成为现代职场人士的必备技能。…...

yolov5实现火焰识别/检测步骤记录

1.克隆yolov5仓库 git clone https://github.com/ultralytics/yolov5 2.安装python3.7、Pytorch1.7.0环境 3.安装yolov5环境 pip install -r requirements.txt 4.数据集与配置文件 #数据集来源 https://universe.roboflow.com/dataset-9xayt/fire-data-annotations-lwfou 在…/…...

GetQzonehistory:三步轻松备份你的QQ空间完整历史说说

GetQzonehistory:三步轻松备份你的QQ空间完整历史说说 【免费下载链接】GetQzonehistory 获取QQ空间发布的历史说说 项目地址: https://gitcode.com/GitHub_Trending/ge/GetQzonehistory 你是否曾经担心QQ空间里那些记录青春岁月的说说会随着时间流逝而消失&…...

ubuntu中添加用户并赋予root权限

1. 添加用户 useradd [-d homepath] [-s shell] -m username useradd -d /home/test -s /bin/bash -m test -d:指定用户的家目录 -s:用户的登录shell -m:创建用户家目录2. 给用户添加root权限 usermod -aG sudo username #测试用户是否有ro…...

中小企业IT治理困局破局之道(AISMM轻量化实施框架首次公开)

更多请点击: https://intelliparadigm.com 第一章:中小企业IT治理困局的本质解构 中小企业IT治理常被简化为“买几台服务器、装个OA、找人修电脑”,但其深层矛盾实为战略意图、组织能力与技术现实之间的三重断裂。当业务部门抱怨系统响应慢&…...

为AI助手集成BigDataCloud MCP Server:实现IP定位与数据验证

1. 项目概述:当AI助手学会“看地图”与“查户口” 如果你经常和Claude、Cursor或者GitHub Copilot这类AI助手打交道,有没有想过让它们变得更“接地气”?比如,你正在写一个用户注册表单,想让AI帮你验证用户输入的手机号…...

如何在老旧Android电视上免费观看4K直播?终极电视直播应用指南

如何在老旧Android电视上免费观看4K直播?终极电视直播应用指南 【免费下载链接】mytv-android 使用Android原生开发的电视直播软件 项目地址: https://gitcode.com/gh_mirrors/myt/mytv-android 如果你正在寻找一款能在老旧Android电视上流畅播放4K直播的免费…...

GetQzonehistory终极指南:3分钟永久备份你的QQ空间所有历史记录

GetQzonehistory终极指南:3分钟永久备份你的QQ空间所有历史记录 【免费下载链接】GetQzonehistory 获取QQ空间发布的历史说说 项目地址: https://gitcode.com/GitHub_Trending/ge/GetQzonehistory 还在担心QQ空间里那些承载着青春回忆的说说会随着时间流逝而…...

基于Azure Cosmos DB与OpenAI构建企业级RAG智能问答应用实战

1. 项目概述:构建一个基于向量数据库的智能对话应用最近在折腾一个挺有意思的项目,想和大家分享一下如何用 Azure Cosmos DB 和 Azure OpenAI Service 来搭建一个真正能用的“副驾驶”应用。这个项目的核心思路,就是把你的数据变成 AI 能理解…...

基于 Taotoken 构建支持多模型切换的智能内容创作平台

基于 Taotoken 构建支持多模型切换的智能内容创作平台 1. 多模型内容创作场景需求分析 在智能内容创作领域,不同创作类型对生成模型的需求存在显著差异。小说创作可能需要更强的叙事连贯性和角色塑造能力,商业文案需要精准的品牌调性把控,而…...

告别手动拷贝!用cwRsync在Windows和Linux间自动同步文件(附详细配置步骤)

跨平台文件同步利器:cwRsync在Windows与Linux间的自动化实践 对于需要在Windows与Linux系统间频繁传输文件的运维工程师和开发者来说,手动复制粘贴或使用FTP工具不仅效率低下,还容易出错。想象一下凌晨三点被叫醒处理生产环境文件同步失败的场…...

Cherry MX键帽3D模型库:解锁机械键盘个性化定制新维度

Cherry MX键帽3D模型库:解锁机械键盘个性化定制新维度 【免费下载链接】cherry-mx-keycaps 3D models of Chery MX keycaps 项目地址: https://gitcode.com/gh_mirrors/ch/cherry-mx-keycaps 还在为寻找独特键帽而烦恼吗?cherry-mx-keycaps项目为…...

BthPS3蓝牙驱动:Windows上完美连接PS3控制器的终极解决方案

BthPS3蓝牙驱动:Windows上完美连接PS3控制器的终极解决方案 【免费下载链接】BthPS3 Windows kernel-mode Bluetooth Profile & Filter Drivers for PS3 peripherals 项目地址: https://gitcode.com/gh_mirrors/bt/BthPS3 还在为PS3控制器在Windows电脑上…...

Emby.CustomCssJS:深度定制你的媒体服务器界面架构

Emby.CustomCssJS:深度定制你的媒体服务器界面架构 【免费下载链接】Emby.CustomCssJS Easy to manage your Custom JavaScript and Css to modify Emby 项目地址: https://gitcode.com/gh_mirrors/em/Emby.CustomCssJS Emby.CustomCssJS是一个专为Emby媒体服…...

Windows安卓应用安装终极指南:APK-Installer完整使用教程

Windows安卓应用安装终极指南:APK-Installer完整使用教程 【免费下载链接】APK-Installer An Android Application Installer for Windows 项目地址: https://gitcode.com/GitHub_Trending/ap/APK-Installer 想在Windows电脑上轻松安装安卓应用吗&#xff1f…...

Cloud Commander测试策略:确保文件管理器稳定性的完整方案

Cloud Commander测试策略:确保文件管理器稳定性的完整方案 【免费下载链接】cloudcmd ✨☁️📁✨ Cloud Commander file manager for the web with console and editor. 项目地址: https://gitcode.com/gh_mirrors/cl/cloudcmd Cloud Commander是…...

Spring Boot项目里,除了velocity-engine-core,你还需要Velocity-Tools吗?一个工具包的选择指南

Spring Boot项目中Velocity工具包的深度选型指南:何时需要Velocity-Tools? 在Java生态中,模板引擎的选择往往让开发者陷入"功能过剩"与"能力不足"的两难境地。Velocity作为老牌模板引擎,其轻量级设计哲学至今…...

Windows 10 下 Qt 5.15 组件选择避坑指南:从MSVC到MinGW,32G空间怎么装最合理?

Windows 10下Qt 5.15组件选择避坑指南:从MSVC到MinGW的32G空间优化方案 Qt作为跨平台开发框架,其组件选择直接影响开发效率和磁盘空间占用。面对Qt在线安装器中庞大的组件列表,开发者常陷入两难:既希望功能完备,又担心…...

Linux下部署MySQL5.7.35

1.MySQL下载 (1)登录到以下网站 https://downloads.mysql.com/archives/community/ (2)选择需要的版本 ,以及操作系统 ,这里是Red Hat Enterprise Linux / Oracle Linux 5.7.35 版本。 (3&…...

OpenMV的PWM控制舵机,从调参到避坑的全流程记录(基于Timer和pyb库)

OpenMV的PWM控制舵机:从调参到避坑的全流程实战指南 引言:为什么选择OpenMV控制舵机? 在嵌入式视觉项目中,我们常常需要同时处理图像识别和机械控制两个任务。传统方案通常采用主控视觉模块的架构,但这种设计存在通信延…...

为什么选择vue-markdown?与其他Markdown渲染器的全面对比分析

为什么选择vue-markdown?与其他Markdown渲染器的全面对比分析 【免费下载链接】vue-markdown vue-markdown: 是一个用于Vue.js的Markdown渲染器组件,允许在Vue应用中轻松展示Markdown格式的内容。 项目地址: https://gitcode.com/gh_mirrors/vu/vue-ma…...