zoukankan      html  css  js  c++  java
  • A*寻路

    最近做东西可能会用到寻路的功能,就先用Javascript写个A*扔这里吧。

    关于A*算法,有兴趣的同学可参考:http://www.policyalmanac.org/games/aStarTutorial.htm 

    中文版:http://blog.vckbase.com/panic/archive/2005/03/20/3778.html
    不过个人觉得A*算法的性能确实不太高,还有需要优化的地方

    OK,这里是JS版的AStar:

                /**
                 * A*类
                 * @param {Array} range 查寻范围
                 * @param {Number} scale 比例
                 * @param {Array} blockList 障碍物列表
                 * @param {Array} src 起始点
                 * @param {Array} des 目标点
                 
    */
                function AStar(range,scale,blockList,src,des){
                    var srcNode={
                        parent:null,
                        G:0,
                        H:0,
                        coord:src || [10,10]
                    };
                    var desNode={
                        parent:null,
                        G:0,
                        H:0,
                        coord:des || [90,90]
                    };
                    
                    var closedList=[];
                    var openList=[srcNode];
                    
                    
                    
                    function init(){
                        range=range || [[0,0],[100,100]];
                        scale=scale || 10;
                    }
                    
                    /**
                     * 检测障碍物
                     * @param {Array} p
                     
    */
                    function checkBlock(p){
                        var i=blockList.length;
                        
                        while(i--){
                            if(blockList[i][0]===p[0] && blockList[i][1]===p[1]){
                                return true;
                            }
                        }
                        
                        return false;
                    }
                    
                    /**
                     * 从列表中移除节点
                     * @param {Object} p
                     * @param {Array} list
                     
    */
                    function removeFromList(p,list){
                        var i=list.length;
                        while(i--){
                            if(list[i]===p){
                                list.splice(i,1);
                            }
                        }
                    }
                    
                    /**
                     * 从列表中获取节点
                     * @param {Object} p
                     * @param {Object} list
                     
    */
                    function getFromList(p,list){
                        var i=list.length;
                        var ret;
                        
                        while(i--){
                            if(list[i].coord[0]===p[0] && list[i].coord[1]===p[1]){
                                ret=list[i];
                                break;
                            }
                        }
                        
                        return ret;
                    }
                    
                    /**
                     * 获取节点的H值
                     * @param {Array} crd1
                     * @param {Array} crd2
                     
    */
                    function getH(crd1,crd2){
                        return Math.abs(crd2[0]-crd1[0]) + Math.abs(crd2[1]-crd1[1])*scale;
                    }
                    
                    /**
                     * 获取节点的G值
                     * @param {Array} crd
                     * @param {Object} p
                     
    */
                    function getG(crd,p){
                        var crd2=p.coord;
                        return Math.floor(Math.sqrt(Math.pow(crd[0]-crd2[0],2)+Math.pow(crd[1]-crd2[1],2))*scale) + p.G;
                    }
                    
                    /**
                     * 根据指定节点获取其相邻的节点集合
                     * @param {Object} p
                     
    */
                    function getNearPoints(p){
                        var i=3;
                        var j;
                        var points=[];
                        var x;
                        var y;
                        var cp;
                        var otp;
                        
                        while(i--){
                            x=p.coord[0] + (1-i);
                            j=3;
                            
                            while(j--){
                                y=p.coord[1] + (1-j);
                                
                                if ((x !== p.coord[0] || y !== p.coord[1])
                                && !checkBlock([x,y])
                                && (x > range[0][0] && x < range[1][0])
                                && (y > range[0][1] && y < range[1][1])
                                && !getFromList([x,y],closedList)
                                ){
                                    cp={
                                        parent:null,
                                        coord: [x, y],
                                        G: 0,
                                        H: getH([x, y], desNode.coord)
                                    };
                                    points.push(cp);
                                }
                            }
                        }
                        return points;
                    }
                    
                    /**
                     * 从open列表中获取当前离目标点最近的节点
                     * @param {Array} openList
                     
    */
                    function getCurrentPoint(openList){
                        var ol=openList;
                        var i=ol.length;
                        var minF=openList[0].G + openList[0].H;
                        var F;
                        var ret;
                        
                        while(i--){
                            F=ol[i].G + ol[i].H;
                            if(F <= minF){
                                minF=F;
                                ret=ol[i];
                            }
                        }
                        
                        return ret;
                    }
                    
                    /**
                     * 检查节点的父节点是否需要更新为更短路径
                     * @param {Object} p
                     * @param {Object} crtP
                     
    */
                    function checkParent(p,crtP){
                        var crd1=p.coord;
                        var crd2=crtP.coord;
                        var crtD=Math.floor(Math.sqrt(Math.pow(crd1[0]-crd2[0],2)+Math.pow(crd1[1]-crd2[1],2))*scale) + crtP.G;
                        
                        if(crtD < p.G){
                            p.G=crtD;
                            p.parent=crtP;
                        }
                    }
                    
                    /**
                     * 搜寻路径
                     
    */
                    function search(){
                        var p;
                        var np;
                        var nearPoints=[];
                        var currentPoint;
                        var i;
                        var ret;
        
                        do {
                            currentPoint=getCurrentPoint(openList);
                            closedList.push(currentPoint);
                            removeFromList(currentPoint,openList);
                            
                            if(getFromList(desNode.coord,closedList)){
                                ret=closedList;
                                break;
                            }
                            
                            nearPoints=getNearPoints(currentPoint);
                            i=nearPoints.length;
                            while(i--){
                                np=nearPoints[i];
                                if(!getFromList(np.coord,openList)){
                                    np.parent=currentPoint;
                                    np.G=getG(np.coord,currentPoint);
                                    openList.push(np);
                                }
                                checkParent(np,currentPoint);
                            }
                            
                        }while (openList.length);
                        
                        return ret;
                    }
                    
                    
                    
                    var me={
                        
                        /**
                         * 获取找寻到的路径
                         * @param {Array} src
                         * @param {Array} des
                         
    */
                        getPath:function(src,des){
                            var path=[];
                            var list;
                            var node;
                            
                            if (src) {
                                srcNode.coord=src;
                                openList = [srcNode];
                            }
                            des && (desNode.coord=des);
                
                            list=search();
                            
                            if(list){
                                node=closedList[closedList.length-1];
                                path.push(node);
                                
                                do{
                                    node=node.parent;
                                    path.push(node);
                                }while(node!==srcNode);
                            }
                            
                            return path;
                        }
                    };
                    
                    init();
                    
                    return me;
                }

    完整版示例(其中绿色为范围,黑色为障碍物,蓝色为起始点,红色为目标点,白色为寻找到的路径): 

  • 相关阅读:
    WinCE 编译固定IP到内核
    wince telnet登陆密码的取消
    lab 美国大学实验室
    PLC 开放性源代码的软件
    linux 嵌入式Linux下3G无线上网卡的驱动
    创业者/职业经理人/员工受用的36句感悟
    iShoot Developer Makes $600,000 In One Month
    如何彻底解决Vista狂读硬盘的问题
    宁做创业狼,不做打工狗
    跟我学EJBCA系列一:安装
  • 原文地址:https://www.cnblogs.com/Random/p/2709433.html
Copyright © 2011-2022 走看看