A*算法的一个C#实现
最近正在读云风的《游戏之旅》,看着看着就读到了A*寻路算法,虽然以前没有接触过,但总觉得好奇。于是从网上找了一些资料便开始研究。
当然,主要参考的算法文档是“http://www.vckbase.com/document/viewdoc/?id=1422”不过这里并没有给出实际的源代码。而搜了一下A*算法的代码,大都是ActionScript的源码。毕竟用Flash做一个Demo会方便很多。不过既然都打开了VisualStudio,那么就用C#写一个吧。
A*算法最主要的是对路径的评分函数。而实际应用时,这个函数的设计会产生不同的结果。从上面的文档中我们可以很容易地了解到评分F的公式:
F = H + G
当然根据文中提到的简便方法,我们可以对H和G的计算写出下面的代码。

2

3

4

5

6

7

8

9

为了进行寻路的计算,我们还需要一个类来保存针对地图上某些点遍历信息的记录,比如这个点的F、G、H值各是多少,这个点的坐标以及到达这个点的上一个点的坐标。

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

33

PathNode这个类实现了IComparable接口,目的是为了对PathNode列表进行排序。还记得上面提到的文章中的一句话吗“寻找开启列表中F值最低的格子。我们称它为当前格。”没错,这就是为这个条件做的准备。对于寻找F值最低的“格子”,把开启列表一排序就OK了。
在实现实际的算法时,还需要准备3个容器对象:
private List<PathNode> unLockList = new List<PathNode>();
private Dictionary<string, PathNode> lockList = new Dictionary<string, PathNode>();
private List<PathNode> path = new List<PathNode>();
前两个是算法中提到的“开启列表”和“关闭列表”,最后一个是找到的最终路径。
最后来实现A*算法:

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

没写什么注释,但思路就是上文中的“A*方法总结”。在此就不重新粘贴一遍了。在此需要多啰嗦两句的是,关闭列表用了一个Dictionary,其实关闭列表的目的就是查找下一个点是否在关闭列表当中,用Dictionary的ContainsKey方法比较容易,毕竟在Hashtable中找个Key总比在List中找个元素要快。
为了简化算法,这里只是遍历了当前点的上下左右4个相邻点。上文中介绍的是遍历8个点的情况,不过这也不是很复杂,只不过麻烦点在于G这个方法,需要判断一下是不是斜向走的。另外对4个相邻点的遍历,方法来源于之前看的一段AS代码,它用了一个偏移量数组来保存8个偏移量。而这里只是保存了4个偏移量。在实际的算法中,循环一下偏移量数组就很方便了(之前见过一个代码并没有用这个方法,而是复制了8短类似的函数调用代码,逻辑上就不如这个看的清晰)。delta数组如下:
private int[][] delta = new int[][]{
new int[]{0,1},
new int[]{0,-1},
new int[]{1,0},
new int[]{-1,0}
};
另一个需要注意的地方是如果4个偏移后的新点包含在开启列表中,那么应该是对开启列表中对应的PathNode的G值进行更新。如果是重新new一个新的PathNode,然后再加入开启列表,那么算法就会出现问题,有可能会陷入无限循环。
对于寻路的结果获取无非就是对PathNode链表中每个PathNode进行遍历,然后放到一个List中再Reverse一下。对于地图来说,这里用的是一个int数组,元素小于0的时候代表不能通过。而A*算法计算出的结果可能并不是最优的结果,不过其效率还是比较高的,原因在于有了评分函数的帮助可以遍历更少的节点。
最后,还是贴上整个Demo项目的文件吧,结构和代码看起来可能并不优雅。[AStarPathSearch.rar]
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 周边上新:园子的第一款马克杯温暖上架
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
· 使用C#创建一个MCP客户端