【问题标题】:A* Pathfinding implementation error leads to infinite loopA* 寻路实现错误导致死循环
【发布时间】:2012-04-01 19:59:24
【问题描述】:

我根据here找到的伪代码实现了下面的A*寻路实现似乎有错误。

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);
            }
        }   
    }
}

我一定是做错了什么,因为代码会陷入无限循环,并且每当我运行它时都会使浏览器崩溃。有人可以指出我的错误吗?

【问题讨论】:

  • 我不认为您可以发布示例输入?
  • 当然,看起来像这样:FindPath(new Vector2(10, 10), new Vector2(15, 15));,其中 Vector2 是一个位置类。
  • 我的意思是你能设置一个完整的测试用例吗?我确定我可以设置一个,但你必须已经有了一个。省了我的麻烦:) - 如果我们能看到它正在尝试工作会更容易
  • 当然,去这里:www.saege.bonfx.com/0.1.3。打开你的控制台并按下 Shift-T 来测试寻路,这会触发失败。我包含了我的整个环境,因此如果您想查看其余脚本,可以查看源代码。
  • @aaaidan:我应该很快为它建立一个站点——正如你所看到的,它仍处于起步阶段。同时,我在 Roguelike Wiki 上建立了一个页面(这个游戏是一个 roguelike),你可以在这里找到它:www.roguebasin.roguelikedevelopment.org/index.php/Saege。不幸的是,该页面也有点过时了,因为自从我上一次更新大约一周前以来,我已经取得了很大的进步。不过,我会在不久的将来某个时候更新它。感谢您的兴趣!

标签: javascript path-finding a-star


【解决方案1】:

我会用我找到的点来更新这个答案。

  • 首先,我认为没有办法逃脱您的外部循环 环境。您有一个 console.log 而不是 return 语句,您在此处发布的示例中确实有该语句。 console.log(path); 而不是 return path;

  • 您没有检查已关闭节点的已关闭列表。因此,一旦您评估了打开列表中某个节点的状态,它就会被推送到关闭列表中,但您对该列表什么也不做。没有什么可以阻止您将关闭列表上的节点再次添加到打开列表中。您只是检查打开列表以防止多次添加同一节点。 (尽管您在此处发布的示例代码表明您是)

这些东西的组合看起来会无限次产生相同的路径。

还需要指出的是,您的示例代码缩进不当,因此看起来很多代码不在 8 个邻居检查循环内。

【讨论】:

  • 那是因为我只在 open_list.length() 大于 0 时循环。
  • 是的,但您想在找到路径后立即退出。这就是 A* 算法使用启发式算法的原因;实现快速收敛。
  • 尽管如此,算法应该仍然有效。不过,我会改变它。
  • 测试将使用其中的 return 语句。我实际上从中得到了一条出路。忘记检查封闭列表允许您遵循循环路径,这显然是这里发生的事情。
【解决方案2】:

您似乎忘记从搜索中排除不可访问和已关闭的节点。

【讨论】:

  • 我没有忘记,我刚刚删除了该代码,因为它引用了一些我不想在这里包含的结构,主要是因为它们很长。很抱歉没有澄清。
  • @ElliotBonneville 嗯,这是代码中非常重要的部分,尤其是封闭节点,这是避免无限递归所必需的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-06
  • 1970-01-01
相关资源
最近更新 更多