简单的A*寻路(js版本)

已知可走的路径坐标,不存在行动力的消耗

/** 
 * 相邻位置的偏移量 8个方位
 * 左,左下,下,右下,右,右上,上,左上 
 * */ 
let  NearGridOffsets = [-1, 99, 100, 101, 1, -99, -100, -101];
/* 可以行走的路径位置点(r,c,r,c...) */ 
let points = [
    8,3,8,4,8,5,8,7,8,8,8,9,8,10,8,11,8,12,8,13,8,14,8,15,8,17,8,18,
    8,19,8,20,8,21,8,22,8,23,8,24,8,25,8,26,8,27,
    8,30,8,31,8,32,8,33,8,34,8,35,8,36,8,37,8,38,8,39,
    9,4,9,7,9,12,9,13,9,14,9,15,9,16,9,17,9,18,9,19,9,20,9,21,9,22,9,23,9,24,9,25,
    9,26,9,27,9,28,9,29,9,30,9,31,9,32,9,33,9,34,9,35,9,36,9,37,9,38,9,39,
    10,4,10,5,10,6,10,7,10,8,10,9,10,10,10,11,10,12,10,13,10,14,10,15,10,16,10,17,10,18,
    10,19,10,20,10,21,10,22,10,23,10,24,10,25,10,26,10,27,10,28,10,29,
    10,30,10,31,10,32,10,33,10,34,10,35,10,36,10,38,10,39,
    11,5,11,6,11,7,11,8,11,9,11,10,11,11,11,12,11,13,11,14,11,15,11,16,11,17,11,18,
    11,19,11,27,11,28,11,29,11,30,11,31,11,32,11,33,11,34,11,35,11,36,11,38,11,39,
    12,5,12,8,12,9,12,10,12,12,12,13,12,14,12,15,12,16,12,17,12,28,12,29,
    12,30,12,31,12,32,12,33,12,34,12,35,12,36,12,37,
    13,5,13,6,13,7,13,8,13,9,13,10,13,11,13,12,13,13,13,14,13,15,13,16,13,17,
    13,28,13,29,13,30,13,31,13,32,13,33,13,34,13,35,13,36,13,37,13,38,
    14,9,14,8,14,10,14,11,14,12,14,13,14,14,14,15,14,16,14,17,
    14,28,14,29,14,30,14,31,14,32,14,33,14,34,14,35,14,36,14,37,14,38,
    15,12,15,13,15,14,15,15,15,16,15,17,
    15,28,15,29,15,30,15,31,15,32,15,33,15,34,15,35,
    16,9,16,10,16,11,16,12,16,13,16,14,16,15,16,16,16,17,16,18,
    16,19,16,27,16,28,16,29,16,30,16,31,16,32,16,35,16,36,16,37,
    17,9,17,10,17,12,17,13,17,14,17,15,17,16,17,17,17,18,17,19,
    17,20,17,21,17,22,17,23,17,24,17,25,17,26,17,27,17,28,17,29,
    17,30,17,31,17,35,17,36,17,37,
    18,10,18,12,18,13,18,14,18,15,18,16,18,17,18,18,18,19,
    18,20,18,21,18,22,18,23,18,24,18,25,18,26,18,27,18,28,18,29,18,35,18,36,
    19,24,20,23,20,24,20,25,
]

/** 位置转换(初始可以行走的点) */
let grids  = {};
for(let i = 0;i < points.length;){
    let rc = 0, r = 0, c = 0;
    r = points[i];
    c = points[i+1];
    rc = r * 100 + c;

    grids[rc] = {
        rc : rc,
        r : r,
        c : c,
    }
    i += 2;
}

/**
 * 是否是无效的点
 *
 * @param {*} rc
 * @returns
 */
let isInvalidPoint = (rc)=>{
    return !grids[rc];
}

/**
 * 查找指定的点是否在列表中
 *
 * @param {*} ps   列表
 * @param {*} rc   指定的点
 * @returns
 */
let findPoint = (ps, rc)=>{
    for(let key in ps){
        if(ps[key].rc == rc){
            return ps[key];
        }
    }
    return null;
}

/**
 * 计算两点之间的距离
 *
 * @param {*} p1
 * @param {*} p2
 */
let distance = (p1, p2)=>{
    let x1 = 0, y1 = 0;
    if( p1 >= 1000){
        x1 = p1 % 100;
        y1 = Math.floor(p1 / 100);
        
    }else{
        x1 = p1 % 10;
        y1 = Math.floor(p1 / 10);
        if (y1 == 2 || y1 == 4){
            x1 = x1 + 0.5
        }
    }

    let x2 = 0, y2 = 0;
    if (p2 >= 1000){
        x2 = p2 % 100;
        y2 = Math.floor(p2 / 100);
    } 
    else{
        x2 = p2 % 10;
        y2 = Math.floor(p2 / 10);
        if (y2 == 2 || y2 == 4){
            x2 = x2 + 0.5
        }
    }
    return Math.sqrt(Math.pow((x1-x2),2) + Math.pow((y1-y2),2));
}
 
 /** 将点位按f值升序 */
let sortPointAsc = (ps)=>{
    ps.sort((p1, p2)=>{
        return p1.f - p2.f;
    })
}

/**
 * 找出路径
 *
 * @param {*} from
 * @param {*} dest
 */
let findPath = (from,dest)=>{
    if(from == dest){
        return null;
    }
    // 目标值
    let dp = null; 
    let rc = null;
    let g = null;
    let h = null;
    let np = null;
    // 开发列表
    let opens = [
        {
            rc : from,
            g : 0,    // 当前节点到起始点的估计
            h : null, // 当前点到终点的估计
            f : 0,
            from : null, // 该点的前一格点
            wc : 0, // 已移动的格子数
        } 
    ]
    // 关闭列表
    let closes = [];

    while(opens.length > 0){
        let cp = opens[0];
        // 获取附近的点
        for (let key in NearGridOffsets){
            let ofs = NearGridOffsets[key];
            rc = cp.rc + ofs;
            // 目标点
            if (rc == dest){
                dp = {rc : dest, from : cp, wc : cp.wc+1}
                break;
            }

            // 是否存在该点,并且不在关闭列表中
            if (!isInvalidPoint(rc) && !findPoint(closes,rc)){
                //  到该点所需要的消耗值
                g = distance(cp.rc,rc) + cp.g;
                // 是否在开放列表中
                np = findPoint(opens,rc);

                if (np){
                // 如果存在
                    // 比较f值
                    let f = np.h + g
                    //  当新的cp点到 rc 该点所f消耗少,把新的cp则替换之前的form点
                    if (f < np.f){
                        np.f = f
                        np.g = g
                        np.from = cp 
                    }
                }else{
                // 不存在放入开放列表中
                    h = distance(rc, dest)
                    opens.push({
                        rc : rc,
                        g : g,
                        h : h,
                        f : g + h,
                        from : cp,
                        wc : cp.wc+1,
                    }  ) 
                }
            }
        }

        // 找到了目标点
        if(dp){
            break;
        }
        // 将该点从开放列表中移除
        opens.splice(0,1);
        closes.push(cp);
        sortPointAsc(opens)
    }

    if (dp == null){
        return null;
    }

    // 路径
    let path = [];
    do{
        path.push(dp.rc);
        dp = dp.from;
    }while(dp != null && dp.rc != from);
    path.push(from);
    path.reverse();
    return path;
}

let path = findPath(803,1020);
console.log(path);

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值