C#实现A*寻路算法 附源码及运行成果图
A*寻路算法实现原理请网上另寻讲解,我也是网上找了很多源码,不过运行总会出现各种各样的问题,因此自己参考网上代码进行修改和完善,本文附实现源码及运行成果图,每段代码都有注释,可以直接运行:
class Grid { public int x; public int y; public int f; public int g; public int h; public Grid parent; public Grid(int x, int y) { this.x = x; this.y = y; } /// <summary> /// 邻近节点不在openList中,设置“父节点”、G、H、F,并放入openList /// </summary> /// <param name="parent"></param> /// <param name="end"></param> public void InitGrid(Grid parent, Grid end) { this.parent = parent; if(Math.Abs(this.x - parent.x)==1&& Math.Abs(this.y - parent.y)==1) { this.g = parent.g + 14; } else if (parent != null) this.g = parent.g + 10; else this.g = 10; this.h = (int)Math.Sqrt(Math.Abs(this.x - end.x) * Math.Abs(this.x - end.x) + Math.Abs(this.y - end.y) * Math.Abs(this.y - end.y))*10; this.f = this.g + this.h; } } class AStarPathFinding { /// <summary> /// 定义场景 /// </summary> public static int[,] MAZE = new int[,] { {0,0,0,0,0,0,0}, {0,0,1,0,0,0,0}, {0,0,1,0,0,0,0}, {0,0,1,0,0,0,0}, {0,0,1,0,0,0,0}, }; /// <summary> /// 判断当前节点是否存在于openList或者closeList中 /// </summary> /// <param name="grids"></param> /// <param name="x"></param> /// <param name="y"></param> /// <returns></returns> private static bool ContainGrid(List<Grid> grids, int x, int y) { foreach (var item in grids) { if (item.x == x && item.y == y) return true; } return false; } /// <summary> /// 判断当前节点是否符合条件 /// </summary> /// <param name="x"></param> /// <param name="y"></param> /// <param name="openList"></param> /// <param name="closeList"></param> /// <returns></returns> private static bool IsValidGrid(int x, int y, List<Grid> openList, List<Grid> closeList) { //是否超过边界 if (x < 0 || x >= MAZE.GetLength(0) || y < 0 || y >= MAZE.GetLength(1)) return false; //是否有障碍物 if (MAZE[x, y] == 1) return false; //是否已经在openList中 if (ContainGrid(openList, x, y)) return false; //是否已经在closeList中 if (ContainGrid(closeList, x, y)) return false; return true; } /// <summary> /// 从当前节点周围的八个节点中找到符合条件的节点 /// </summary> /// <param name="grid"></param> /// <param name="openList"></param> /// <param name="closeList"></param> /// <returns></returns> private static List<Grid> FindNeighbors(Grid grid, List<Grid> openList, List<Grid> closeList) { List<Grid> gridList = new List<Grid>(); if (IsValidGrid(grid.x, grid.y - 1, openList, closeList)) gridList.Add(new Grid(grid.x, grid.y - 1)); if (IsValidGrid(grid.x, grid.y + 1, openList, closeList)) gridList.Add(new Grid(grid.x, grid.y + 1)); if (IsValidGrid(grid.x - 1, grid.y, openList, closeList)) gridList.Add(new Grid(grid.x - 1, grid.y)); if (IsValidGrid(grid.x + 1, grid.y, openList, closeList)) gridList.Add(new Grid(grid.x + 1, grid.y)); if (IsValidGrid(grid.x - 1, grid.y - 1, openList, closeList) && (MAZE[grid.x, grid.y - 1] != 1)&&(MAZE[grid.x-1,grid.y]!=1)) gridList.Add(new Grid(grid.x - 1, grid.y - 1)); if (IsValidGrid(grid.x - 1, grid.y + 1, openList, closeList) && (MAZE[grid.x, grid.y + 1] != 1) && (MAZE[grid.x-1, grid.y] != 1)) gridList.Add(new Grid(grid.x - 1, grid.y + 1)); if (IsValidGrid(grid.x + 1, grid.y - 1, openList, closeList) && (MAZE[grid.x + 1, grid.y] != 1) && (MAZE[grid.x, grid.y - 1] != 1)) gridList.Add(new Grid(grid.x + 1, grid.y - 1)); if (IsValidGrid(grid.x + 1, grid.y + 1, openList, closeList) && (MAZE[grid.x+1, grid.y] != 1) && (MAZE[grid.x, grid.y + 1] != 1)) gridList.Add(new Grid(grid.x + 1, grid.y + 1)); return gridList; } /// <summary> /// 从openList中找到F值最小的节点 /// </summary> /// <param name="openList"></param> /// <returns></returns> private static Grid FindMinGrid(List<Grid> openList) { Grid tempGrid = openList[0]; foreach (var item in openList) { if (item.f < tempGrid.f) tempGrid = item; } return tempGrid; } /// <summary> /// A*寻路主逻辑 /// </summary> /// <param name="star">起点</param> /// <param name="end">终点</param> /// <returns></returns> public static Grid AStarSearch(Grid start, Grid end) { List<Grid> openList = new List<Grid>(); List<Grid> closeList = new List<Grid>(); //把起点加入openList openList.Add(start); //主循环,每一轮检查1个当前方格节点 while (openList.Count > 0) { //在openList中查找F值最小的节点 Grid currentGrid = FindMinGrid(openList); //将当前节点从openList中移除 openList.Remove(currentGrid); //当前方格节点进入closeList closeList.Add(currentGrid); //找到所有邻近节点 List<Grid> neighbors = FindNeighbors(currentGrid, openList, closeList); foreach (var item in neighbors) { if (!openList.Contains(item)) { //邻近节点不在openList中,设置“父节点”、G、H、F,并放入openList item.InitGrid(currentGrid, end); openList.Add(item); } } //如果终点在openList中,直接返回终点格子 foreach (var item in openList) { if (item.x == end.x && item.y == end.y) return item; } } //openList用尽,仍然找不到终点,说明终点不可到达,返回空 return null; } /// <summary> /// 主程序 /// </summary> /// <param name="args"></param> static void Main(string[] args) { Console.WriteLine("Start"); //设置起点和终点 Grid starGrid = new Grid(4, 0); Grid endGrid = new Grid(2, 5); //搜索终点 Grid resultGrid = AStarSearch(starGrid, endGrid); //回溯路径 List<Grid> path = new List<Grid>(); while (resultGrid != null) { path.Add(new Grid(resultGrid.x, resultGrid.y)); resultGrid = resultGrid.parent; } //输出场景和路径,路径用*表示 for (int i = 0; i < MAZE.GetLength(0); i++) { for (int j = 0; j < MAZE.GetLength(1); j++) { if (ContainGrid(path, i, j)) Console.Write("*, "); else Console.Write(MAZE[i, j] + ", "); } Console.WriteLine(); } Console.WriteLine(); } } }
运行结果(*为路径,1为障碍物):


浙公网安备 33010602011771号