A*算法JS版本

提供一個A*尋徑算法的源碼+DEMO,做WEB遊戲很有用。

下面是DEMO:

<html><head><title>use A* to find path...</title></head>
<body style="margin:0px">
<script>
    //地圖寬高
    var w=30,h=20;
   
    //地圖數組
    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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,0]
       ]  

    var start=[0,0];
    var end = [29,19];
   
   
    //設定相關
    var flag = 0;
    var startTD = null;
    var endTD = null;
    var passList = [];
   
    function setFlag()
    {
        var ele = event.srcElement;
       
        switch(flag)
        {
            case 0:
            {
                if(startTD != null)
                    startTD.style.background = "#ffffff";
                ele.style.background = "#0000ff";               
                start = ele.getAttribute("pos").split(',');               
                startTD = ele;
                break;
            }
            case 1:
            {
                if(endTD != null)
                    endTD.style.background = "#ffffff";
                ele.style.background = "#ff0000";
                end = ele.getAttribute("pos").split(',');
                endTD = ele;
                break;               
            }
            case 2:
                ele.style.background = "#c1c1c1";
                var pos = ele.getAttribute("pos").split(',');
                map[pos[1]][pos[0]]=1;//設置障礙點
               
                passList[passList.length]=ele;
               
                break;
            default:
                break;
        }
    }
   
   
    var lastPath = null;
    function findIt()
    {
        lastPath = AStar.getPath(map,start,end);
       
        for(var i=0;i<lastPath.length;i++)
        {
            maptt.rows[lastPath[i][1]].cells[lastPath[i][0]].style.backgroundColor="#00ff00";
        }
        alert(lastPath.join(','));
    }
  
   function clearIt()
   {
        if(lastPath == null)
            return;
        for(var i=0;i<lastPath.length;i++)
        {
            maptt.rows[lastPath[i][1]].cells[lastPath[i][0]].style.backgroundColor="#ffffff";
        }
       
        if(startTD != null)
            startTD.style.backgroundColor="#ffffff";
        if(endTD != null)
            endTD.style.backgroundColor="#ffffff";
           
           
       
        if(passList.length >0)
        {
            for(var j=0;j<passList.length;j++)
                passList[j].style.backgroundColor="#ffffff";
      
        }
       
        flag = 0;
        startTD = null;
        endTD = null;
        passList = [];
   }
  
  
</script>

<script language="javascript" src="myAStar.js"></script>

 

<table id="maptt" style="position:absolute;left:100px;top:50px;" cellspacing="1" cellpadding="0" border="0" bgcolor="#000000">
<script>
for(var i=0;i<h;i++){
 document.write("<tr>");
 for(var j=0;j<w;j++){
  document.write('<td pos='+j+","+i+' bgcolor="#ffffff" width="20" height="20" onclick="setFlag();"></td>');
 }
 document.write("</tr>");
}
</script>
</table>
<div id="info" style="position:absolute;left:100px;top:550px;">
</div>

<input type="button"  value="start" onclick="flag=0;">
<input type="button"  value="end" onclick="flag=1;">
<input type="button"  value="non" onclick="flag=2;">

<input type="button"  value="find" onclick="findIt();">
<input type="button"  value="clear" onclick="clearIt();">

</body>
</html>
 

 

 

源碼:

// JScript 文件

var AStar={};

AStar.map = [];//矩陣
AStar.closelist=[];//已考察表
AStar.openlist=[];//待考察表

AStar.start = [0,0];
AStar.end = [0,0];

AStar.sPath = [];

AStar.gw=10;
AStar.gh=10;
AStar.gwh=14;

AStar.num=0;

AStar.intA = function(t)
{
    t[0]=parseInt(t[0]);t[1]=parseInt(t[1]);
}

AStar.getPath = function(m,s,e)
{
    this.closelist.length = 0;
    this.openlist.length = 0;
    this.num=0;
   
    this.intA(s);
    this.intA(e);
   
    this.map = m;
    this.start = s;
    this.end = e;
   
    var h=(Math.abs(e[0]-s[0])+Math.abs(e[1]-s[1]))*this.gw;
   
 this.sPath=[h,0,h,s,e];
 
 if(this.doLoop())   
        return this._getPath();
    return [];
}


AStar._getPath = function(){
 var path=[]
 var t=this.closelist[this.closelist.length-1][4];
 while(1){
  path[path.length]=t;  
  for(var i=0;i<this.closelist.length;i++){
   if(this.closelist[i][3][0]==t[0]&&this.closelist[i][3][1]==t[1])
    t=this.closelist[i][4];
  }
  if(t[0]==this.start[0]&&t[1]==this.start[1])
   break;
 }
 return path;
}

AStar.doLoop = function(){
       
    this.GetF(this.getRound(this.sPath[3])); 
     
 this.Sort(this.openlist);
 
 this.sPath=this.openlist[this.openlist.length-1]; 
 
 this.closelist[this.closelist.length]=this.sPath;
 
 this.openlist[this.openlist.length-1]=null;
 
 if(this.openlist.length==0){return false;}

 this.openlist.length=this.openlist.length-1;
   
 if( (this.sPath[3][0] == this.end[0]) && (this.sPath[3][1] == this.end[1]) ){    
  return true;
 }
 else{
     //maptt.rows[this.sPath[3][1]].cells[this.sPath[3][0]].style.backgroundColor="#00ff00";
     return this.doLoop();     
 }
}


AStar.GetF = function (arr){
 var t,G,H,F;
 for(var i=0;i<arr.length;i++){
  t=arr[i].split(",");
  
  t[0]=parseInt(t[0]);t[1]=parseInt(t[1]);
  
  if(this.IsOutScreen([t[0],t[1]])||this.IsPass(arr[i])||this.InClose([t[0],t[1]])||this.IsStart([t[0],t[1]])||!this.IsInTurn([t[0],t[1]]))
   continue;
   
  if((t[0]-this.sPath[3][0])*(t[1]-this.sPath[3][1])!=0)
   G=this.sPath[1]+this.gwh;
  else
   G=this.sPath[1]+this.gw;
   
  if(this.InOpen([t[0],t[1]])){     
   if(G<this.openlist[this.num][1]){
     
    this.openlist[this.num][0]=(G+this.openlist[this.num][2]);
    this.openlist[this.num][1]=G;
    this.openlist[this.num][4]=this.sPath[3];
   }
   else{G=this.openlist[this.num][1];}
  }
  else{
   H=(Math.abs(this.end[0]-t[0])+Math.abs(this.end[1]-t[1]))*this.gw;
   F=G+H;
   arr[i]=new Array();
   arr[i][0]=F;arr[i][1]=G;arr[i][2]=H;arr[i][3]=[t[0],t[1]];arr[i][4]=this.sPath[3];
   this.openlist[this.openlist.length]=arr[i];   
   
  }
   
  
  // maptt.rows[t[1]].cells[t[0]].style.backgroundColor="#FF00FF";
     
  
 }
}


//獲取周圍八個方向的點的位置
AStar.getRound = function (pos){
 var a=new Array();
 a[0]=(pos[0]+1)+","+(pos[1]-1);
 a[1]=(pos[0]+1)+","+pos[1];
 a[2]=(pos[0]+1)+","+(pos[1]+1);
 a[3]=pos[0]+","+(pos[1]+1);
 a[4]=(pos[0]-1)+","+(pos[1]+1);
 a[5]=(pos[0]-1)+","+pos[1];
 a[6]=(pos[0]-1)+","+(pos[1]-1);
 a[7]=pos[0]+","+(pos[1]-1);
 
 return a;
}


AStar.InOpen = function (pos){
 var bool=false;
 for(var i=0;i<this.openlist.length;i++)
 {
  if(pos[0]==this.openlist[i][3][0]&&pos[1]==this.openlist[i][3][1])
  {
   bool=true;
   this.num=i;
   break;
  }
 }
 return bool;
}

AStar.InClose = function (pos){
 var bool=false;
 for(var i=0;i<this.closelist.length;i++){
  if((pos[0]==this.closelist[i][3][0])&&(pos[1]==this.closelist[i][3][1])){
   bool=true;break;}
 }
 return bool;
}

//是否是障礙點
AStar.IsPass = function (_pos){  
    var pos = _pos.split(',');
   
 if(this.map[pos[1]][pos[0]] == 1)
  return true;
 return false;
 
}

AStar.IsStart = function (pos){
 if(pos[0]==this.start[0]&&pos[1]==this.start[1])
  return true;
 return false;
}


AStar.IsInTurn = function(pos){
 if(pos[0]>this.sPath[3][0]){
  if(pos[1]>this.sPath[3][1]){
   if(this.IsPass((pos[0]-1)+","+pos[1])||this.IsPass(pos[0]+","+(pos[1]-1)))
    return false;
  }
  else if(pos[1]<this.sPath[3][1]){
   if(this.IsPass((pos[0]-1)+","+pos[1])||this.IsPass(pos[0]+","+(pos[1]+1)))
    return false;
  }
 }
 else if(pos[0]<this.sPath[3][0]){
  if(pos[1]>this.sPath[3][1]){
   if(this.IsPass((pos[0]+1)+","+pos[1])||this.IsPass(pos[0]+","+(pos[1]-1)))
    return false;
  }
  else if(pos[1]<this.sPath[3][1]){
   if(this.IsPass((pos[0]+1)+","+pos[1])||this.IsPass(pos[0]+","+(pos[1]+1)))
    return false;
  }
 }
 return true;
}

AStar.IsOutScreen = function (pos){
 if(pos[0]<0||pos[1]<0||pos[0]>(this.map[0].length-1)||pos[1]>(this.map.length-1))
  return true;
 return false;
}

AStar.Sort = function (arr){
 var temp;
 for(var i=0;i<arr.length;i++){
  if(arr.length==1)break;
  if(arr[i][0]<=arr[i+1][0]){
   temp=arr[i];
   arr[i]=arr[i+1];
   arr[i+1]=temp;
  }
  if((i+1)==(arr.length-1))
   break;
 }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章