Created
January 2, 2012 02:44
-
-
Save huckfinnaafb/1549077 to your computer and use it in GitHub Desktop.
A*pathfinding implementation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
A* Pathfinding | |
*/ | |
function Path(map, start, end) { | |
// Sets | |
var open = [], | |
closed = []; | |
// Create node for start | |
var begin; | |
begin = new Path.Node(start); | |
begin.gscore = 0; | |
begin.hscore = Path.heuristic(start, end); | |
begin.fscore = begin.gscore + begin.hscore; | |
// Open set begins with start node | |
Path.append(open, begin); | |
while (open.length) { | |
// Node with lowest fscore | |
var current = _.min(open, function (element) { | |
return element.fscore; | |
}); | |
// Current node not at the end of path | |
if (!Vector.isEqual(current.vector, end)) { | |
// Swap sets | |
Path.remove(open, current); | |
Path.append(closed, current); | |
// Loop through immediate neighbors | |
var j, neighbors = Path.neighbors(current); | |
for (j = 0; j < neighbors.length; j += 1) { | |
// Shorthand | |
var neighbor = neighbors[j]; | |
// Tentative move cost | |
var cost = current.gscore + 1; // 1 is guaranteed distance between two neighboring tiles for now | |
if (Path.isMember(open, neighbor) && cost < neighbor.gscore) { | |
Path.remove(open, neighbor); | |
} | |
if (Path.isMember(closed, neighbor) && cost < neighbor.gscore) { | |
Path.remove(closed, neighbor); | |
} | |
if (!Path.isMember(closed, neighbor) && !Path.isMember(open, neighbor)) { | |
Path.append(open, neighbor); | |
neighbor.hscore = Path.heuristic(neighbor.vector, end); | |
neighbor.gscore = cost; | |
neighbor.fscore = neighbor.gscore + neighbor.hscore; | |
neighbor.parent = current; | |
} | |
} | |
} else { | |
return Path.reconstruct(current); | |
} | |
} | |
} | |
Path.Node = function (vector) { | |
this.parent = undefined; | |
this.gscore = undefined; | |
this.hscore = undefined; | |
this.fscore = undefined; // gscore + hscore | |
this.vector = new Vector(vector.x, vector.y); | |
}; | |
Path.append = function (collection, node) { | |
return collection.push(node); | |
}; | |
Path.remove = function (collection, node) { | |
return collection.remove(Path.find(collection, node)); | |
}; | |
Path.find = function (collection, node) { | |
var i; | |
for (i = 0; i < collection.length; i += 1) { | |
if (Vector.isEqual(collection[i].vector, node.vector)) { | |
return i; | |
} | |
} | |
}; | |
Path.neighbors = function (node) { | |
return [ | |
new Path.Node(Vector.add(node.vector, Vector.N)), | |
new Path.Node(Vector.add(node.vector, Vector.W)), | |
new Path.Node(Vector.add(node.vector, Vector.S)), | |
new Path.Node(Vector.add(node.vector, Vector.E)) | |
]; | |
}; | |
Path.heuristic = function (a, b) { | |
return Vector.distance(a, b); | |
}; | |
Path.isMember = function (collection, node) { | |
return Path.find(collection, node) > -1; | |
}; | |
Path.reconstruct = function (node) { | |
var path = []; | |
while (typeof node.parent !== 'undefined') { | |
path.push(node.vector); | |
node = node.parent; | |
} | |
return path.reverse(); | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment