JavaScript 寻路算法实践

在 JavaScript 中实践寻路算法,最常用且易理解的是 A(A-Star)算法 *,它结合了 Dijkstra 算法的准确性和贪心算法的高效性,核心是通过“预估代价”优先探索更可能到达终点的路径。以下是完整实践步骤:
 
一、核心概念(A* 算法)
 
A* 的核心是为每个节点计算一个优先级  f = g + h ,优先选择  f  值最小的节点探索:
 
- g 值:起点到当前节点的实际移动代价(如上下左右移动,每步代价为 1)。
- h 值:当前节点到终点的预估代价(常用“曼哈顿距离”,即  |x1-x2| + |y1-y2| ,仅适用于网格无斜向移动的场景)。
- openList:待探索的节点列表(始终从中选  f  最小的节点)。
- closeList:已探索完成的节点列表(避免重复计算)。
 
二、完整代码实践(网格寻路)
 
以“二维网格”为例(0 = 可通行,1 = 障碍物),实现从起点到终点的路径查找,返回路径坐标数组。

javascript:
  
// 1. 定义节点类:存储坐标、g/h/f 值、父节点(用于回溯路径)
class Node {
  constructor(x, y) {
    this.x = x; // 横坐标
    this.y = y; // 纵坐标
    this.g = 0; // 起点到当前节点的实际代价
    this.h = 0; // 当前节点到终点的预估代价
    this.f = 0; // 总优先级:f = g + h
    this.parent = null; // 父节点(记录路径)
  }
}

// 2. A* 寻路核心函数
function aStarSearch(grid, startX, startY, endX, endY) {
  // 2.1 初始化起点和终点节点
  const startNode = new Node(startX, startY);
  const endNode = new Node(endX, endY);
  
  // 2.2 初始化 openList(待探索)和 closeList(已探索)
  const openList = [startNode];
  const closeList = [];

  // 2.3 定义移动方向(上下左右,无斜向,每步代价 1)
  const dirs = [
    { x: 0, y: -1 }, // 上
    { x: 0, y: 1 },  // 下
    { x: -1, y: 0 }, // 左
    { x: 1, y: 0 }   // 右
  ];

  // 3. 循环探索:直到 openList 为空(无路径)或找到终点
  while (openList.length > 0) {
    // 3.1 从 openList 中选 f 值最小的节点(当前最优节点)
    let currentIndex = 0;
    let currentNode = openList[0];
    for (let i = 1; i < openList.length; i++) {
      if (openList[i].f < currentNode.f) {
        currentNode = openList[i];
        currentIndex = i;
      }
    }

    // 3.2 移除当前节点到 closeList(标记为已探索)
    openList.splice(currentIndex, 1);
    closeList.push(currentNode);

    // 3.3 若找到终点:回溯父节点,生成路径(从终点到起点,最后反转)
    if (currentNode.x === endNode.x && currentNode.y === endNode.y) {
      let path = [];
      let temp = currentNode;
      while (temp) {
        path.push({ x: temp.x, y: temp.y });
        temp = temp.parent;
      }
      return path.reverse(); // 反转后:起点 → 终点
    }

    // 3.4 探索当前节点的 4 个相邻节点
    for (let dir of dirs) {
      // 计算相邻节点坐标
      const neighborX = currentNode.x + dir.x;
      const neighborY = currentNode.y + dir.y;

      // 跳过无效节点:1. 超出网格范围 2. 是障碍物(grid 中为 1) 3. 已在 closeList 中
      if (
        neighborX < 0 || neighborX >= grid[0].length || // 横向越界
        neighborY < 0 || neighborY >= grid.length ||    // 纵向越界
        grid[neighborY][neighborX] === 1 ||             // 障碍物
        closeList.some(node => node.x === neighborX && node.y === neighborY) // 已探索
      ) {
        continue;
      }

      // 初始化相邻节点(若不在 openList 中,则添加;若已在,则更新 g 值)
      let neighborNode = openList.find(node => node.x === neighborX && node.y === neighborY);
      if (!neighborNode) {
        neighborNode = new Node(neighborX, neighborY);
        // 计算 g/h/f 值
        neighborNode.g = currentNode.g + 1; // 每步代价 1
        neighborNode.h = Math.abs(neighborNode.x - endNode.x) + Math.abs(neighborNode.y - endNode.y); // 曼哈顿距离
        neighborNode.f = neighborNode.g + neighborNode.h;
        neighborNode.parent = currentNode; // 父节点指向当前节点(记录路径)
        openList.push(neighborNode);
      } else {
        // 若相邻节点已在 openList:检查“经当前节点到达”是否代价更低,是则更新
        const newG = currentNode.g + 1;
        if (newG < neighborNode.g) {
          neighborNode.g = newG;
          neighborNode.f = neighborNode.g + neighborNode.h;
          neighborNode.parent = currentNode; // 更新父节点(更优路径)
        }
      }
    }
  }

  // 4. 若 openList 为空,说明无路径
  return [];
}

// ------------------- 测试 -------------------
// 定义网格:0 = 可走,1 = 障碍物
const grid = [
  [0, 0, 0, 0, 0],
  [0, 1, 1, 1, 0],
  [0, 0, 0, 0, 0],
  [0, 1, 1, 1, 0],
  [0, 0, 0, 0, 0]
];
// 起点 (0,0),终点 (4,4)
const path = aStarSearch(grid, 0, 0, 4, 4);

console.log("寻路结果(坐标 x,y):", path);
// 输出示例:[{x:0,y:0}, {x:1,y:0}, {x:2,y:0}, ..., {x:4,y:4}]

三、关键优化与扩展
 
1. 斜向移动支持:
在  dirs  中添加斜向方向(如  {x:1,y:1} ),并将斜向移动的  g  值设为  Math.sqrt(2) (约 1.414,符合实际距离)。
2. 不同地形代价:
若网格有“草地(代价 1)”“山地(代价 3)”,可将  grid  元素设为代价值(如  2  代表山地),计算  g  值时用  currentNode.g + grid[neighborY][neighborX] 。
3. 性能优化:
- 用“哈希表”或“二维数组”存储  closeList (替代  some  遍历,降低查找时间)。
- 用“优先队列”(如  heap  结构)实现  openList (替代每次遍历找最小  f  值,时间复杂度从 O(n) 降为 O(log n))。
 
四、应用场景
 
- 游戏:角色自动寻路(如 RPG 中的 NPC 移动、塔防游戏的敌人路径)。
- 地图:APP 中的步行/驾车路线规划(需结合实际道路数据)。
- 机器人:室内机器人避障导航(网格对应物理空间)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值