diff --git a/astar.js b/astar.js index 8a25115..e919920 100644 --- a/astar.js +++ b/astar.js @@ -34,18 +34,18 @@ function getHeap() { } var astar = { - /** - * Perform an A* Search on a graph given a start and end node. - * @param {Graph} graph - * @param {GridNode} start - * @param {GridNode} end - * @param {Object} [options] - * @param {bool} [options.closest] Specifies whether to return the - path to the closest node if the target is unreachable. - * @param {Function} [options.heuristic] Heuristic function (see - * astar.heuristics). - */ - search: function(graph, start, end, options) { +/** +* Perform an A* Search on a graph given a start and end node. +* @param {Graph} graph +* @param {GridNode} start +* @param {GridNode} end +* @param {Object} [options] +* @param {bool} [options.closest] Specifies whether to return the +path to the closest node if the target is unreachable. +* @param {Function} [options.heuristic] Heuristic function (see +* astar.heuristics). +*/ +search: function(graph, start, end, options) { graph.cleanDirty(); options = options || {}; var heuristic = options.heuristic || astar.heuristics.manhattan; @@ -53,99 +53,101 @@ var astar = { var openHeap = getHeap(); var closestNode = start; // set the start node to be the closest if required - + var closedList = []; start.h = heuristic(start, end); - graph.markDirty(start); openHeap.push(start); - while (openHeap.size() > 0) { + while(openHeap.size() > 0) { - // Grab the lowest f(x) to process next. Heap keeps this sorted for us. - var currentNode = openHeap.pop(); + // Grab the lowest f(x) to process next. Heap keeps this sorted for us. + var currentNode = openHeap.pop(); - // End case -- result has been found, return the traced path. - if (currentNode === end) { - return pathTo(currentNode); - } + // End case -- result has been found, return the traced path. + if(currentNode === end) { + while(closedList.length>0)closedList.pop().closed = false; + return pathTo(currentNode); + } - // Normal case -- move currentNode from open to closed, process each of its neighbors. - currentNode.closed = true; + // Normal case -- move currentNode from open to closed, process each of its neighbors. + currentNode.closed = true; + closedList.push(currentNode); - // Find all neighbors for the current node. - var neighbors = graph.neighbors(currentNode); + // Find all neighbors for the current node. + var neighbors = graph.neighbors(currentNode); - for (var i = 0, il = neighbors.length; i < il; ++i) { - var neighbor = neighbors[i]; + for (var i = 0, il = neighbors.length; i < il; ++i) { + var neighbor = neighbors[i]; - if (neighbor.closed || neighbor.isWall()) { - // Not a valid node to process, skip to next neighbor. - continue; - } + if (neighbor.closed || neighbor.isWall()) { + // Not a valid node to process, skip to next neighbor. + continue; + } - // The g score is the shortest distance from start to current node. - // We need to check if the path we have arrived at this neighbor is the shortest one we have seen yet. - var gScore = currentNode.g + neighbor.getCost(currentNode); - var beenVisited = neighbor.visited; - - if (!beenVisited || gScore < neighbor.g) { - - // Found an optimal (so far) path to this node. Take score for node to see how good it is. - neighbor.visited = true; - neighbor.parent = currentNode; - neighbor.h = neighbor.h || heuristic(neighbor, end); - neighbor.g = gScore; - neighbor.f = neighbor.g + neighbor.h; - graph.markDirty(neighbor); - if (closest) { - // If the neighbour is closer than the current closestNode or if it's equally close but has - // a cheaper path than the current closest node then it becomes the closest node - if (neighbor.h < closestNode.h || (neighbor.h === closestNode.h && neighbor.g < closestNode.g)) { - closestNode = neighbor; + // The g score is the shortest distance from start to current node. + // We need to check if the path we have arrived at this neighbor is the shortest one we have seen yet. + var gScore = currentNode.g + neighbor.getCost(currentNode); + var beenVisited = neighbor.visited; + + if (!beenVisited || gScore < neighbor.g) { + + // Found an optimal (so far) path to this node. Take score for node to see how good it is. + neighbor.visited = true; + neighbor.parent = currentNode; + neighbor.h = neighbor.h || heuristic(neighbor, end); + neighbor.g = gScore; + neighbor.f = neighbor.g + neighbor.h; + graph.markDirty(neighbor); + if (closest) { + // If the neighbour is closer than the current closestNode or if it's equally close but has + // a cheaper path than the current closest node then it becomes the closest node + if (neighbor.h < closestNode.h || (neighbor.h === closestNode.h && neighbor.g < closestNode.g)) { + closestNode = neighbor; + } + } + + if (!beenVisited) { + // Pushing to heap will put it in proper place based on the 'f' value. + openHeap.push(neighbor); + } else { + // Already seen the node, but since it has been rescored we need to reorder it in the heap + openHeap.rescoreElement(neighbor); + } } - } - - if (!beenVisited) { - // Pushing to heap will put it in proper place based on the 'f' value. - openHeap.push(neighbor); - } else { - // Already seen the node, but since it has been rescored we need to reorder it in the heap - openHeap.rescoreElement(neighbor); - } } - } } + while(closedList.length>0)closedList.pop().closed = false; if (closest) { - return pathTo(closestNode); + return pathTo(closestNode); } // No result was found - empty array signifies failure to find path. return []; - }, - // See list of heuristics: http://theory.stanford.edu/~amitp/GameProgramming/Heuristics.html - heuristics: { +}, +// See list of heuristics: http://theory.stanford.edu/~amitp/GameProgramming/Heuristics.html +heuristics: { manhattan: function(pos0, pos1) { - var d1 = Math.abs(pos1.x - pos0.x); - var d2 = Math.abs(pos1.y - pos0.y); - return d1 + d2; + var d1 = Math.abs(pos1.x - pos0.x); + var d2 = Math.abs(pos1.y - pos0.y); + return d1 + d2; }, diagonal: function(pos0, pos1) { - var D = 1; - var D2 = Math.sqrt(2); - var d1 = Math.abs(pos1.x - pos0.x); - var d2 = Math.abs(pos1.y - pos0.y); - return (D * (d1 + d2)) + ((D2 - (2 * D)) * Math.min(d1, d2)); + var D = 1; + var D2 = Math.sqrt(2); + var d1 = Math.abs(pos1.x - pos0.x); + var d2 = Math.abs(pos1.y - pos0.y); + return (D * (d1 + d2)) + ((D2 - (2 * D)) * Math.min(d1, d2)); } - }, - cleanNode: function(node) { +}, +cleanNode:function(node){ node.f = 0; node.g = 0; node.h = 0; node.visited = false; node.closed = false; node.parent = null; - } +} }; /** @@ -401,4 +403,4 @@ return { Graph: Graph }; -}); \ No newline at end of file +});