A*搜索算法死循环
A* search algorithm infinite loop
正如标题所说,这个 A* 搜索算法永远不会停止搜索。我正在尝试为 point-click 在 2D tile-based 游戏中行走创建一个有效的 A* 搜索算法,一些方块是 walk-able 而一些方块是实心的。
PathFinder.java:
public class PathFinder {
public static List<Node> findPath(Map map, int sx, int sy, int dx, int dy) {
if(map.getTile(dx, dy).isSolid()) return null;
Node startNode = new Node(new Vector2i(sx, sy), null, 0, 0);
Vector2i goal = new Vector2i(dx, dy);
List<Node> open = new ArrayList<>();
HashSet<Node> closed = new HashSet<>();
open.add(startNode);
while(open.size() > 0) {
Node currentNode = open.get(0);
for(int i = 1; i < open.size(); i++) {
if(open.get(i).fCost < currentNode.fCost ||
open.get(i).fCost == currentNode.fCost && open.get(i).hCost < currentNode.hCost) {
currentNode = open.get(i);
}
}
open.remove(currentNode);
closed.add(currentNode);
if(currentNode.tile == goal){
System.out.println("returning path!");
return retracePath(startNode, currentNode);
}
for(Tile tile : map.getNeighbors(currentNode)) {
Vector2i neighbor = new Vector2i(tile.getTileX(), tile.getTileY());
if(tile.isSolid() || getNodeInHashSetForPosition(neighbor, closed) != null) {
continue;
}
double gCost = currentNode.gCost + getNodeDistance(currentNode.tile, neighbor);
if(currentNode.gCost < gCost || !vecInList(neighbor, open)) {
double hCost = getNodeDistance(neighbor, goal);
Node node = new Node(neighbor, currentNode, gCost, hCost);
if(!open.contains(node)) {
open.add(node);
}
}
}
}
return null;
}
private static List<Node> retracePath(Node startNode, Node endNode) {
List<Node> path = new ArrayList<>();
Node currentNode = endNode;
while(currentNode != startNode) {
path.add(currentNode);
currentNode = currentNode.parent;
}
List<Node> finalPath = new ArrayList<>();
for(int i = path.size() - 1; i > 0; i--) {
finalPath.add(path.get(i));
}
return finalPath;
}
private static boolean vecInList(Vector2i vec, List<Node> list) {
for(Node n : list) {
if(n.tile.equals(vec)) return true;
}
return false;
}
private static boolean vecInList(Vector2i vec, HashSet<Node> list) {
for(Node n : list) {
if(n.tile.equals(vec)) return true;
}
return false;
}
private static Node getNodeInHashSetForPosition(Vector2i position, HashSet<Node> hashSet) {
for(Node n : hashSet) {
if(n.tile.equals(position)) return n;
}
return null;
}
private static double getNodeDistance(Vector2i nodeA, Vector2i nodeB) {
int dstX = Math.abs(nodeA.x - nodeB.x);
int dstY = Math.abs(nodeA.y - nodeB.y);
if(dstX > dstY) return 14 * dstY + 10 * (dstX - dstY);
return (14 * dstX) + (10 * (dstY - dstX));
}
}
Node.java
public class Node {
public Vector2i tile;
public Node parent;
public double fCost, gCost, hCost; //a cost is like the distance it takes to get to that point. these are used to find the lowest cost way to get from start point A to end point B.
//gCost is the sum of all of our node to node, or tile to tile, distances.
//hCost is the direct distance from the start node to the end node.
//fCost is the total cost for all the ways we calculate to get to the end node/tile.
public Node(Vector2i tile, Node parent, double gCost, double hCost) { //NODE CONSTRUCTOR STARt
this.tile = tile;
this.parent = parent;
this.gCost = gCost;
this.hCost = hCost;
this.fCost = this.gCost + this.hCost;
}//NODE CONSTRUCTOR END
}
更改以下内容:
if(!open.contains(node)) {
至:
if(!veckInList(neighbor, open) {
正如标题所说,这个 A* 搜索算法永远不会停止搜索。我正在尝试为 point-click 在 2D tile-based 游戏中行走创建一个有效的 A* 搜索算法,一些方块是 walk-able 而一些方块是实心的。
PathFinder.java:
public class PathFinder {
public static List<Node> findPath(Map map, int sx, int sy, int dx, int dy) {
if(map.getTile(dx, dy).isSolid()) return null;
Node startNode = new Node(new Vector2i(sx, sy), null, 0, 0);
Vector2i goal = new Vector2i(dx, dy);
List<Node> open = new ArrayList<>();
HashSet<Node> closed = new HashSet<>();
open.add(startNode);
while(open.size() > 0) {
Node currentNode = open.get(0);
for(int i = 1; i < open.size(); i++) {
if(open.get(i).fCost < currentNode.fCost ||
open.get(i).fCost == currentNode.fCost && open.get(i).hCost < currentNode.hCost) {
currentNode = open.get(i);
}
}
open.remove(currentNode);
closed.add(currentNode);
if(currentNode.tile == goal){
System.out.println("returning path!");
return retracePath(startNode, currentNode);
}
for(Tile tile : map.getNeighbors(currentNode)) {
Vector2i neighbor = new Vector2i(tile.getTileX(), tile.getTileY());
if(tile.isSolid() || getNodeInHashSetForPosition(neighbor, closed) != null) {
continue;
}
double gCost = currentNode.gCost + getNodeDistance(currentNode.tile, neighbor);
if(currentNode.gCost < gCost || !vecInList(neighbor, open)) {
double hCost = getNodeDistance(neighbor, goal);
Node node = new Node(neighbor, currentNode, gCost, hCost);
if(!open.contains(node)) {
open.add(node);
}
}
}
}
return null;
}
private static List<Node> retracePath(Node startNode, Node endNode) {
List<Node> path = new ArrayList<>();
Node currentNode = endNode;
while(currentNode != startNode) {
path.add(currentNode);
currentNode = currentNode.parent;
}
List<Node> finalPath = new ArrayList<>();
for(int i = path.size() - 1; i > 0; i--) {
finalPath.add(path.get(i));
}
return finalPath;
}
private static boolean vecInList(Vector2i vec, List<Node> list) {
for(Node n : list) {
if(n.tile.equals(vec)) return true;
}
return false;
}
private static boolean vecInList(Vector2i vec, HashSet<Node> list) {
for(Node n : list) {
if(n.tile.equals(vec)) return true;
}
return false;
}
private static Node getNodeInHashSetForPosition(Vector2i position, HashSet<Node> hashSet) {
for(Node n : hashSet) {
if(n.tile.equals(position)) return n;
}
return null;
}
private static double getNodeDistance(Vector2i nodeA, Vector2i nodeB) {
int dstX = Math.abs(nodeA.x - nodeB.x);
int dstY = Math.abs(nodeA.y - nodeB.y);
if(dstX > dstY) return 14 * dstY + 10 * (dstX - dstY);
return (14 * dstX) + (10 * (dstY - dstX));
}
}
Node.java
public class Node {
public Vector2i tile;
public Node parent;
public double fCost, gCost, hCost; //a cost is like the distance it takes to get to that point. these are used to find the lowest cost way to get from start point A to end point B.
//gCost is the sum of all of our node to node, or tile to tile, distances.
//hCost is the direct distance from the start node to the end node.
//fCost is the total cost for all the ways we calculate to get to the end node/tile.
public Node(Vector2i tile, Node parent, double gCost, double hCost) { //NODE CONSTRUCTOR STARt
this.tile = tile;
this.parent = parent;
this.gCost = gCost;
this.hCost = hCost;
this.fCost = this.gCost + this.hCost;
}//NODE CONSTRUCTOR END
}
更改以下内容:
if(!open.contains(node)) {
至:
if(!veckInList(neighbor, open) {