ToB企服应用市场:ToB评测及商务社交产业平台

标题: 11.A星寻路算法 [打印本页]

作者: 老婆出轨    时间: 2025-2-13 23:04
标题: 11.A星寻路算法
14.A星寻路算法

标题

迷宫寻路需求,在一个迷宫游戏中,有一些怪物攻击主角,现在盼望小怪物,能自动绕过迷宫中的障碍物,探求到主角的所在。
思路

A星寻路算法(A*search algorithm),是一种用于探求有效路径的算法。
简单的场景举例(简化问题),看一看A星寻路算法的工作过程。

小怪物从绿色的小方块开始每次只能移动一步,且不能穿越墙壁,求到达红色小方块的最少步数。
引入两个聚集和一个公式。
聚集:OpenList(可到达的格子),CloseList(已到达的格子)。
公式:F = G + H
每一个格子都具有F,G,H这3个属性,G(从起点走到当前格子的成本,既是从起点走大当前格子,已经走的步数),H(在不考虑障碍物的情况下,从当前格子走到目标格子的距离,也就是离目标另有多远),F(G和H之和,既是从起点到达当前格子,再从当前格子到达目标格子的总步数)。
第一步,把起点放入OpenList,也就是刚才所说的可到达格子的聚集。第2步,找出OpenList中F值最小的方格作为当前方格。虽然我们没有直接计算 起点方格的F值,但此时OpenList中只有唯一的方格Grid(1,2),把当前格子移出 OpenList,放入CloseList。代表这个格子已到达并查抄过了。第3步,找出当前方格(刚刚查抄过的格子)上、下、左、右全部可到达的格 子,看它们是否在OpenList或CloseList当中。假如不在,则将它们加入 OpenList,计算出相应的G、H、F值,并把当前格子作为它们的“父节点”。一个格子的“父节点”代表它的来路,在输出终极蹊径时会用到。刚才的1-3步,就是局部寻路的步骤。重复2,3步,直到找到尽头,或把全部可达的格子用尽为止。
代码
  1. import java.util.ArrayList;
  2. import java.util.List;
  3. import java.util.Objects;
  4. public class AStar {
  5.     public static final int[][] MAZE = {
  6.             {0, 0, 0, 0, 0, 0, 0},
  7.             {0, 0, 0, 1, 0, 0, 0},
  8.             {0, 0, 0, 1, 0, 0, 0},
  9.             {0, 0, 0, 1, 0, 0, 0},
  10.             {0, 0, 0, 0, 0, 0, 0}
  11.     };
  12.     /**
  13.      * A*寻路主逻辑
  14.      *
  15.      * @param start 起点
  16.      * @param end   终点
  17.      */
  18.     public static Grid aStarSearch(Grid start, Grid end) {
  19.         List<Grid> openList = new ArrayList<>();
  20.         List<Grid> closeList = new ArrayList<>();
  21.         openList.add(start);
  22.         while (openList.size() > 0) {
  23.             Grid currentGrid = findMinGrid(openList);//在openList找到F值最小的点
  24.             openList.remove(currentGrid);//在openList移除当前格子
  25.             closeList.add(currentGrid);//添加到closeList
  26.             List<Grid> neighbors = findNeighbors(currentGrid, openList, closeList);
  27.             for (Grid grid : neighbors) {
  28.                 if (!openList.contains(grid)) {
  29.                     //相邻节点不在openList,标记"父节点",G,H,F并放入openList
  30.                     grid.initGrid(currentGrid, end);
  31.                     openList.add(grid);
  32.                 }
  33.             }
  34.             for (Grid grid : openList) {//终点在openList中,直接返回终点格子
  35.                 if ((grid.x == end.x) && (grid.y == end.y))
  36.                     return grid;
  37.             }
  38.         }
  39.         return null;//openList用尽,找不到终点,说明终点不可达,返回null
  40.     }
  41.     /**
  42.      * 寻找在OpenList集合中F值最小的
  43.      */
  44.     private static Grid findMinGrid(List<Grid> openList) {
  45.         Grid grid = openList.get(0);
  46.         for (Grid _grid : openList) {
  47.             if (_grid.f < grid.f)
  48.                 grid = _grid;
  49.         }
  50.         return grid;
  51.     }
  52.     /**
  53.      * 寻找在格子,周围的格子(在边界内,没有走过的)
  54.      */
  55.     private static List<Grid> findNeighbors(Grid grid, List<Grid> openList, List<Grid> closeList) {
  56.         List<Grid> gridList = new ArrayList<>();
  57.         int x = grid.x;
  58.         int y = grid.y;
  59.         if (isValidGrid(x, y - 1, openList, closeList))
  60.             gridList.add(new Grid(x, y - 1));
  61.         if (isValidGrid(x, grid.y + 1, openList, closeList))
  62.             gridList.add(new Grid(x, y + 1));
  63.         if (isValidGrid(x - 1, y, openList, closeList))
  64.             gridList.add(new Grid(x - 1, y));
  65.         if (isValidGrid(x + 1, y, openList, closeList))
  66.             gridList.add(new Grid(x + 1, y));
  67.         return gridList;
  68.     }
  69.     private static boolean isValidGrid(int x, int y, List<Grid> openList, List<Grid> closeList) {
  70.         if (x < 0 || x >= MAZE.length || y < 0 || y >= MAZE[0].length)//是否越过边界
  71.             return false;
  72.         if (MAZE[x][y] == 1)//是否有障碍物
  73.             return false;
  74.         if (containGrid(openList, x, y))//是否在openList
  75.             return false;
  76.         return !containGrid(closeList, x, y);//在closeList,返回false 不在时不满足所有情况,返回true
  77.         /**
  78.          *  return !containGrid(closeList, x, y); <==>
  79.          *  if(containGrid(closeList, x, y))
  80.          *      return false;
  81.          *  return true;
  82.          */
  83.     }
  84.     private static boolean containGrid(List<Grid> grids, int x, int y) {
  85.         for (Grid grid : grids) {
  86.             if (grid.x == x && grid.y == y)
  87.                 return true;
  88.         }
  89.         return false;
  90.     }
  91.     static class Grid {
  92.         //演示代码,不符合Java Bean规范
  93.         public int x;
  94.         public int y;
  95.         public int f;
  96.         public int g;
  97.         public int h;
  98.         public Grid parent;
  99.         public Grid(int x, int y) {
  100.             this.x = x;
  101.             this.y = y;
  102.         }
  103.         public void initGrid(Grid parent, Grid end) {
  104.             this.parent = parent;//设置当前节点的父节点,方便回溯路径
  105.             this.g = Objects.nonNull(parent) ? (parent.g + 1) : 1;//设置G属性值
  106.             this.h = Math.abs(this.x - end.x) + Math.abs(this.y - end.y);//设置H属性值
  107.             this.f = this.g + this.h;//设置F属性值
  108.         }
  109.     }
  110.     public static void main(String[] args) {
  111.         Grid startGrid = new Grid(2, 1);//起点
  112.         Grid endGrid = new Grid(2, 5);//终点
  113.         Grid resultGrid = aStarSearch(startGrid, endGrid);
  114.         //回溯迷宫路径
  115.         List<Grid> path = new ArrayList<>();
  116.         while (Objects.nonNull(resultGrid)) {
  117.             path.add(new Grid(resultGrid.x, resultGrid.y));
  118.             resultGrid = resultGrid.parent;
  119.         }
  120.         //输出迷宫和路径,路径用*表示
  121.         for (int i = 0; i < MAZE.length; i++) {
  122.             for (int j = 0; j < MAZE[0].length; j++) {
  123.                 if (containGrid(path, i, j))
  124.                     System.out.print("*,");
  125.                 else
  126.                     System.out.print(MAZE[i][j] + ",");
  127.             }
  128.             System.out.println();
  129.         }
  130.     }
  131. }
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4