【发布时间】:2018-08-09 15:46:59
【问题描述】:
我使用这个伪代码在 java 中编写了一个 A* 寻路算法。在某些情况下它可以正常工作,但在某些情况下它会永远挂起并将无限数量的节点添加到打开列表中。这是我执行伪代码的问题,还是伪代码本身的问题?我尝试了一堆打印语句进行调试,但我什至无法确定问题。这是我的 A* 代码:
import java.awt.Point;
import java.util.ArrayList;
import java.util.Collections;
public class AStar {
Point[] adjacents = {new Point(0,1),new Point(1,1), new Point(1,0), new Point(1,-1), new Point(0,-1), new Point(-1,-1), new Point(-1,0), new Point(-1,1)};
public Node[] calculatePH(Node startNode, Node endNode, int[][] map) {
// Initialize both open and closed list
ArrayList<Node> open = new ArrayList<Node>();
ArrayList<Node> closed = new ArrayList<Node>();
// Add the start node
open.add(startNode);
// Loop until you find the end
while(!open.isEmpty()) {
// Get the current node
Node currentNode = open.get(0);
for(Node n : open) {
if(n.f<currentNode.f) {
currentNode = n;
}
}
open.remove(currentNode);
closed.add(currentNode);
// Found the goal
if(currentNode.equals(endNode)) {
ArrayList<Node> path = new ArrayList<Node>();
Node current = currentNode;
while(current!=null) {
path.add(current);
current = current.parent;
}
Collections.reverse(path);
return path.toArray(new Node[path.size()]);
}
// Generate children
ArrayList<Node> children = new ArrayList<Node>();
for(Point p : adjacents) {
Point childpos = currentNode.getLocation();
childpos.translate(p.x, p.y);
//Checks to ensure that the node is on the actual field, so we don't ram into a field tech lol
if((childpos.y>(map.length-1)) || (childpos.y<0) || (childpos.x>(map[0].length-1)) || (childpos.x<0)) {
continue;
}
//Checks to ensure that the node is "walkable", or basically just not inside a wall or object.
if(map[childpos.y][childpos.x] != 0) {
continue;
}
Node child = new Node(currentNode,childpos);
children.add(child);
}
for(Node n : children) {
// Child is on the closedList
if(closed.indexOf(n)>-1) {
continue;
}
n.g = currentNode.g + currentNode.distance(n);
n.h = n.distance(endNode);
n.f = n.g+n.h;
boolean inFlag = false;
for(Node m : open) {
if((n==m) && (n.g>m.g)) {
inFlag = true;
}
}
if(!inFlag) {
open.add(n);
}
}
}
return new Node[0];
}
}
还有 Node 类,它是 java.awt.Point 的子类,带有一些额外的东西。
import java.awt.Point;
import java.util.ArrayList;
public class Node extends Point { //Extends Point for conveinince and
//neatness. Maybe just use a has-a relationship if this breaks.
public Node(Node Parent, Point loc) {
super(loc);
this.parent = Parent;
}
public Node(Point loc) {
super(loc);
}
void translate(Point p){
translate(p.x,p.y);
}
public Node parent;
public double f;
public double g;
public double h;
public String toString() {
return "("+x+","+y+")";
}
}
我正在使用一个 27 高和 54 宽的迷宫,起点在 (0,0),目标在 (24,24),目前有两个障碍物。在这种情况下,它工作正常:
但在这种情况下,它会永远挂起。唯一的区别是第二个障碍物向下延伸了 1 行。
任何帮助都将不胜感激,如果我应该更改问题或添加更多信息,请告诉我。
编辑:它不漂亮,但这里是 int[][] 包含 non-functioning 版本的地图数据。
int[][] map ={
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,1,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,1,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
};
【问题讨论】:
-
您是否尝试过单步执行代码,尤其是当它开始向列表中添加数百万个节点时,看看为什么?
-
请提供导致其失败的地图(硬编码数据)进行测试。
-
您将 Node 对象插入到 ArrayLists 中,但它们没有覆盖
equals方法。检查您是否真的可以排除圆形路径。 minimal reproducible example 会很有帮助。 -
您是否知道在第一次运行时您在
if(n.f<currentNode.f)中使用f在它被初始化之前? -
@c0der 是的,我可能应该初始化它,但默认值是 0,无论如何都是正确的。