var AStar = (function () {
/**
* A* (A-Star) algorithm for a path finder
* @author Andrea Giammarchi
* @license Mit Style License
*/
function diagonalSuccessors($N, $S, $E, $W, N, S, E, W, grid, rows, cols, result, i) {
if($N) {
$E && !grid[N][E] && (result[i++] = {x:E, y:N});
$W && !grid[N][W] && (result[i++] = {x:W, y:N});
}
if($S){
$E && !grid[S][E] && (result[i++] = {x:E, y:S});
$W && !grid[S][W] && (result[i++] = {x:W, y:S});
}
return result;
}
function diagonalSuccessorsFree($N, $S, $E, $W, N, S, E, W, grid, rows, cols, result, i) {
$N = N > -1;
$S = S < rows;
$E = E < cols;
$W = W > -1;
if($E) {
$N && !grid[N][E] && (result[i++] = {x:E, y:N});
$S && !grid[S][E] && (result[i++] = {x:E, y:S});
}
if($W) {
$N && !grid[N][W] && (result[i++] = {x:W, y:N});
$S && !grid[S][W] && (result[i++] = {x:W, y:S});
}
return result;
}
function nothingToDo($N, $S, $E, $W, N, S, E, W, grid, rows, cols, result, i) {
return result;
}
function successors(find, x, y, grid, rows, cols){
var
N = y - 1,
S = y + 1,
E = x + 1,
W = x - 1,
$N = N > -1 && !grid[N][x],
$S = S < rows && !grid[S][x],
$E = E < cols && !grid[y][E],
$W = W > -1 && !grid[y][W],
result = [],
i = 0
;
$N && (result[i++] = {x:x, y:N});
$E && (result[i++] = {x:E, y:y});
$S && (result[i++] = {x:x, y:S});
$W && (result[i++] = {x:W, y:y});
return find($N, $S, $E, $W, N, S, E, W, grid, rows, cols, result, i);
}
function diagonal(start, end, f1, f2) {
return f2(f1(start.x - end.x), f1(start.y - end.y));
}
function euclidean(start, end, f1, f2) {
var
x = start.x - end.x,
y = start.y - end.y
;
return f2(x * x + y * y);
}
function manhattan(start, end, f1, f2) {
return f1(start.x - end.x) + f1(start.y - end.y);
}
function AStar(grid, start, end, f) {
var
cols = grid[0].length,
rows = grid.length,
limit = cols * rows,
f1 = Math.abs,
f2 = Math.max,
list = {},
result = [],
open = [{x:start[0], y:start[1], f:0, g:0, v:start[0]+start[1]*cols}],
length = 1,
adj, distance, find, i, j, max, min, current, next
;
end = {x:end[0], y:end[1], v:end[0]+end[1]*cols};
switch (f) {
case "Diagonal":
find = diagonalSuccessors;
case "DiagonalFree":
distance = diagonal;
break;
case "Euclidean":
find = diagonalSuccessors;
case "EuclideanFree":
f2 = Math.sqrt;
distance = euclidean;
break;
default:
distance = manhattan;
find = nothingToDo;
break;
}
find || (find = diagonalSuccessorsFree);
do {
max = limit;
min = 0;
for(i = 0; i < length; ++i) {
if((f = open[i].f) < max) {
max = f;
min = i;
}
};
current = open.splice(min, 1)[0];
if (current.v != end.v) {
--length;
next = successors(find, current.x, current.y, grid, rows, cols);
for(i = 0, j = next.length; i < j; ++i){
(adj = next[i]).p = current;
adj.f = adj.g = 0;
adj.v = adj.x + adj.y * cols;
if(!(adj.v in list)){
adj.f = (adj.g = current.g + distance(adj, current, f1, f2)) + distance(adj, end, f1, f2);
open[length++] = adj;
list[adj.v] = 1;
}
}
} else {
i = length = 0;
do {
result[i++] = [current.x, current.y];
} while (current = current.p);
result.reverse();
}
} while (length);
return result;
}
return AStar;
}());