A星寻路算法JS实现版

A星算法,排序是利用了array.sort来取最小代价,其实可以利用二叉树或者优先级链表,在数据添加就处理好位置排列,关闭列表和开放列表其实就是节点状态的表示,也可以用节点的一个状态属性来表示,不需要专门用一个集合来存储检查,还有就是代价因子在实际的地图应用中,是需要根据你真实的地形来计算的。 

var map = [
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
    [0, 0, 2, 0, 1, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 1, 0, 3, 0, 0, 0],
    [0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
]
var paths = findPath([2, 3], [6, 4], map);
let newMap = map.slice();
paths.forEach(p => {
    newMap[p[1]][p[0]] = 4;
});
console.log("path:",paths)
console.log("map:",newMap)
function findPath(startPoint, targetPoint, map, configs) {
    // 配置
    configs = configs || {};
    // 判断地图格子是不是障碍
    var getIsObstacle = configs.getIsObstacle || ((tileValue) => {
        return tileValue == 1;
    });
    // 代价因子
    var getCostFactor = configs.getCostFactor || ((tileValue,currentPoint, parentPoint) => {
        if (!parentPoint) {
            return 1;
        }
        return currentPoint[0] != parentPoint[0] && currentPoint[1] !== parentPoint[1] ? 1.5: 1;
    });
    var
        row = map.length, //地图行高
        col = map[0].length, //地图列宽
        openList = [],//开放列表,存放待处理的节点
        closeList = [],//关闭列表,存放已处理的节点
        mapSet = map.map(d => new Array(col));

    // 创建节点
    function createNode(point, parentNode) {
        let x2 = point[0], y2 = point[1];
        let currentNode = mapSet[y2][x2];//获取当前节点
        // // 如果已存在,就不在创建 
        // if (currentNode) {
        //    // return currentNode;
        // }
        currentNode = {};
        let tileValue = map[y2][x2];// 地图对应的tile值
        let cost = getCostFactor(tileValue,point, parentNode ? parentNode.point : null);// 代价因子
        let isObstacle = getIsObstacle(tileValue, x2, y2);//是否障碍物
        //G值 = 父节点的G值 + 父节点到当前点的移动代价
        let g = parentNode ? (parentNode.g+cost): 0;//计算当前点与起始点的距离
       // let g = parentNode ? (Math.abs(parentNode.x - x2) + Math.abs(parentNode.y - y2) * cost) + parentNode.g : 0;//计算当前点与起始点的距离
        //H值 = 当前点到结束点的曼哈顿距离
        let h = Math.abs(targetPoint[0] - x2) + Math.abs(targetPoint[1] - y2);//计算当前点与目标点的距离          
        let f = g + h;//代价

        Object.assign(currentNode, {
            value: tileValue,
            isObstacle: isObstacle,
            g: g,
            h: h,
            f: f,
            x: x2,
            y: y2,
            point: point,
            parent: parentNode
        });
        mapSet[y2][x2] = currentNode;
        return currentNode;
    }
    // 获取目标节点
    function getTargetNodePath(currentNode) {
        // 从左上角开始计算
        //从行到列 
        rowLoop:
        for (let r = currentNode.y - 1, rlen = r + 3; r < rlen; r++) {
            colLoop:
            for (let c = currentNode.x - 1, clen = c + 3; c < clen; c++) {
                // 如果不在范围内,跳过
                if (!(c >= 0 && c < col && r >= 0 && r < row)) {
                    continue colLoop;
                }
                let point = [c, r];
                let node = createNode(point, currentNode);
                // 如果节点等于目标就直接返回
                if (node.x == targetPoint[0] && node.y == targetPoint[1]) {
                    return node;
                }
                // 如果不存在openlist列表中或closelist列表,并且是非障碍
                if (!node.isObstacle && openList.indexOf(node) == -1 && closeList.indexOf(node) == -1) {
                    openList.push(node);
                }

            }
        }
        //按最小代价升序排列
        openList.sort((a, b) => {
            return a.f - b.f;
        })

    }
    var startNode = createNode(startPoint, null), targetNode;
    openList.push(startNode);
    while (openList.length) {
        current = openList.shift();//获取当前列表最小代价节点
        closeList.push(current);
        targetNode = getTargetNodePath(current);
        if (targetNode) {
            break;
        }
    }
    // 如果不等空,就找出所有路径
    var paths = [];
    if (targetNode) {
        let current = targetNode.parent;
        while (current) {
            if (current !== startNode) {
                paths.unshift(current.point);
            }
            current = current.parent;
        }
    }
    return paths;
}

 

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值