当前位置:   article > 正文

C#,人工智能,机器人,路径规划,A*(AStar Algorithm)算法、源代码及计算数据可视化_c# 人工智能

c# 人工智能

Peter Hart 

Nils Nilsson 

Bertram Raphael 

参考:

C#,人工智能(AI)机器人路径规划(Path Planning)的ARA*(Anytime Replanning A* Algorithm)算法与源程序icon-default.png?t=N7T8https://blog.csdn.net/beijinghorn/article/details/125464754

一、A*算法概述

A*算法最初由斯坦福研究院(Stanford Institute)的 Peter Hart,Nils Nilsson,Bertram Raphael 发表于1968年,属于Dijkstra算法的拓展之一。

论文原文icon-default.png?t=N7T8https://www.cs.auckland.ac.nz/courses/compsci709s2c/resources/Mike.d/astarNilsson.pdf

A*算法是常用的路径规划、最短路径搜索、图遍历算法。

借助於启发函数,A*同时拥有较好的性能与准确度,因而备受人工智能、机器人研究者们的欢迎。

除了 A* ,现在发展了 D*,D*Lite。。。诸多改进的算法,后续都会给出 C# 源代码。

A* 的算法不复杂,属于入门级别的。

二、计算结果的动画演示

三、A* 源代码

1、节点信息 NodeInfo

  1. #define ANIMATE
  2. using System;
  3. using System.IO;
  4. using System.Text;
  5. using System.Linq;
  6. using System.Collections.Generic;
  7. using System.Text.RegularExpressions;
  8. namespace Legalsoft.Truffer.Algorithm
  9. {
  10. /// <summary>
  11. /// 节点信息
  12. /// </summary>
  13. public class NodeInfo
  14. {
  15. /// <summary>
  16. /// 前一节点
  17. /// </summary>
  18. public NodeInfo Last { get; set; } = null;
  19. /// <summary>
  20. /// 邻接距离(权值)
  21. /// </summary>
  22. public int ManhattanWeight { get; set; } = 0;
  23. /// <summary>
  24. /// 曼哈顿距离(权值)
  25. /// </summary>
  26. public int RemoteWeight { get; set; } = 0;
  27. /// <summary>
  28. /// 综合距离(权值)
  29. /// </summary>
  30. public int TotalWeight { get; set; } = 0;
  31. /// <summary>
  32. /// 行号
  33. /// </summary>
  34. public int Column { get; set; } = 0;
  35. /// <summary>
  36. /// 列号
  37. /// </summary>
  38. public int Row { get; set; } = 0;
  39. /// <summary>
  40. /// 是否为墙(节点)?
  41. /// </summary>
  42. public bool IsWall { get; set; } = false;
  43. /// <summary>
  44. /// 是否被加入到了close中
  45. /// </summary>
  46. public bool InClose { get; set; } = false;
  47. /// <summary>
  48. /// 开口节点?
  49. /// </summary>
  50. public bool InOpen { get; set; } = false;
  51. /// <summary>
  52. /// 路过?
  53. /// </summary>
  54. public bool Visited { get; set; } = false;
  55. /// <summary>
  56. /// 构造函数
  57. /// </summary>
  58. /// <param name="y">行号</param>
  59. /// <param name="x">列号</param>
  60. /// <param name="iswall"></param>
  61. public NodeInfo(int y, int x, bool iswall)
  62. {
  63. Row = y;
  64. Column = x;
  65. IsWall = iswall;
  66. }
  67. }
  68. }

2、地图信息MapInfo

  1. #define ANIMATE
  2. using System;
  3. using System.IO;
  4. using System.Text;
  5. using System.Linq;
  6. using System.Collections.Generic;
  7. using System.Text.RegularExpressions;
  8. namespace Legalsoft.Truffer.Algorithm
  9. {
  10. /// <summary>
  11. /// 地图信息(墙1与空0)
  12. /// </summary>
  13. public class MapInfo
  14. {
  15. /// <summary>
  16. /// 行数
  17. /// </summary>
  18. public int Row { get; set; } = 0;
  19. /// <summary>
  20. /// 列数
  21. /// </summary>
  22. public int Column { get; set; } = 0;
  23. /// <summary>
  24. /// 所有节点
  25. /// </summary>
  26. public NodeInfo[,] Nodes { get; set; } = null;
  27. /// <summary>
  28. /// 从文本创建地图
  29. /// </summary>
  30. /// <param name="buf"></param>
  31. public void FromBuffer(string buf)
  32. {
  33. buf = buf.Replace("\r", "").Trim();
  34. string[] xlines = buf.Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
  35. Nodes = new NodeInfo[xlines.Length, xlines[0].Trim().Length];
  36. Row = Nodes.GetLength(0);
  37. Column = Nodes.GetLength(1);
  38. int y = 0;
  39. foreach (string xu in xlines)
  40. {
  41. for (int x = 0; x < xu.Trim().Length; x++)
  42. {
  43. NodeInfo node = new NodeInfo(y, x, Int32.Parse(xu.Trim().Substring(x, 1)) > 0);
  44. Nodes[y, x] = node;
  45. }
  46. y++;
  47. }
  48. }
  49. /// <summary>
  50. /// 从文件创建地图
  51. /// </summary>
  52. /// <param name="filename"></param>
  53. /// <exception cref="Exception"></exception>
  54. public void FromFile(string filename)
  55. {
  56. try
  57. {
  58. string buf = File.ReadAllText(filename);
  59. FromBuffer(buf);
  60. }
  61. catch (Exception ex)
  62. {
  63. throw new Exception("");
  64. }
  65. }
  66. /// <summary>
  67. /// this重载
  68. /// </summary>
  69. /// <param name="y"></param>
  70. /// <param name="x"></param>
  71. /// <returns></returns>
  72. public NodeInfo this[int y, int x]
  73. {
  74. set { Nodes[y, x] = value; }
  75. get { return Nodes[y, x]; }
  76. }
  77. /// <summary>
  78. /// 第一个节点
  79. /// </summary>
  80. public NodeInfo First
  81. {
  82. get { return Nodes[0, 0]; }
  83. }
  84. /// <summary>
  85. /// 最后一个节点
  86. /// </summary>
  87. public NodeInfo Last
  88. {
  89. get { return Nodes[Row - 1, Column - 1]; }
  90. }
  91. /// <summary>
  92. /// 清除路径
  93. /// </summary>
  94. public void ClearPath()
  95. {
  96. for (int i = 0; i < Row; i++)
  97. {
  98. for (int j = 0; j < Column; j++)
  99. {
  100. this[i, j].Visited = false;
  101. }
  102. }
  103. }
  104. }
  105. }

3、核心代码 AStar Kernal

  1. #define ANIMATE
  2. using System;
  3. using System.IO;
  4. using System.Text;
  5. using System.Linq;
  6. using System.Collections.Generic;
  7. using System.Text.RegularExpressions;
  8. namespace Legalsoft.Truffer.Algorithm
  9. {
  10. public class AStar
  11. {
  12. /// <summary>
  13. /// 开放列表
  14. /// </summary>
  15. private List<NodeInfo> openList { get; set; } = new List<NodeInfo>();
  16. /// <summary>
  17. /// 当前访问的节点
  18. /// </summary>
  19. private NodeInfo curNode { get; set; } = null;
  20. /// <summary>
  21. /// 起始节点
  22. /// </summary>
  23. private NodeInfo startNode { get; set; } = null;
  24. /// <summary>
  25. /// 终止节点
  26. /// </summary>
  27. private NodeInfo endNode { get; set; } = null;
  28. /// <summary>
  29. /// 地图
  30. /// </summary>
  31. public MapInfo map { get; set; } = new MapInfo();
  32. /// <summary>
  33. /// 构造函数
  34. /// </summary>
  35. public AStar()
  36. {
  37. }
  38. /// <summary>
  39. /// 节点加入列表,并计算相关权值
  40. /// </summary>
  41. /// <param name="node"></param>
  42. private void AddToList(NodeInfo node)
  43. {
  44. if (node.IsWall) return;
  45. if (node.InClose) return;
  46. if (node.InOpen) return;
  47. openList.Add(node);
  48. node.InOpen = true;
  49. node.ManhattanWeight = curNode.ManhattanWeight + WeightOf(node, curNode);
  50. node.RemoteWeight = WeightOf(node, endNode);
  51. node.TotalWeight = node.ManhattanWeight + node.RemoteWeight;
  52. node.Last = curNode;
  53. }
  54. /// <summary>
  55. /// 路径规划A*算法(最短路径A*算法)
  56. /// 默认左上角(0,0)为起点;右下角为终点;
  57. /// </summary>
  58. /// <param name="start">起点</param>
  59. /// <param name="end">终点</param>
  60. public void Tracing(NodeInfo start = null, NodeInfo end = null)
  61. {
  62. List<int[]> steps = new List<int[]>() {
  63. new int[2] { 1, 1 },
  64. new int[2] { 0, 1 },
  65. new int[2] { 1, 0 },
  66. new int[2] { 0,-1 },
  67. new int[2] { -1, 0 },
  68. new int[2] { 1,-1 },
  69. new int[2] { -1, 1 },
  70. new int[2] { -1,-1 },
  71. };
  72. startNode = (start == null) ? map.First : start;
  73. endNode = (end == null) ? map.Last : end;
  74. // 将起点加入到开放列表中
  75. openList.Add(startNode);
  76. while (true)
  77. {
  78. openList.Sort(SortByCost);
  79. curNode = openList[0];
  80. openList.Remove(curNode);
  81. curNode.InOpen = false;
  82. curNode.InClose = true;
  83. // 终点?
  84. if (curNode == endNode)
  85. {
  86. return;
  87. }
  88. MarkPath();
  89. map.ClearPath();
  90. }
  91. }
  92. /// <summary>
  93. /// 节点1到节点2的Weight
  94. /// </summary>
  95. /// <param name="a">节点1</param>
  96. /// <param name="b">节点2</param>
  97. /// <returns></returns>
  98. private int WeightOf(NodeInfo a, NodeInfo b)
  99. {
  100. // 直行步长
  101. double straightDistance = 1.0;
  102. // 斜行步长
  103. double diagonalDistance = 1.414;
  104. int deltaX = Math.Abs(a.Column - b.Column);
  105. int deltaY = Math.Abs(a.Row - b.Row);
  106. if (deltaX == deltaY)
  107. {
  108. return (int)(deltaX * diagonalDistance);
  109. }
  110. else if (deltaX < deltaY)
  111. {
  112. return (int)(deltaX * diagonalDistance + (deltaY - deltaX) * straightDistance);
  113. }
  114. else
  115. {
  116. return (int)(deltaY * diagonalDistance + (deltaX - deltaY) * straightDistance);
  117. }
  118. }
  119. /// <summary>
  120. /// 排序的委托函数
  121. /// </summary>
  122. /// <param name="a">节点1</param>
  123. /// <param name="b">节点2</param>
  124. /// <returns></returns>
  125. private int SortByCost(NodeInfo a, NodeInfo b)
  126. {
  127. if (a.TotalWeight.CompareTo(b.TotalWeight) != 0)
  128. {
  129. return (a.TotalWeight.CompareTo(b.TotalWeight));
  130. }
  131. else if (a.RemoteWeight.CompareTo(b.RemoteWeight) != 0)
  132. {
  133. return (a.RemoteWeight.CompareTo(b.RemoteWeight));
  134. }
  135. else
  136. {
  137. return 1;
  138. }
  139. }
  140. /// <summary>
  141. /// 标记当前获取的路径
  142. /// </summary>
  143. public void MarkPath()
  144. {
  145. NodeInfo cd = curNode;
  146. while (cd != null)
  147. {
  148. if (cd == startNode)
  149. {
  150. break;
  151. }
  152. cd.Visited = true;
  153. cd = cd.Last;
  154. }
  155. }
  156. }
  157. }

--------------------------------------------------------------------------------

POWER BY TRUFFER.CN

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

闽ICP备14008679号