mirror of
https://github.moeyy.xyz/https://github.com/trekhleb/javascript-algorithms.git
synced 2024-11-13 06:23:00 +08:00
Merge 8ada0862e6
into ca3d16dcce
This commit is contained in:
commit
7c68ee1c77
@ -0,0 +1,147 @@
|
|||||||
|
var astar = {
|
||||||
|
init: function(grid) {
|
||||||
|
for(var x = , xl = grid.length; x < xl; x++) {
|
||||||
|
for(var y = , yl = grid[x].length; y < yl; y++) {
|
||||||
|
var node = grid[x][y];
|
||||||
|
node.f = ;
|
||||||
|
node.g = ;
|
||||||
|
node.h = ;
|
||||||
|
node.cost = 1;
|
||||||
|
node.visited = false;
|
||||||
|
node.closed = false;
|
||||||
|
node.parent = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
heap: function() {
|
||||||
|
return new BinaryHeap(function(node) {
|
||||||
|
return node.f;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
search: function(grid, start, end, diagonal, heuristic) {
|
||||||
|
astar.init(grid);
|
||||||
|
heuristic = heuristic || astar.manhattan;
|
||||||
|
diagonal = !!diagonal;
|
||||||
|
|
||||||
|
var openHeap = astar.heap();
|
||||||
|
|
||||||
|
openHeap.push(start);
|
||||||
|
|
||||||
|
while(openHeap.size() > ) {
|
||||||
|
|
||||||
|
// 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) {
|
||||||
|
var curr = currentNode;
|
||||||
|
var ret = [];
|
||||||
|
while(curr.parent) {
|
||||||
|
ret.push(curr);
|
||||||
|
curr = curr.parent;
|
||||||
|
}
|
||||||
|
return ret.reverse();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Normal case -- move currentNode from open to closed, process each of its neighbors.
|
||||||
|
currentNode.closed = true;
|
||||||
|
|
||||||
|
// Find all neighbors for the current node. Optionally find diagonal neighbors as well (false by default).
|
||||||
|
var neighbors = astar.neighbors(grid, currentNode, diagonal);
|
||||||
|
|
||||||
|
for(var i=, 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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.cost;
|
||||||
|
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.pos, end.pos);
|
||||||
|
neighbor.g = gScore;
|
||||||
|
neighbor.f = neighbor.g + neighbor.h;
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// No result was found - empty array signifies failure to find path.
|
||||||
|
return [];
|
||||||
|
},
|
||||||
|
manhattan: function(pos0, pos1) {
|
||||||
|
// See list of heuristics: http://theory.stanford.edu/~amitp/GameProgramming/Heuristics.html
|
||||||
|
|
||||||
|
var d1 = Math.abs (pos1.x - pos0.x);
|
||||||
|
var d2 = Math.abs (pos1.y - pos0.y);
|
||||||
|
return d1 + d2;
|
||||||
|
},
|
||||||
|
neighbors: function(grid, node, diagonals) {
|
||||||
|
var ret = [];
|
||||||
|
var x = node.x;
|
||||||
|
var y = node.y;
|
||||||
|
|
||||||
|
// West
|
||||||
|
if(grid[x-1] && grid[x-1][y]) {
|
||||||
|
ret.push(grid[x-1][y]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// East
|
||||||
|
if(grid[x+1] && grid[x+1][y]) {
|
||||||
|
ret.push(grid[x+1][y]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// South
|
||||||
|
if(grid[x] && grid[x][y-1]) {
|
||||||
|
ret.push(grid[x][y-1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// North
|
||||||
|
if(grid[x] && grid[x][y+1]) {
|
||||||
|
ret.push(grid[x][y+1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (diagonals) {
|
||||||
|
|
||||||
|
// Southwest
|
||||||
|
if(grid[x-1] && grid[x-1][y-1]) {
|
||||||
|
ret.push(grid[x-1][y-1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Southeast
|
||||||
|
if(grid[x+1] && grid[x+1][y-1]) {
|
||||||
|
ret.push(grid[x+1][y-1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Northwest
|
||||||
|
if(grid[x-1] && grid[x-1][y+1]) {
|
||||||
|
ret.push(grid[x-1][y+1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Northeast
|
||||||
|
if(grid[x+1] && grid[x+1][y+1]) {
|
||||||
|
ret.push(grid[x+1][y+1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
};
|
27
src/algorithms/search/a-star searching/README.md
Normal file
27
src/algorithms/search/a-star searching/README.md
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
This is the actual implementation of the algorithm. I will do my best to explain what is going on, but feel free to just look at the source of the example, or just download astar.js.
|
||||||
|
|
||||||
|
There are three functions that we keep track of for nodes that we look at:
|
||||||
|
|
||||||
|
g(x): The total cost of getting to that node (pretty straightforward). If we reach a node for the first time or reach a node in less time than it currently took, then update the g(x) to the cost to reach this node.
|
||||||
|
h(x): The estimated time to reach the finish from the current node. This is also called a heuristic. We online need to update this if it is not set already, since the distance to the finish will not change even if the path we took to arrive at a node changes. Note: There are many different ways to guess how far you are from the end, I use the Manhattan distance in this implementation.
|
||||||
|
f(x): Simply g(x) + h(x). The lower the f(x), the better. Think about it like this: the best node is one that takes the least total amount of time to arrive at and to get to the end. So, a node that took only 1 step to arrive at and 5 to get to the end is more ideal than one that took 10 to arrive and and only 1 to get to the end.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
PsuedoCode:
|
||||||
|
push startNode onto openList
|
||||||
|
while(openList is not empty) {
|
||||||
|
currentNode = find lowest f in openList
|
||||||
|
if currentNode is final, return the successful path
|
||||||
|
push currentNode onto closedList and remove from openList
|
||||||
|
foreach neighbor of currentNode {
|
||||||
|
if neighbor is not in openList {
|
||||||
|
save g, h, and f then save the current parent
|
||||||
|
add neighbor to openList
|
||||||
|
}
|
||||||
|
if neighbor is in openList but the current g is better than previous g {
|
||||||
|
save g and f, then save the current parent
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user