From c5da87cae7d8c1582239fb74477a1e697c0bb604 Mon Sep 17 00:00:00 2001 From: Jiminibob <15093657+Jiminibob@users.noreply.github.com> Date: Fri, 27 Aug 2021 16:21:01 +0100 Subject: [PATCH 1/2] Adds option to 'find nearest' when target tile is unacceptable --- bin/easystar-0.4.4.js | 21 +++++++++-- bin/easystar-0.4.4.min.js | 2 +- src/easystar.js | 79 ++++++++++++++++++++++++++++++++++----- 3 files changed, 87 insertions(+), 15 deletions(-) diff --git a/bin/easystar-0.4.4.js b/bin/easystar-0.4.4.js index ba4d9b5..6db12f4 100644 --- a/bin/easystar-0.4.4.js +++ b/bin/easystar-0.4.4.js @@ -116,7 +116,7 @@ var EasyStar= * * Implementation By Bryce Neal (@prettymuchbryce) **/ -var EasyStar={},Instance=__webpack_require__(1),Node=__webpack_require__(2),Heap=__webpack_require__(3);module.exports=EasyStar;var nextInstanceId=1;EasyStar.js=function(){var collisionGrid,iterationsSoFar,acceptableTiles,syncEnabled=!1,pointsToAvoid={},costMap={},pointsToCost={},directionalConditions={},allowCornerCutting=!0,instances={},instanceQueue=[],iterationsPerCalculation=Number.MAX_VALUE,diagonalsEnabled=!1; +var EasyStar={},Instance=__webpack_require__(1),Node=__webpack_require__(2),Heap=__webpack_require__(3);module.exports=EasyStar;var nextInstanceId=1;EasyStar.js=function(){var collisionGrid,iterationsSoFar,acceptableTiles,syncEnabled=!1,pointsToAvoid={},costMap={},pointsToCost={},directionalConditions={},allowCornerCutting=!0,instances={},instanceQueue=[],iterationsPerCalculation=Number.MAX_VALUE,diagonalsEnabled=!1,findNearestEnabled=!1; /** * Sets the collision grid that EasyStar uses. * @@ -146,6 +146,14 @@ this.enableDiagonals=function(){diagonalsEnabled=!0}, * Disable diagonal pathfinding. */ this.disableDiagonals=function(){diagonalsEnabled=!1}, +/** + * Enable pathfinder to find 'nearest' tile when non acceptable tile is selected. + */ +this.enableFindNearest=function(){findNearestEnabled=!0}, +/** + * Enable find nearest. + */ +this.disableFindNearest=function(){findNearestEnabled=!1}, /** * Sets the collision grid that EasyStar uses. * @@ -249,7 +257,7 @@ if(void 0===acceptableTiles)throw new Error("You can't set a path without first if(void 0===collisionGrid)throw new Error("You can't set a path without first calling setGrid() on EasyStar.");// Start or endpoint outside of scope. if(startX<0||startY<0||endX<0||endY<0||startX>collisionGrid[0].length-1||startY>collisionGrid.length-1||endX>collisionGrid[0].length-1||endY>collisionGrid.length-1)throw new Error("Your start or end point is outside the scope of your grid.");// Start and end are the same tile. if(startX!==endX||startY!==endY){for(// End point is not an acceptable tile. -var endTile=collisionGrid[endY][endX],isAcceptable=!1,i=0;i0&&checkAdjacentNode(instance,searchNode,0,-1,1*getTileCost(searchNode.x,searchNode.y-1)),searchNode.x0&&checkAdjacentNode(instance,searchNode,-1,0,1*getTileCost(searchNode.x-1,searchNode.y)),diagonalsEnabled&&(searchNode.x>0&&searchNode.y>0&&(allowCornerCutting||isTileWalkable(collisionGrid,acceptableTiles,searchNode.x,searchNode.y-1,searchNode)&&isTileWalkable(collisionGrid,acceptableTiles,searchNode.x-1,searchNode.y,searchNode))&&checkAdjacentNode(instance,searchNode,-1,-1,1.4*getTileCost(searchNode.x-1,searchNode.y-1)),searchNode.x0&&(allowCornerCutting||isTileWalkable(collisionGrid,acceptableTiles,searchNode.x,searchNode.y-1,searchNode)&&isTileWalkable(collisionGrid,acceptableTiles,searchNode.x+1,searchNode.y,searchNode))&&checkAdjacentNode(instance,searchNode,1,-1,1.4*getTileCost(searchNode.x+1,searchNode.y-1)),searchNode.x>0&&searchNode.y0&&checkAdjacentNode(instance,searchNode,0,-1,1*getTileCost(searchNode.x,searchNode.y-1)),searchNode.x0&&checkAdjacentNode(instance,searchNode,-1,0,1*getTileCost(searchNode.x-1,searchNode.y)),diagonalsEnabled&&(searchNode.x>0&&searchNode.y>0&&(allowCornerCutting||isTileWalkable(collisionGrid,acceptableTiles,searchNode.x,searchNode.y-1,searchNode)&&isTileWalkable(collisionGrid,acceptableTiles,searchNode.x-1,searchNode.y,searchNode))&&checkAdjacentNode(instance,searchNode,-1,-1,1.4*getTileCost(searchNode.x-1,searchNode.y-1)),searchNode.x0&&(allowCornerCutting||isTileWalkable(collisionGrid,acceptableTiles,searchNode.x,searchNode.y-1,searchNode)&&isTileWalkable(collisionGrid,acceptableTiles,searchNode.x+1,searchNode.y,searchNode))&&checkAdjacentNode(instance,searchNode,1,-1,1.4*getTileCost(searchNode.x+1,searchNode.y-1)),searchNode.x>0&&searchNode.yclosestDist);i++)(!targetNode||targetCost>instance.storeList[i].costSoFar)&&(targetNode=instance.storeList[i],targetCost=instance.storeList[i].costSoFar);if(targetNode){for(var path=[];targetNode;)path.push({x:targetNode.x,y:targetNode.y}),targetNode=targetNode.parent;instance.callback(path.reverse())}else instance.callback(null)}else instance.callback(null);delete instances[instanceId],instanceQueue.shift()}else // This instance was cancelled instanceQueue.shift()}};// Private methods follow -var checkAdjacentNode=function(instance,searchNode,x,y,cost){var adjacentCoordinateX=searchNode.x+x,adjacentCoordinateY=searchNode.y+y;if((void 0===pointsToAvoid[adjacentCoordinateY]||void 0===pointsToAvoid[adjacentCoordinateY][adjacentCoordinateX])&&isTileWalkable(collisionGrid,acceptableTiles,adjacentCoordinateX,adjacentCoordinateY,searchNode)){var node=coordinateToNode(instance,adjacentCoordinateX,adjacentCoordinateY,searchNode,cost);void 0===node.list?(node.list=1,instance.openList.push(node)):searchNode.costSoFar+costc[0].length-1||n>c.length-1||e>c[0].length-1||o>c.length-1)throw new Error("Your start or end point is outside the scope of your grid.");if(t!==e||n!==o){for(var s=c[o][e],u=!1,l=0;l>1])<0;)t[e]=i,e=s;return t[e]=r},f=function(t,n,e){var o,r,i,s,u;for(null==e&&(e=p),r=t.length,i=t[u=n],o=2*n+1;oc[0].length-1||n>c.length-1||e>c[0].length-1||o>c.length-1)throw new Error("Your start or end point is outside the scope of your grid.");if(t!==e||n!==o){for(var s=c[o][e],u=!1,l=0;ls);u++)(!r||i>n.storeList[u].costSoFar)&&(r=n.storeList[u],i=n.storeList[u].costSoFar);if(r){for(var l=[];r;)l.push({x:r.x,y:r.y}),r=r.parent;n.callback(l.reverse())}else n.callback(null)}else n.callback(null);delete y[t],v.shift()}else v.shift()}};var b=function(t,n,e,o,r){e=n.x+e,o=n.y+o;void 0!==i[o]&&void 0!==i[o][e]||!O(c,f,e,o,n)||(void 0===(o=P(t,e,o,n,r)).list?(o.list=1,t.openList.push(o)):n.costSoFar+r>1])<0;)t[e]=i,e=s;return t[e]=r},f=function(t,n,e){var o,r,i,s,u;for(null==e&&(e=p),r=t.length,i=t[u=n],o=2*n+1;o closestDist ) break; + + if(!targetNode || targetCost > instance.storeList[i].costSoFar){ + targetNode = instance.storeList[i]; + targetCost = instance.storeList[i].costSoFar; + } + } + + if(targetNode){ + var path = []; + while(targetNode){ + path.push({x:targetNode.x, y:targetNode.y}) + targetNode = targetNode.parent + } + instance.callback(path.reverse()); + } + else + { + instance.callback(null); + } + } + else + { + instance.callback(null); + } + delete instances[instanceId]; instanceQueue.shift(); continue; @@ -462,6 +515,12 @@ EasyStar.js = function() { node.parent = searchNode; instance.openList.updateItem(node); } + else{ + if(!instance.storeList){ + instance.storeList = []; + } + instance.storeList.push( node ) + } } }; @@ -546,11 +605,11 @@ EasyStar.js = function() { }; } -EasyStar.TOP = 'TOP' -EasyStar.TOP_RIGHT = 'TOP_RIGHT' -EasyStar.RIGHT = 'RIGHT' -EasyStar.BOTTOM_RIGHT = 'BOTTOM_RIGHT' -EasyStar.BOTTOM = 'BOTTOM' -EasyStar.BOTTOM_LEFT = 'BOTTOM_LEFT' -EasyStar.LEFT = 'LEFT' -EasyStar.TOP_LEFT = 'TOP_LEFT' +EasyStar.TOP = 'TOP'; +EasyStar.TOP_RIGHT = 'TOP_RIGHT'; +EasyStar.RIGHT = 'RIGHT'; +EasyStar.BOTTOM_RIGHT = 'BOTTOM_RIGHT'; +EasyStar.BOTTOM = 'BOTTOM'; +EasyStar.BOTTOM_LEFT = 'BOTTOM_LEFT'; +EasyStar.LEFT = 'LEFT'; +EasyStar.TOP_LEFT = 'TOP_LEFT'; From 7e09cc1e781e9850f97da4a7cf0d8d8b591156b3 Mon Sep 17 00:00:00 2001 From: Jiminibob <15093657+Jiminibob@users.noreply.github.com> Date: Mon, 30 Aug 2021 11:32:30 +0100 Subject: [PATCH 2/2] cache nearest tile during lookup --- bin/easystar-0.4.4.js | 9 ++++----- bin/easystar-0.4.4.min.js | 2 +- src/easystar.js | 33 ++++++++++----------------------- 3 files changed, 15 insertions(+), 29 deletions(-) diff --git a/bin/easystar-0.4.4.js b/bin/easystar-0.4.4.js index 6db12f4..df5ccc6 100644 --- a/bin/easystar-0.4.4.js +++ b/bin/easystar-0.4.4.js @@ -279,13 +279,12 @@ iterationsSoFar=0);var instanceId=instanceQueue[0],instance=instances[instanceId if(0!==instance.openList.size()){var searchNode=instance.openList.pop();// Handles the case where we have found the destination if(instance.endX!==searchNode.x||instance.endY!==searchNode.y)searchNode.list=0,searchNode.y>0&&checkAdjacentNode(instance,searchNode,0,-1,1*getTileCost(searchNode.x,searchNode.y-1)),searchNode.x0&&checkAdjacentNode(instance,searchNode,-1,0,1*getTileCost(searchNode.x-1,searchNode.y)),diagonalsEnabled&&(searchNode.x>0&&searchNode.y>0&&(allowCornerCutting||isTileWalkable(collisionGrid,acceptableTiles,searchNode.x,searchNode.y-1,searchNode)&&isTileWalkable(collisionGrid,acceptableTiles,searchNode.x-1,searchNode.y,searchNode))&&checkAdjacentNode(instance,searchNode,-1,-1,1.4*getTileCost(searchNode.x-1,searchNode.y-1)),searchNode.x0&&(allowCornerCutting||isTileWalkable(collisionGrid,acceptableTiles,searchNode.x,searchNode.y-1,searchNode)&&isTileWalkable(collisionGrid,acceptableTiles,searchNode.x+1,searchNode.y,searchNode))&&checkAdjacentNode(instance,searchNode,1,-1,1.4*getTileCost(searchNode.x+1,searchNode.y-1)),searchNode.x>0&&searchNode.yclosestDist);i++)(!targetNode||targetCost>instance.storeList[i].costSoFar)&&(targetNode=instance.storeList[i],targetCost=instance.storeList[i].costSoFar);if(targetNode){for(var path=[];targetNode;)path.push({x:targetNode.x,y:targetNode.y}),targetNode=targetNode.parent;instance.callback(path.reverse())}else instance.callback(null)}else instance.callback(null);delete instances[instanceId],instanceQueue.shift()}else +if(findNearestEnabled) +// does instance have a 'nearest target' +if(instance.nearestTarget){for(var path=[],targetNode=instance.nearestTarget;targetNode;)path.push({x:targetNode.x,y:targetNode.y}),targetNode=targetNode.parent;instance.callback(path.reverse())}else instance.callback(null);else instance.callback(null);delete instances[instanceId],instanceQueue.shift()}else // This instance was cancelled instanceQueue.shift()}};// Private methods follow -var checkAdjacentNode=function(instance,searchNode,x,y,cost){var adjacentCoordinateX=searchNode.x+x,adjacentCoordinateY=searchNode.y+y;if((void 0===pointsToAvoid[adjacentCoordinateY]||void 0===pointsToAvoid[adjacentCoordinateY][adjacentCoordinateX])&&isTileWalkable(collisionGrid,acceptableTiles,adjacentCoordinateX,adjacentCoordinateY,searchNode)){var node=coordinateToNode(instance,adjacentCoordinateX,adjacentCoordinateY,searchNode,cost);void 0===node.list?(node.list=1,instance.openList.push(node)):searchNode.costSoFar+costc[0].length-1||n>c.length-1||e>c[0].length-1||o>c.length-1)throw new Error("Your start or end point is outside the scope of your grid.");if(t!==e||n!==o){for(var s=c[o][e],u=!1,l=0;ls);u++)(!r||i>n.storeList[u].costSoFar)&&(r=n.storeList[u],i=n.storeList[u].costSoFar);if(r){for(var l=[];r;)l.push({x:r.x,y:r.y}),r=r.parent;n.callback(l.reverse())}else n.callback(null)}else n.callback(null);delete y[t],v.shift()}else v.shift()}};var b=function(t,n,e,o,r){e=n.x+e,o=n.y+o;void 0!==i[o]&&void 0!==i[o][e]||!O(c,f,e,o,n)||(void 0===(o=P(t,e,o,n,r)).list?(o.list=1,t.openList.push(o)):n.costSoFar+r>1])<0;)t[e]=i,e=s;return t[e]=r},f=function(t,n,e){var o,r,i,s,u;for(null==e&&(e=p),r=t.length,i=t[u=n],o=2*n+1;oc[0].length-1||n>c.length-1||e>c[0].length-1||r>c.length-1)throw new Error("Your start or end point is outside the scope of your grid.");if(t!==e||n!==r){for(var s=c[r][e],u=!1,a=0;a>1])<0;)t[e]=i,e=s;return t[e]=o},f=function(t,n,e){var r,o,i,s,u;for(null==e&&(e=p),o=t.length,i=t[u=n],r=2*n+1;r closestDist ) break; - - if(!targetNode || targetCost > instance.storeList[i].costSoFar){ - targetNode = instance.storeList[i]; - targetCost = instance.storeList[i].costSoFar; - } - } - if(targetNode){ + // does instance have a 'nearest target' + if( instance.nearestTarget){ var path = []; + let targetNode = instance.nearestTarget; while(targetNode){ path.push({x:targetNode.x, y:targetNode.y}) targetNode = targetNode.parent @@ -515,11 +500,13 @@ EasyStar.js = function() { node.parent = searchNode; instance.openList.updateItem(node); } - else{ - if(!instance.storeList){ - instance.storeList = []; - } - instance.storeList.push( node ) + else if(findNearestEnabled) { + if(!instance.nearestTarget) { + instance.nearestTarget = searchNode; + } + else if( node.simpleDistanceToTarget < instance.nearestTarget.simpleDistanceToTarget || node.simpleDistanceToTarget === instance.nearestTarget.simpleDistanceToTarget && node.costSoFar < instance.nearestTarget.costSoFar ){ + instance.nearestTarget = node; + } } } };