A *算法无法找到目标的路径

时间:2015-09-29 00:37:01

标签: java algorithm

我一直在努力实现Java中的A *算法。我想要做的是加载在文本文件中创建的瓦片地图(空格,障碍物,开始和目标由不同的字符标记),从中创建节点地图并能够在地图上运行A *。但是,当我运行A *时,它会在开始列表用完之前检查开始周围的几个节点并返回null。过去几天我一直在搞乱这个问题,我无法弄清楚它失败的原因。它可能是愚蠢的,但任何帮助都会受到赞赏。

A *实施:

public ArrayList<Node> calculateShortestPath(int startHeight, int startWidth, int goalHeight, int goalWidth) {
    map.setStart(startHeight, startWidth);
    map.setGoal(goalHeight, goalWidth);

    if (map.getGoal().isObstacle()) {
        return null;
    }

    map.getStart().setDistanceFromStart(0);
    closedList.clear();
    openList.clear();
    openList.add(map.getStart());
    Collections.sort(openList);

    while (!openList.isEmpty()) {
        Node currentNode = openList.get(0); //the list should be sorted, so this should produce the node with the lowest f value
        if (currentNode.equals(map.getGoal())) {
            return reconstructPath(currentNode);
        }

        openList.remove(currentNode);
        closedList.add(currentNode);

        for (Node neighbour : currentNode.getNeighbourList()) {
            System.out.println(neighbour);
            boolean neighbourIsBetter;
            if (closedList.contains(neighbour)) {
                continue;
            }
            if (!neighbour.isObstacle()) {
                float neighbourDistanceFromStart = (currentNode.getDistanceFromStart() + map.getDistanceBetweenNodes(currentNode, neighbour));
                if (!openList.contains(neighbour)) {
                    openList.add(neighbour);
                    Collections.sort(openList);
                    neighbourIsBetter = true;
                } else if (neighbourDistanceFromStart < currentNode.getDistanceFromStart()) {
                    neighbourIsBetter = true;
                } else {
                    neighbourIsBetter = false;
                }
                if (neighbourIsBetter) {
                    neighbour.setPreviousNode(currentNode);
                    neighbour.setDistanceFromStart(neighbourDistanceFromStart);
                    neighbour.setHeuristicDistanceFromGoal(getEstimatedDistanceToGoal(neighbour.getHeight(), neighbour.getWidth(), goalHeight, goalWidth));
                }
            }
        }
    }
    return null;
}

一些地图创建方法:

private void createMap() {
    Node node;
    map = new Node[mapHeight][mapWidth];
    for (int x = 0; x < mapHeight; x++) {
        for (int y = 0; y < mapWidth; y++) {
            node = new Node(x, y);
            map[x][y] = node;
            if (obstacles[x][y] == 1) {
                node.setObstacle(true);
            }
        }
    }
}

private void registerEdges() {
    for (int x = 0; x < mapHeight - 1; x++) {
        for (int y = 0; y < mapWidth - 1; y++) {
            Node node = map[x][y];
            if (!(x == 0)) {
                node.setNorth(map[x - 1][y]);
            }
            if (!(y == mapWidth)) {
                node.setEast(map[x][y + 1]);
            }
            if (!(x == mapHeight)) {
                node.setSouth(map[x + 1][y]);
            }
            if (!(y == 0)) {
                node.setWest(map[x][y - 1]);
            }
        }
    }
}

最后,compareTo覆盖用于对打开列表进行排序

@Override
public int compareTo(Node otherNode) {
    float thisTotalDistanceFromGoal = heuristicDistanceFromGoal + distanceFromStart;
    float otherTotalDistanceFromGoal = otherNode.getHeuristicDistanceFromGoal() + otherNode.getDistanceFromStart();

    if (thisTotalDistanceFromGoal < otherTotalDistanceFromGoal) {
        return -1;
    } else if (thisTotalDistanceFromGoal > otherTotalDistanceFromGoal) {
        return 1;
    } else {
        return 0;
    }
}

所有其他方法都是getter,setter和其他支持方法。我使用曼哈顿距离作为启发式算法。我知道我通过高度然后宽度(y,x对x,y)创建和访问地图。它源于这样的事实:这是文件的读入方式(行然后是行中的字符),并且我选择在整个过程中保持它,因为来回切换最初会给我带来问题。

这里有一些关于我尝试过的内容。我在测试期间打印出了节点图,所以我知道它正在被正确创建。我还在算法中访问节点时打印出有关节点的信息,并正确分配高度和宽度值,算法从正确的位置开始。我已经使用断点来确认我的compareTo方法是被调用的方法,并且我可以在任何时候将节点添加到openList中进行排序。我根本无法发现问题。

编辑: 附加代码:

完整地图类:

public class Map {
private final int mapWidth;
private final int mapHeight;
private Node[][] map;
private final int[][] obstacles;
private int startHeight = 0;
private int startWidth = 0;
private int goalHeight = 0;
private int goalWidth = 0;

public Map (int mapWidth, int mapHeight, int[][] obstacles) {
    this.mapWidth = mapWidth;
    this.mapHeight = mapHeight;
    this.obstacles = obstacles;

    createMap();
    registerEdges();
}

private void createMap() {
    Node node;
    map = new Node[mapHeight][mapWidth];
    for (int x = 0; x < mapHeight; x++) {
        for (int y = 0; y < mapWidth; y++) {
            node = new Node(x, y);
            map[x][y] = node;
            if (obstacles[x][y] == 1) {
                node.setObstacle(true);
            }
        }
    }
}

private void registerEdges() {
    for (int x = 0; x < mapHeight - 1; x++) {
        for (int y = 0; y < mapWidth - 1; y++) {
            Node node = map[x][y];
            if (!(x == 0)) {
                node.setNorth(map[x - 1][y]);
            }
            if (!(y == mapWidth)) {
                node.setEast(map[x][y + 1]);
            }
            if (!(x == mapHeight)) {
                node.setSouth(map[x + 1][y]);
            }
            if (!(y == 0)) {
                node.setWest(map[x][y - 1]);
            }
        }
    }
}

public Node[][] getNodes() {
    return map;
}

public void setObstacle(int height, int width, boolean isObstacle) {
    map[height][width].setObstacle(isObstacle);
}

public Node getNode(int height, int width) {
    return map[height][width];
}

public void setStart(int height, int width) {
    map[startHeight][startWidth].setStart(false);
    map[height][width].setStart(true);
    startHeight = height;
    startWidth = width;
}

public void setGoal(int height, int width) {
    map[goalHeight][goalWidth].setGoal(false);
    map[height][width].setGoal(true);
    goalHeight = height;
    goalWidth = width;
}

public int getStartHeight() {
    return startHeight;
}

public int getStartWidth() {
    return startWidth;
}

public Node getStart() {
    return map[startHeight][startWidth];
}

public int getGoalHeight() {
    return goalHeight;
}

public int getGoalWidth() {
    return goalWidth;
}

public Node getGoal() {
    return map[goalHeight][goalWidth];
}

public float getDistanceBetweenNodes(Node node1, Node node2) {
    return 1 * (mapWidth + mapHeight);
}

public int getWidth() {
    return mapWidth;
}

public int getHeight() {
    return mapHeight;
}

public void clear() {
    startHeight = 0;
    startWidth = 0;
    goalHeight = 0;
    goalWidth = 0;
    createMap();
    registerEdges();
}

}

完整的节点类:

public class Node implements Comparable<Node>{
private Map map;
private Node north;
private Node east;
private Node south;
private Node west;
private ArrayList<Node> neighbourList;
boolean visited;
float distanceFromStart;
float heuristicDistanceFromGoal;
Node previousNode;
int height;
int width;
boolean isObstacle;
boolean isStart;
boolean isGoal;

public Node(int height, int width) {
    neighbourList = new ArrayList<Node>();
    this.height = height;
    this.width = width;
    this.visited = false;
    this.distanceFromStart = Integer.MAX_VALUE;
    this.isObstacle = false;
    this.isStart = false;
    this.isGoal = false;
}

public Node (int height, int width, boolean visited, int distanceFromStart, boolean isObstacle, boolean isStart, boolean isGoal) {
    neighbourList = new ArrayList<Node>();
    this.height = height;
    this.width = width;
    this.visited = visited;
    this.distanceFromStart = distanceFromStart;
    this.isObstacle = isObstacle;
    this.isStart = isStart;
    this.isGoal = isGoal;
}

public Node getNorth() {
    return north;
}

public void setNorth(Node north) {
    //replace the old Node with the new one in the neighborList
    if (neighbourList.contains(this.north)) {
        neighbourList.remove(this.north);
    }
    neighbourList.add(north);

    //set the new Node
    this.north = north;
}

public Node getEast() {
    return east;
}

public void setEast(Node east) {
    //replace the old Node with the new one in the neighborList
    if (neighbourList.contains(this.east)) {
        neighbourList.remove(this.east);
    }
    neighbourList.add(east);

    //set the new Node
    this.east = east;
}

public Node getSouth() {
    return south;
}

public void setSouth(Node south) {
    //replace the old Node with the new one in the neighborList
    if (neighbourList.contains(this.south)) {
        neighbourList.remove(this.south);
    }
    neighbourList.add(south);

    //set the new Node
    this.south = south;
}

public Node getWest() {
    return west;
}

public void setWest(Node west) {
    //replace the old Node with the new one in the neighborList
    if (neighbourList.contains(this.west)) {
        neighbourList.remove(this.west);
    }
    neighbourList.add(west);

    //set the new Node
    this.west = west;
}

public ArrayList<Node> getNeighbourList() {
    return neighbourList;
}

public boolean isVisited() {
    return visited;
}

public void setVisited(boolean visited) {
    this.visited = visited;
}

public float getDistanceFromStart() {
    return distanceFromStart;
}

public void setDistanceFromStart(float distanceFromStart) {
    this.distanceFromStart = distanceFromStart;
}

public float getHeuristicDistanceFromGoal() {
    return heuristicDistanceFromGoal;
}

public void setHeuristicDistanceFromGoal(float heuristicDistanceFromGoal) {
    this.heuristicDistanceFromGoal = heuristicDistanceFromGoal;
}

public Node getPreviousNode() {
    return previousNode;
}

public void setPreviousNode(Node previousNode) {
    this.previousNode = previousNode;
}

public int getHeight() {
    return height;
}

public void setHeight(int height) {
    this.height = height;
}

public int getWidth() {
    return width;
}

public void setWidth(int width) {
    this.width = width;
}

public boolean isObstacle() {
    return isObstacle;
}

public void setObstacle(boolean isObstacle) {
    this.isObstacle = isObstacle;
}

public boolean isStart() {
    return isStart;
}

public void setStart(boolean isStart) {
    this.isStart = isStart;
}

public boolean isGoal() {
    return isGoal;
}

public void setGoal(boolean isGoal) {
    this.isGoal = isGoal;
}

public boolean equals(Node node) {
    return (node.height == this.height) && (node.width == this.width);
}

@Override
public int compareTo(Node otherNode) {
    float thisTotalDistanceFromGoal = heuristicDistanceFromGoal + distanceFromStart;
    float otherTotalDistanceFromGoal = otherNode.getHeuristicDistanceFromGoal() + otherNode.getDistanceFromStart();

    if (thisTotalDistanceFromGoal < otherTotalDistanceFromGoal) {
        return -1;
    } else if (thisTotalDistanceFromGoal > otherTotalDistanceFromGoal) {
        return 1;
    } else {
        return 0;
    }
}

@Override
public String toString() {
    return "Height: " + this.getHeight() + " Width: " + this.getWidth();
}

//for debugging
public void printObstacle() {
    if (isObstacle) {
        System.out.print("1 ");
    } else {
        System.out.print("0 ");
    }
}

}

完成AStar课程:

public class AStar {
private Map map;
private ArrayList<Node> closedList;
private ArrayList<Node> openList;
private ArrayList<Node> wayPoints;

public AStar(Map map) {
    this.map = map;

    closedList = new ArrayList<Node>();
    openList = new ArrayList<Node>();
}

public ArrayList<Node> calculateShortestPath(int startHeight, int startWidth, int goalHeight, int goalWidth) {
    map.setStart(startHeight, startWidth);
    map.setGoal(goalHeight, goalWidth);

    if (map.getGoal().isObstacle()) {
        return null;
    }

    map.getStart().setDistanceFromStart(0);
    closedList.clear();
    openList.clear();
    openList.add(map.getStart());
    Collections.sort(openList);

    while (!openList.isEmpty()) {
        Node currentNode = openList.get(0);
        if (currentNode.equals(map.getGoal())) {
            return reconstructPath(currentNode);
        }

        openList.remove(currentNode);
        closedList.add(currentNode);

        for (Node neighbour : currentNode.getNeighbourList()) {
            System.out.println(neighbour);
            boolean neighbourIsBetter;
            if (closedList.contains(neighbour)) {
                continue;
            }
            if (!neighbour.isObstacle()) {
                float neighbourDistanceFromStart = (currentNode.getDistanceFromStart() + map.getDistanceBetweenNodes(currentNode, neighbour));
                if (!openList.contains(neighbour)) {
                    openList.add(neighbour);
                    Collections.sort(openList);
                    neighbourIsBetter = true;
                } else if (neighbourDistanceFromStart < currentNode.getDistanceFromStart()) {
                    neighbourIsBetter = true;
                } else {
                    neighbourIsBetter = false;
                }
                if (neighbourIsBetter) {
                    neighbour.setPreviousNode(currentNode);
                    neighbour.setDistanceFromStart(neighbourDistanceFromStart);
                    neighbour.setHeuristicDistanceFromGoal(getEstimatedDistanceToGoal(neighbour.getHeight(), neighbour.getWidth(), goalHeight, goalWidth));
                }
            }
        }
    }
    return null;
}

private ArrayList<Node> reconstructPath(Node node) {
    ArrayList<Node> path = new ArrayList<Node>();
    while (!(node.getPreviousNode() == null)) {
        wayPoints.add(0, node);
        node = node.getPreviousNode();
    }
    this.wayPoints = path;
    return path;
}

private float getEstimatedDistanceToGoal(int startX, int startY, int goalX, int goalY) {
    float dx = Math.abs(goalX - startX);
    float dy = Math.abs(goalY - startY);

    return dx + dy;
}

public ArrayList<Node> getWayPoints() {
    return wayPoints;
}

}

相关主要代码:

文件阅读,地图创建和AStar通话:

ArrayList<ArrayList<Integer>> readMap = new ArrayList<ArrayList<Integer>>();
    int height = 0;
    int width = 0;
    int startHeight = 0;
    int startWidth = 0;
    int goalHeight = 0;
    int goalWidth = 0;

    File fileMap = new File("./map.txt");
    try (BufferedReader br = new BufferedReader(new FileReader(fileMap))) {
        String line;
        while ((line = br.readLine()) != null) {
            char[] characters = line.toCharArray();
            readMap.add(new ArrayList<Integer>());
            for (char character : characters) {
                if (Character.isWhitespace(character)) {
                    readMap.get(height).add(0);
                } else if (character == 'X') {
                    readMap.get(height).add(1);
                } else if (character == 'S') {
                    readMap.get(height).add(0);
                    startHeight = height;
                    startWidth = width;
                } else if (character == 'G') {
                    readMap.get(height).add(0);
                    goalHeight = height;
                    goalWidth = width;
                }
                width++;
            }
            width = 0;
            height++;
            mapFile.add(line);
        }
        br.close();
    }
    catch (IOException ex) {
        System.err.println("Exception: " + ex.getMessage());
    }

    height = 0;
    width = 0;
    int[][] obstacleMap = new int[readMap.size()][readMap.get(0).size()];
    for (ArrayList<Integer> row : readMap) {
        for (Integer column : row) {
            obstacleMap[height][width] = column;
            width++;
        }
        width = 0;
        height++;
    }

    Map map = new Map(obstacleMap[0].length, obstacleMap.length, obstacleMap);
    AStar pathfinder = new AStar(map);
    shortestPath = pathfinder.calculateShortestPath(startHeight, startWidth, goalHeight, goalWidth);

运行时的邻居节点打印输出:

Height: 11 Width: 0
Height: 12 Width: 1
Height: 13 Width: 0
Height: 10 Width: 0
Height: 11 Width: 1
Height: 12 Width: 0
Height: 11 Width: 1
Height: 12 Width: 2
Height: 13 Width: 1
Height: 12 Width: 0
Height: 10 Width: 1
Height: 11 Width: 2
Height: 12 Width: 1
Height: 11 Width: 0
Height: 11 Width: 2
Height: 12 Width: 3
Height: 13 Width: 2
Height: 12 Width: 1
Height: 10 Width: 2
Height: 11 Width: 3
Height: 12 Width: 2
Height: 11 Width: 1

这就是它所做的。 (12,0)是起始节点(对于该映射)。此外,对角线路径不是必需的,因此仅查看北,西,东和南节点。

0 个答案:

没有答案