mirror of
https://github.moeyy.xyz/https://github.com/trekhleb/javascript-algorithms.git
synced 2024-11-10 11:09:43 +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