当前位置:   article > 正文

AL游戏中的自动寻路——A*算法详解(C++实现)_数据结构中迷宫的a*算法c++

数据结构中迷宫的a*算法c++

目录

      一、A*算法的一个应用实例:迷宫寻路

      二、A*算法简介

     三、A*算法的原理和步骤

     四、算法实现

        ①将用户调用的算法接口与A*算法实现接口分开

        ②A*算法实现

        ③寻找列表F值最小节点

        ④判断指定结点是否对另一结点可达

        ⑦ 寻找可达节点

        ⑧A*算法完善

        ⑨对可达节点的处理

        ⑩A*算法最终实现

        程序资源清理


一、A*算法的一个应用实例:迷宫寻路

【下面是A*算法的一个应用实例:迷宫寻路,将迷宫地图信息录入后即可自动实现路径的搜索。

以下是迷宫寻路中的全部代码,大家可以直接拷贝运行。

AStar.h

  1. #pragma once
  2. #include<list>
  3. const int kCost1 = 1; //直移一格的消耗
  4. const int kCost2 = 2; //斜移一格的消耗
  5. typedef struct _Point {
  6. int x, y; //点坐标,x - 横排 y - 竖排
  7. int F, G, H; //F=G+H
  8. struct _Point* parent;
  9. }Point;
  10. /******************************
  11. * 功能:分配一格结点
  12. * 输入:
  13. * x - 二维数组行
  14. * y - 二维数组列
  15. * 返回:
  16. * 已初始化的结点的指针
  17. ******************************/
  18. Point* AllocPoint(int x, int y);
  19. /******************************
  20. * 功能:初始化地图
  21. * 输入:
  22. * _maze - 二维数组地址
  23. * _lines - 二维数组行数
  24. * _columns - 二维数组列数
  25. * 返回:
  26. * 无
  27. ******************************/
  28. void InitAstarMaze(int* _maze, int _lines, int _colums);
  29. /******************************
  30. * 功能:寻找路径
  31. * 输入:
  32. * startPoint - 起始位置
  33. * endPoint - 终点位置
  34. * 返回:
  35. * 返回路径链表的头节点
  36. ******************************/
  37. std::list<Point*> GetPath(Point* startPoint, Point* endPoint);
  38. /******************************
  39. * 功能:资源清理
  40. * 输入:
  41. * 无
  42. * 返回:
  43. * 无
  44. ******************************/
  45. void ClearAstarMaze();

AStar.cpp

  1. #include<math.h>
  2. #include<iostream>
  3. #include<vector>
  4. #include"AStar.h"
  5. static int* maze; // 迷宫对应的二维数组,用一级指针表示
  6. static int cols; // 二维数组列数
  7. static int lines; // 二维数组对应的行数
  8. static std::list<Point*>openList; // 开放列表
  9. static std::list<Point*>closeList; // 关闭列表
  10. Point* AllocPoint(int x, int y);
  11. static std::vector<Point*>getSurroundPoints(const Point* point);
  12. static Point* isInList(std::list<Point*>& list, const Point* point);
  13. /******************************
  14. * 功能:查找openList中F值最小节点
  15. * 输入:
  16. * 无
  17. * 返回:
  18. * F值最小节点
  19. ******************************/
  20. static Point* getLeastFpoint() {
  21. if (!openList.empty()) {
  22. Point* resPoint = openList.front();
  23. std::list<Point*>::const_iterator itor;
  24. for (itor = openList.begin(); itor != openList.end(); ++itor) {
  25. Point* p = *itor; // itor是list<Point *>类型迭代器,所以*itor是Poit *类型
  26. if (p->F < resPoint->F) {
  27. resPoint = *itor;
  28. }
  29. }
  30. return resPoint;
  31. }
  32. //是空值情况
  33. return NULL;
  34. }
  35. /******************************
  36. * 功能:计算指定结点到父节点的G值
  37. * 输入:
  38. * parent - 父节点
  39. * point - 指定结点
  40. * 返回:
  41. * 指定结点到父节点的G值
  42. ******************************/
  43. static int calcG(Point* parrent, Point* point) {
  44. //如果可以直走额外消耗量为kCost1,如果需要斜走额外消耗量为kCost2
  45. //int extraG=abs(parrent->x - point->x) + abs(parrent->y - point->y) == 1 ? kCost1 : kCost2;
  46. int extraG = kCost2; // 规定只能直着走
  47. int parentG = (point->parent == NULL ? NULL : point->parent->G);
  48. return parentG + extraG;
  49. }
  50. /******************************
  51. * 功能:计算指定结点到终点结点的H值
  52. * 输入:
  53. * point - 指定结点
  54. * endPoint - 终点结点
  55. * 返回:
  56. * 指定结点到终点结点的H值
  57. ******************************/
  58. static int calcH(Point* point, Point* end) {
  59. //考虑斜移
  60. //return (int)sqrt((double)(end->x - point->x) * (double)(end->x - point->x) + (double)(end->y - point->y) + (double)(end->y - point->y));
  61. //规定只能直走
  62. return (end->x - point->x) + (end->y - point->y);
  63. }
  64. /******************************
  65. * 功能:计算指定结点的F值
  66. * 输入:
  67. * point - 指定结点
  68. * 返回:
  69. * 指定结点的F值
  70. ******************************/
  71. static int calcF(Point* point) {
  72. return point->G + point->H;
  73. }
  74. /******************************
  75. * 功能:A*算法实现
  76. * 输入:
  77. * startPoint - 起始位置
  78. * endPoint - 终点位置
  79. * 返回:
  80. * 终点位置的结点
  81. ******************************/
  82. static Point* findPath(Point* startPoint, Point* endPoint) {
  83. //置入起点,拷贝开辟一格节点,内外隔离
  84. openList.push_back(AllocPoint(startPoint->x, startPoint->y));
  85. //openList不为空时,不停的取openList中L的最小值
  86. while (!openList.empty()) {
  87. //查找openList中F最小值节点
  88. Point* curPoint = getLeastFpoint();
  89. //把最小值节点放到关闭列表中
  90. openList.remove(curPoint); // 从openList中移除
  91. closeList.push_back(curPoint); // 放入closeList中
  92. //找到当前节点周围可达节点处理
  93. std::vector<Point*>surroundPoints = getSurroundPoints(curPoint);
  94. std::vector<Point*>::const_iterator iter;
  95. for (iter = surroundPoints.begin(); iter != surroundPoints.end(); ++iter) {
  96. Point* target = *iter;
  97. //对某一结点,如果不在openList中,则加入到openList中,并设置其父节点;如果在openList中,则重新计算F值,选取min(F)的结点
  98. Point* exist = isInList(openList, target);
  99. //不在openList中
  100. if (!exist) {
  101. target->parent = curPoint;
  102. target->G = calcG(curPoint, target);
  103. target->H = calcH(target, endPoint);
  104. target->F = calcF(target);
  105. openList.push_back(target);
  106. }// 在开放列表中,重新计算G值,保留min(F)
  107. else {
  108. int tempG = calcG(curPoint, target);
  109. if (tempG < target->G) {
  110. exist->parent = curPoint;
  111. exist->G = tempG;
  112. exist->F = calcF(target);
  113. }
  114. delete target;
  115. }
  116. } // end for
  117. surroundPoints.clear();
  118. //判断终点是否在openList中
  119. Point* resPoint = isInList(openList, endPoint);
  120. if (resPoint) {
  121. return resPoint;
  122. }
  123. }
  124. //如果while执行完毕则表明没有找到
  125. return NULL;
  126. }
  127. /******************************
  128. * 功能:判断指定节点是否在指定链表中
  129. * 输入:
  130. * list - 指定链表
  131. * point - 指定节点
  132. * 返回:
  133. * Point* - 判断节点在链表中,返回该在链表中地址
  134. * NULL - 不在节点中
  135. ******************************/
  136. static Point* isInList(std::list<Point*>& list, const Point* point) {
  137. std::list<Point*>::const_iterator itor;
  138. for (itor = list.begin(); itor != list.end(); ++itor) {
  139. if ((*itor)->x == point->x && (*itor)->y == point->y) {
  140. return *itor;
  141. }
  142. }
  143. return NULL;
  144. }
  145. /******************************
  146. * 功能:判断某点是否可达指定点
  147. * 输入:
  148. * point - 指定节点
  149. * target - 待判断节点
  150. * 返回:
  151. * true - 可达
  152. * false - 不可达
  153. ******************************/
  154. static bool isCanreach(const Point* point, const Point* target) {
  155. int x = target->x;
  156. int y = target->y;
  157. //待测节点超过二维数组,或待测节点是障碍物,或者待测节点与指定节点重合,或待测节点在closeList链表中。则不可达
  158. if (x < 0 || x >= lines || y < 0 || y >= cols
  159. || maze[x * cols + y] == 0
  160. || (x == point->x && y == point->y)
  161. || isInList(closeList, target)) {
  162. return false;
  163. }
  164. if (abs(point->x - target->x) + abs(point->y - target->y) == 1) {
  165. //待测点与指定点相邻
  166. return true;
  167. }
  168. else {
  169. return false;
  170. }
  171. }
  172. /******************************
  173. * 功能:获得当前节点的周围可达节点(这里只考虑直着走)
  174. * 输入:
  175. * point - 指定节点
  176. * 返回:
  177. * 周围可达节点vector数组
  178. ******************************/
  179. static std::vector<Point*>getSurroundPoints(const Point* point) {
  180. //定义存储可达节点的数组
  181. std::vector<Point*>surroundPoints;
  182. for (int x = point->x - 1; x <= point->x + 1; ++x) {
  183. for (int y = point->y - 1; y <= point->y + 1; ++y) {
  184. Point* temp = AllocPoint(x, y);
  185. if (isCanreach(point, temp)) {
  186. surroundPoints.push_back(temp);
  187. }
  188. else {
  189. //不可达则释放资源
  190. delete temp;
  191. }
  192. }
  193. }
  194. return surroundPoints;
  195. }
  196. /******************************
  197. * 功能:初始化地图
  198. * 输入:
  199. * _maze - 二维数组地址
  200. * _lines - 二维数组行数
  201. * _columns - 二维数组列数
  202. * 返回:
  203. * 无
  204. ******************************/
  205. void InitAstarMaze(int* _maze, int _lines, int _colums) {
  206. maze = _maze;
  207. cols = _colums;
  208. lines = _lines;
  209. }
  210. /******************************
  211. * 功能:分配一格结点
  212. * 输入:
  213. * x - 二维数组行
  214. * y - 二维数组列
  215. * 返回:
  216. * 已初始化的结点的指针
  217. ******************************/
  218. Point* AllocPoint(int x, int y) {
  219. Point* temp = new Point;
  220. memset(temp, 0, sizeof(Point)); //初始值清零
  221. temp->x = x;
  222. temp->y = y;
  223. return temp;
  224. }
  225. /******************************
  226. * 功能:调用A*算法,寻找路径
  227. * 输入:
  228. * startPoint - 起始位置
  229. * endPoint - 终点位置
  230. * 返回:
  231. * 返回路径链表的头节点
  232. ******************************/
  233. std::list<Point*> GetPath(Point* startPoint, Point* endPoint) {
  234. Point* result = findPath(startPoint, endPoint);
  235. std::list<Point*>path;
  236. //返回路径,如果没有找到路径,返回空链表
  237. while (result) {
  238. path.push_front(result);
  239. result = result->parent;
  240. }
  241. //path.reverse();
  242. return path;
  243. }
  244. /******************************
  245. * 功能:资源清理
  246. * 输入:
  247. * 无
  248. * 返回:
  249. * 无
  250. ******************************/
  251. void ClearAstarMaze() {
  252. maze = NULL;
  253. lines = 0;
  254. cols = 0;
  255. std::list<Point*>::iterator itor;
  256. for (itor = openList.begin(); itor != openList.end();) {
  257. delete* itor;
  258. itor = openList.erase(itor); //从链表中删除某个结点,并返回下一个结点
  259. }
  260. for (itor = closeList.begin(); itor != closeList.end();) {
  261. delete* itor;
  262. itor = closeList.erase(itor); //从链表中删除某个结点,并返回下一个结点
  263. }
  264. }

迷宫地图代码

迷宫寻路中的图片下载地址

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/526184
推荐阅读
相关标签