我查看了很多关于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);
}
}
}
}
答案 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时,您应该事先检查它。