A*寻路算法学习及实现
来源:互联网 发布:淘宝外卖点麻辣烫 编辑:程序博客网 时间:2024/04/30 22:57
A*寻路算法学习及实现
- 算法简介
A*算法是游戏中常用的一种寻路算法,通过该算法可以求得节点化地图上起点到终点的一条最短路。
它将最短路算法(Dijkstra)和启发式算法(Greedy Best-First-Search)进行了结合。通过代价函数F=G+H 进行寻找最短路(G为离起点最近的目标节点的距离;H为该目标节点到终点的距离,起到启发作用);有效避免了Dijstra寻路过程中的搜索空间很大的缺点,又避免了简单启发式算法在复杂地形下找不到最优路径的问题。具体细节可以参考Stanford的A*简介。 算法流程
- 符号标记:
- 代价函数
F=G+H ; - 开列表(open list)和闭列表(close list),openList用于存储当前已搜索过的节点的邻接节点,closeList用于存储已经搜索过的节点,当openList中的F值最小的节点被选中为当前搜索节点(curNode)后,将该节点放入closeList中;
- 父节点(parentNode),表示该节点到起点所需要经过的最短路中的第一个节点;
- 相邻节点间的距离(D):垂直或水平相邻距离为10,斜对角相邻距离为14;
- 地图(map),起点(S),终点(D),当前搜索节点(curNode);
- map是经节点化处理过的,这里将地图处理成网格,每个网格即为一个节点;
- 每个节点有四种状态:
普通状态(normal)表示该节点为可通过节点;
障碍状态(obstacle)表示该节点为障碍物,不可通过;
开状态(open)表示该节点在openList中;
闭状态(close)表示该节点在closeList中;
- 代价函数
- 流程:
- 初始化:生成map;openList、closeList为空;curNode = S;
- while(curNode != D) —- 一直搜索到终点加入到openList结束
- closeList.push_back(curNode) —- 搜索过的节点放入闭集合;
- 更新当前搜索的节点curNode的邻接节点adjNodes状态:
- 对adjNodes中的normal节点(nd):将其父节点设为curNode,并将该节点加入到openList中,然后计算该节点的代价值(G = curNode.G + nd.D, H = nd到终点的Manhattan距离,即从nd到终点D只进行横向和纵向移动所需要经过的距离,F = G+H);
- 对adjNodes中的open节点(od):比较其经过curNode到起点的代价(G’ = curNode.G + od.D)与该点原来到起点的代价(G)做比较: 如果 G’ < G,则更新od的父节点为curNode,并更新其代价函数值(G=G’,F = G + H);否则不做更改;
- 对adjNode中的其他类型节点:不做处理;
- 查找当前openList中F值最小的节点,赋给curNode。然后将其保存到closeList中,并从openList中移除;
- 搜索到起点S 到终点 D的路径后,从终点D开始,逐一查找其父节点,直到起点S,便找到了起点到终点间的一条最短路;
- 符号标记:
寻路结果
- map:
- 寻路:
- 终点位置1,寻路结果
- 终点位置2寻路结果
- 终点位置1,寻路结果
- map:
- 代码实现
#include <iostream>#include <vector>#include <algorithm>#include "DebugFunc.h"typedef unsigned int uint;typedef enum ENodeFlag{ ENF_OPEN, //open ENF_CLOSE, //close ENF_NORMAL, //normal ENF_OBSTACLE, //obstacle}ENodeFlag;typedef struct SPoint{ int x; //地图节点的横坐标; int y; //地图节点的纵坐标; SPoint(int ax = -1, int ay = -1) { x = ax; y = ay; } const SPoint operator=(const SPoint &p) { x = p.x; y = p.y; return *this; } bool operator!=(const SPoint &p) { return (p.x != x) || (p.y != y); }}SPoint;typedef struct SCost{ int G; //起点到当前节点的cost; int H; //当前节点到终点的预估cost; int F; //总代价,F=G+H; SCost() { G = H = F = 0; }}SCost;typedef struct SMap{ char m; //地图节点表示; char f; //节点状态标记,open/close/normal; SCost c; //路径代价; SPoint p; //父节点坐标; SMap() { m = '.'; f = ENF_NORMAL; }}SMap;typedef std::vector<std::vector<SMap>> TArray; // 定义存储矩阵的类型;const uint hoffset = 10; //水平移动单位距离;const uint soffset = 14; //斜对角移动的单位距离;const uint INFI = 0xFFFFFFF;//无穷值;using namespace std;void AStar(TArray &map, const SPoint &s, const SPoint &d);int main(int argc, char **argv){ //生成地图; const int mapSize = 30; TArray map(mapSize, vector<SMap>(mapSize)); SPoint s, d; s.x = 1; s.y = 9; //起点坐标; d.x = 28; d.y = 17; //终点坐标; map[s.x][s.y].m = 'S'; map[d.x][d.y].m = 'D'; for (int i = 2; i < mapSize - 5; ++i) { map[mapSize/2][i].m = '0'; map[mapSize/2][i].f = ENF_OBSTACLE; } for (int i = 1; i < 10; ++i) { map[i][mapSize/2].m = '0'; map[i][mapSize/2].f = ENF_OBSTACLE; map[mapSize - i][d.y - 2].m = '0'; map[mapSize - i][d.y - 2].f = ENF_OBSTACLE; } for (int i = d.y - 2; i < d.y + 4; ++i) { map[d.x - 2][i].m = '0'; map[d.x - 2][i].f = ENF_OBSTACLE; } //打印地图; PRINT("'.'--普通地面\t'0'--障碍物\t'S'--起点\n'D'--终点\t'o'--S到D的路径\n"); for (uint x = 0; x < mapSize; ++x) { for (uint y = 0; y < mapSize; ++y) { PRINT("%c ", map[x][y].m); } PRINT("\n"); } AStar(map, s, d); //进行寻路; //显示寻路结果; SPoint curNode = map[d.x][d.y].p; while (curNode != s) { map[curNode.x][curNode.y].m = 'o'; curNode = map[curNode.x][curNode.y].p; } PRINT("-----------------------------------------------------\n"); for (uint x = 0; x < mapSize; ++x) { for (uint y = 0; y < mapSize; ++y) { PRINT("%c ", map[x][y].m); } PRINT("\n"); } system("pause"); return 0;}void UpdateOpenNode(TArray &map, const SPoint &curNode, const SPoint &endNode, vector<SPoint> &openList){ int sX = 0, sY = 0, eX = 0, eY = 0; sX = (curNode.x - 1) >= 0 ? curNode.x - 1 : 0; eX = (curNode.x + 1) < map.size() ? curNode.x + 1 : map.size() - 1; sY = (curNode.y - 1) >= 0 ? curNode.y - 1 : 0; eY = (curNode.y + 1) < map.size() ? curNode.y + 1 : map.size() - 1; for (int curX = sX; curX <= eX; ++curX) { for (int curY = sY; curY <= eY; ++curY) { if (map[curX][curY].f == ENF_NORMAL) { openList.push_back(SPoint(curX, curY)); map[curX][curY].p = curNode; map[curX][curY].c.G = map[curNode.x][curNode.y].c.G + static_cast<int>(sqrt((float)(abs(curX - curNode.x) + abs(curY - curNode.y))) * 10); map[curX][curY].c.H = (abs(curX - endNode.x) + abs(curY - endNode.y)) * 10; map[curX][curY].c.F = map[curX][curY].c.H + map[curX][curY].c.G; map[curX][curY].f = ENF_OPEN; } else if (map[curX][curY].f == ENF_OPEN) { int curG = map[curNode.x][curNode.y].c.G + static_cast<int>(sqrt((float)(abs(curX - curNode.x) + abs(curY - curNode.y))) * 10); if (curG < map[curX][curY].c.G) //经过当前节点的路径更短; { map[curX][curY].c.G = curG; map[curX][curY].c.F = curG +map[curX][curY].c.H; map[curX][curY].p = curNode; } } } }}void AStar(TArray &map, const SPoint &s, const SPoint &d){ uint mapSize = map.size(); vector<SPoint> openList; openList.reserve(mapSize); SPoint curNode = s; while(curNode != d) { map[curNode.x][curNode.y].f = ENF_CLOSE; //将当前节点加入闭节点列表; UpdateOpenNode(map, curNode, d, openList); //更新当前节点周围的相邻节点到开列表中; //查找当前开列表中cost最小的节点;这里可做优化,将cost信息保存进来,用堆结构加速查找过程; int minCost = INFI; vector<SPoint>::iterator itor = openList.begin(), minItor; for (; itor != openList.end(); ++itor) { if (map[itor->x][itor->y].c.F < minCost) { minItor = itor; curNode = *itor; minCost = map[itor->x][itor->y].c.F; } } openList.erase(minItor); //从openList中移除当前节点; }}
0 0
- A*寻路算法学习及实现
- 【算法入门】A* 寻路算法具体过程及实现
- 游戏开发之A*算法学习及java实现
- A*寻路算法 学习
- A*寻路算法及优化
- A算法描述及JAVA实现
- CART算法学习及实现
- CART算法学习及实现
- 流场寻路算法学习及实现
- JS中实现A*算法寻路
- 游戏寻路算法A*的实现
- A*寻路算法的C#实现
- A*寻路算法的实现
- js实现A*寻路算法
- A*寻路算法的lua实现
- Unity3D实现A*寻路算法
- A*寻路算法C++简单实现
- 关于A*寻路算法的实现
- 剑指offer(二)
- 学习OpenGL入门第一步之画三角形详解
- ROS常用三維機器人仿真工具Gazebo教程匯總
- Extjs中treeStore自动提交leaf字段
- 选择时间日历控件DatePickerDialog实现(从外包项目中挖出来整理的)
- A*寻路算法学习及实现
- 分析函数:first_value,last_value用法
- 为JAXB和response设置编码,解决wechat4j中文乱码
- 备忘录模式——对象行为型模式
- bitmap的oom问题
- Redis 配置文件 详解
- C语言中宏定义(#define)时do{...}while(0)的价值
- js函数的闭包
- js事件的分类和介绍