A*寻路算法源码

// 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("未找到路径");
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值