A *寻路问题

时间:2014-04-14 00:07:54

标签: java

我查看了很多关于A *寻路的文章,看了伪代码后,我试着自己制作。

我有一个Node类:

private int x, y;

//The cost of movement (g) and the heuristic (h)
private int g;

private Node parent;

public Node(int x, int y) {
    this.x = x;
    this.y = y;
}

public Node(int x, int y, Node parent) {
    this.x = x;
    this.y = y;
    this.parent = parent;
    this.g = parent.getG() + 1;
}

public boolean equals(Node node) {
    return (this.x == node.getX() && this.y == node.getY() && this.parent.equals(node.getParent()));
}

public int getX() {
    return x;
}

public void setX(int x) {
    this.x = x;
}

public int getY() {
    return y;
}

public void setY(int y) {
    this.y = y;
}

public Node getParent() {
    return parent;
}

public void setParent(Node parent) {
    this.parent = parent;
}

public int getF(Node goal) {
    return g + getH(goal);
}

public int getG() {
    return g;
}

public void setG(int g) {
    this.g = g;
}

public int getH(Node goal) {
    int dx = Math.abs(this.x - goal.getX());
    int dy = Math.abs(this.y - goal.getY());
    return (dx + dy);
}

}

寻路:

public Path getPath(Node start, Node goal) {
    ArrayList<Node> openset = new ArrayList<Node>();
    ArrayList<Node> closedset = new ArrayList<Node>();

    //Add current position to open set
    openset.add(start);

    while(!openset.isEmpty()) {
        //Current node = node with lowest F score
        Node current = getNodeWithLowestScore(openset, goal);
        closedset.add(current);
        openset.remove(current);

        if(closedset.contains(goal)) {
            System.out.println("PATH FOUND.");
            break;
        }

        ArrayList<Node> adjacentNodes = getAdjacentNodes(current, closedset);

        for(Node n : adjacentNodes) {
            if(closedset.contains(n)) {
                continue;
            }

            if(!openset.contains(n)) {
                n.setParent(current);
                openset.add(n);
            }else{
                if(n.getF(goal) > (current.getG() + n.getH(goal))) {
                    n.setParent(current);
                }
            }
        }
    }
    return null;
}

public Node getNodeWithLowestScore(ArrayList<Node> openset, Node goal) {
    Node lowest = openset.get(0);

    for(int i = 0; i < openset.size(); i++) {

        Node n = openset.get(i);
        int nscore = n.getF(goal);

        if(nscore < lowest.getF(goal)) {
            lowest = n;
        }
    }
    return lowest;
}

public ArrayList<Node> getAdjacentNodes(Node node, ArrayList<Node> closedset) {
    ArrayList<Node> nodes = new ArrayList<Node>();

    nodes.add(new Node(node.getX() + 1, node.getY(), node));
    nodes.add(new Node(node.getX() - 1, node.getY(), node));
    nodes.add(new Node(node.getX(), node.getY() + 1, node));
    nodes.add(new Node(node.getX(), node.getY() - 1, node));

    for(int i = 0; i < nodes.size(); i++) {
        if(nodes.get(i) == null || closedset.contains(nodes.get(i))) {
            nodes.remove(i);
        }
    }
    return nodes;
}

}

它没有工作,如果我打印出打开或关闭设置的大小,数字就会飙升得那么高。我用30x30 2D网格测试了这个,从10,10(开始)到30,30(目标)。

到目前为止我所做的改变:

getAdjacentNodes方法 - &gt;

    ArrayList<Node> nodes = new ArrayList<Node>();

    nodes.add(new Node(node.getX() + 1, node.getY(), node));
    nodes.add(new Node(node.getX() - 1, node.getY(), node));
    nodes.add(new Node(node.getX(), node.getY() + 1, node));
    nodes.add(new Node(node.getX(), node.getY() - 1, node));

    for(int i = 0; i < nodes.size(); i++) {
        int x = nodes.get(i).getX();
        int y = nodes.get(i).getY();
        if(!((x > 0 && x < 30) && (y > 0 && y < 30))) {
            nodes.remove(i);
        }
    }
    return nodes;
}

getPath方法 - &gt; (在while内部(openset不为空)方法)

        Node current = getNodeWithLowestScore(openset, goal);
        openset.remove(current);

        if(current.equals(goal)) {
            System.out.println("PATH FOUND.");
            break;
        }else{
            closedset.add(current);
            ArrayList<Node> adjacentNodes = getAdjacentNodes(current, closedset);

            for(Node n : adjacentNodes) {
                if(closedset.contains(n) && (n.getG() > current.getG())) {
                    n.setG(current.getG());
                    n.setParent(current);
                }else if(openset.contains(n) && (n.getG() > current.getG())) {
                    n.setG(current.getG());
                    n.setParent(current);
                }else{
                    openset.add(n);
                }
            }
        }
    }

1 个答案:

答案 0 :(得分:0)

您的主要问题是

中的一个小细节
public boolean equals(Node node) {
    return (this.x == node.getX() && this.y == node.getY() 
         && this.parent.equals(node.getParent()));
}

结合使用
if(!openset.contains(n)) {
    n.setParent(current);
    openset.add(n);
}

很难发现,我花了一段时间来弄明白。

ArrayList<>().contains(Object o)在内部使用(在indexOf的帮助下)方法Object().equals(Object o),该方法将Object作为参数。

您的Node().equals(Node n)方法使用Node参数,因此不会覆盖您要覆盖的Object().equals(Object o)方法。

要解决此问题,您应该将方法更改为:

public boolean equals(Object o) {
    if(!(o instanceof Node)) return false;
    return (this.x == node.getX() && this.y == node.getY() 
         && this.parent.equals(node.getParent()));
}

我不知道您的代码是否存在更多问题,因为我还没有真正了解您如何调用它以及Path类的外观等等。我尝试从(0,0)到(3,2),至少它终止了,修复后尺寸似乎更小。

虽然我在调用Node().getParent()时发生了一些NullPointerExceptions,也许你应该看一下。例如,在您的equals(Object o) this.parent可能为null时,您应该事先检查它。

祝你好运!