// A* 寻路算法实现
/**
* 节点类,用于表示网格中的每个节点
*/
class Node {
constructor(x, y, walkable = true) {
this.x = x; // 节点的x坐标
this.y = y; // 节点的y坐标
this.walkable = walkable; // 节点是否可通行
this.g = 0; // 从起点到当前节点的代价
this.h = 0; // 当前节点到终点的估算代价
this.f = 0; // 总代价 f = g + h
this.parent = null; // 当前节点的父节点,用于回溯路径
}
}
/**
* A* 寻路算法
* @param {Node[][]} grid 网格地图,二维数组
* @param {Node} start 起点节点
* @param {Node} end 终点节点
* @returns {Node[]} 返回从起点到终点的路径(如果存在)
*/
function aStar(grid, start, end) {
const openList = []; // 开放列表,存储待处理的节点
const closedList = []; // 关闭列表,存储已处理的节点
openList.push(start); // 将起点加入开放列表
while (openList.length > 0) {
// 从开放列表中找到 f 值最小的节点
let currentNode = openList.reduce((prev, curr) => (prev.f < curr.f ? prev : curr));
// 如果当前节点是终点,回溯路径并返回
if (currentNode === end) {
const path = [];
while (currentNode) {
path.unshift(currentNode); // 将节点添加到路径的开头
currentNode = currentNode.parent; // 回溯到父节点
}
return path;
}
// 从开放列表中移除当前节点,并加入关闭列表
openList.splice(openList.indexOf(currentNode), 1);
closedList.push(currentNode);
// 获取当前节点的所有邻居
const neighbors = getNeighbors(grid, currentNode);
for (const neighbor of neighbors) {
// 如果邻居不可通行或已在关闭列表中,跳过
if (!neighbor.walkable || closedList.includes(neighbor)) {
continue;
}
// 计算邻居的 g 值
const tentativeG = currentNode.g + 1; // 假设每个移动的代价为1
// 如果邻居不在开放列表中,或者新的 g 值更小
if (!openList.includes(neighbor) || tentativeG < neighbor.g) {
neighbor.g = tentativeG; // 更新 g 值
neighbor.h = heuristic(neighbor, end); // 计算 h 值
neighbor.f = neighbor.g + neighbor.h; // 计算 f 值
neighbor.parent = currentNode; // 设置父节点
// 如果邻居不在开放列表中,将其加入
if (!openList.includes(neighbor)) {
openList.push(neighbor);
}
}
}
}
// 如果开放列表为空,说明没有路径
return [];
}
/**
* 获取指定节点的邻居节点
* @param {Node[][]} grid 网格地图
* @param {Node} node 当前节点
* @returns {Node[]} 邻居节点数组
*/
function getNeighbors(grid, node) {
const neighbors = [];
const directions = [
[0, -1], // 上
[0, 1], // 下
[-1, 0], // 左
[1, 0], // 右
];
for (const [dx, dy] of directions) {
const x = node.x + dx;
const y = node.y + dy;
// 检查坐标是否在网格范围内
if (x >= 0 && x < grid.length && y >= 0 && y < grid[0].length) {
neighbors.push(grid[x][y]);
}
}
return neighbors;
}
/**
* 启发函数(曼哈顿距离)
* @param {Node} node 当前节点
* @param {Node} end 终点节点
* @returns {number} 曼哈顿距离
*/
function heuristic(node, end) {
return Math.abs(node.x - end.x) + Math.abs(node.y - end.y);
}
// 示例用法
const grid = [];
const gridSize = 5;
// 创建一个5x5的网格
for (let x = 0; x < gridSize; x++) {
grid[x] = [];
for (let y = 0; y < gridSize; y++) {
grid[x][y] = new Node(x, y);
}
}
// 设置一些不可通行的节点
grid[1][1].walkable = false;
grid[1][2].walkable = false;
grid[1][3].walkable = false;
// 定义起点和终点
const start = grid[0][0];
const end = grid[4][4];
// 执行A*算法
const path = aStar(grid, start, end);
// 输出路径
if (path.length > 0) {
console.log("找到路径:");
path.forEach(node => console.log(`(${node.x}, ${node.y})`));
} else {
console.log("未找到路径");
}
A*寻路算法源码
于 2025-03-21 09:42:39 首次发布