I seem to have a error in the following A* pathfinding implementation, which I implemented based on the pseudocode found here.
function NodeList() {
this.nodes = [];
this.add = function(givenNode) {
for(var i = 0; i<this.nodes.length; i++) {
if(this.nodes[i].f <= givenNode.f) {
this.nodes.splice(i, 0, givenNode);
return;
}
}
this.nodes.push(givenNode);
}
this.pop = function() {
return this.nodes.splice(this.nodes.length-1, 1)[0];
}
this.getNode = function(givenNode) {
for (var i = 0; i < this.nodes.length; i++) {
if (this.nodes[i].pos.x == givenNode.pos.x && this.nodes[i].pos.y == givenNode.pos.y) {
return this.nodes.splice(i, 1)[0];
}
}
return -1;
}
this.hasNode = function(givenNode) {
for (var i = 0; i < this.nodes.length; i++) {
if (this.nodes[i].pos.x == givenNode.pos.x && this.nodes[i].pos.y == givenNode.pos.y) {
return true;
}
}
return false;
}
this.length = function() {
return this.nodes.length;
}
}
function PathNode(pos, f, g, h) {
this.pos = pos;
this.f = f;
this.g = g;
this.h = h;
}
function FindPath(start, goal) {
var x_array = [0, -1, -1, -1, 0, 1, 1, 1];
var y_array = [1, 1, 0, -1, -1, -1, 0, 1];
var open_list = new NodeList();
open_list.add(new PathNode(start, start.Manhattan(goal) * 10, 0, start.Manhattan(goal) * 10));
var closed_list = new NodeList();
while(open_list.length() > 0) {
var currentNode = open_list.pop();
if(currentNode.pos.x == goal.x && currentNode.pos.y == goal.y) {
var path = [];
var curNode = currentNode;
while(true) {
path.push(curNode);
curNode = curNode.parent;
if(curNode == undefined) break;
}
return(path);
}
closed_list.add(currentNode);
for(var i=0; i<8; i++) {
var neighbor = new PathNode(new Vector2(currentNode.pos.x + x_array[i], currentNode.pos.y + y_array[i]), 0, 0, 0);
if(map.tiles[neighbor.pos.x][neighbor.pos.y].blocked == true) {
canContinue = false;
}
for(var j=0; j<objects.length; j++) {
if(objects[j].blocks == true && objects[j].position.x == neighbor.pos.x && objects[j].position.y == neighbor.pos.y) canContinue = false;
}
if(closed_list.hasNode(neighbor)) continue;
if(!canContinue) continue;
if(open_list.hasNode(neighbor)) { // if open_list contains neighbor, do this:
neighbor = open_list.getNode(neighbor);
neighbor.parent == currentNode;
neighbor.g = currentNode.g + 10;
neighbor.h = neighbor.pos.Manhattan(goal) * 10;
neighbor.f = neighbor.g + neighbor.h;
open_list.add(neighbor);
} else { // otherwise it's not on the open list, do this:
if(neighbor.g < currentNode.g) {
neighbor.parent = currentNode;
neighbor.g = currentNode.g + 10;
neighbor.f = neighbor.g + neighbor.h;
}
open_list.add(neighbor);
}
}
}
}
I must be doing something wrong, because the code spirals into an infinite loop and crashes the browser whenever I run it. Could somebody point my error(s)?
I'll update this answer with points as I find them.
First of all I see no way to escape the outer loop in your
environment. You have a console.log instead of a return statement, which you do have in your example posted here. console.log(path);
instead of return path;
You are not checking the closed list for nodes which have been closed. So once you have assessed the state of a node on the open list, it's pushed onto the closed list but you do nothing with that list. There is nothing preventing you from adding a node on the closed list to the open list again. You are only checking the open list for preventing the addition of the same node more than once. (Though your example code posted here shows that you are)
The combination of these things look like it will produce the same path infinitely many times.
Also just to point out, your example code is improperly indented so it looks like a lot of that code is not inside the 8 neighbours checking loop.