打印PacMan迈向迷宫,广度优先搜索 - Java

时间:2013-05-22 17:26:35

标签: java breadth-first-search maze

我正在尝试创建某种没有鬼影的PacMan模拟,它以6x10的矩阵表示。我已经实现了BFS的一个变体,我在递归调用两个被搜索节点之间的算法,它给了我满意的结果。然而,我真正想做的是在每次PacMan运动之后打印迷宫的状态,其中PacMan用“2”表示,方框用“3”表示,墙用“1”表示,自由方式用“0”表示。我试图将每个节点的符号更改为“2”,对于每个新移动,然后将其父节点符号更改为“0”,但是这不能按预期工作,并且它给了我一些奇怪的结果。

我想我知道问题在哪里,虽然我还没有设法解决它。因此,对于每个被探索的节点,我将它放入一个列表中(可以更高效地完成它,这只是第一次运行),问题是它不会访问已经访问过的节点,所以它无法打印PacMan运动的每一步。我已经尝试在检查之前更改节点标志,如果它们已经被探索过,尽管它不能很好地工作。

我想这听起来相当令人困惑,所以我会尝试绘制一些我希望它看起来的步骤。

这是一个起始迷宫:

  

1 1 1 1 1 1 1 1 1 1

     

2 0 0 3 1 0 0 0 3 1

     

1 3 1 1 1 3 1 1 0 1

     

1 0 1 0 3 0 1 1 3 1

     

1 3 0 3 1 3 0 1 0 1

     

1 1 1 1 1 1 0 3 0 1

这就是解决方案的外观:

  

1 1 1 1 1 1 1 1 1 1

     

0 0 0 0 1 0 0 0 0 1

     

1 0 1 1 1 2 1 1 0 1

     

1 0 1 0 0 0 1 1 0 1

     

1 0 0 0 1 0 0 1 0 1

     

1 1 1 1 1 1 0 0 0 1

现在,我希望为pacman所采取的每一步打印一个新的迷宫:

  

1 1 1 1 1 1 1 1 1 1 /////// 1 1 1 1 1 1 1 1 1 /////// 1 1 1 1 1 1 1 1 1   1

     

0 2 0 3 1 0 0 0 3 1 /////// 0 0 2 3 1 0 0 0 3 1 /////// 0 0 0 2 1 0 0 0 3   1

     

1 3 1 1 1 3 1 1 0 1 /////// 1 3 1 1 1 3 1 1 0 1 /////// 1 3 1 1 1 3 1 1 0   1

     

1 0 1 0 3 0 1 1 3 1 ///////。

     

1 3 0 3 1 3 0 1 0 1 ///////。

     

1 1 1 1 1 1 0 3 0 1 ///////

     

/////////

     

1 1 1 1 1 1 1 1 1 1

     

0 0 2 0 1 0 0 0 3 1

     

1 3 1 1 1 3 1 1 0 1

等等,抱歉这些令人困惑的图片,我只写了前三行。

这是函数的代码和所有相关函数,以及完整源代码的链接。我也做了一些评论,并且我已经尝试了最后一件事。任何建议都可以。谢谢。

源代码:http://www.speedyshare.com/DkXgQ/BreadthFirstSearch.rar

public static boolean breadthFirstSearch(Node root, Node[][] mazeGrid, int boxCounter) {

    root.setSign("0");
    toExplore.add(root);
    int[] x_coord = { 0, 1, 0, -1};
    int[] y_coord = {1, 0, -1, 0 };
    while(!toExplore.isEmpty()) {

        Node node = toExplore.poll();
        explored.add(node);
        //for moving!!!!!

        /*if(node.getParent() != null) {
            node.getParent().setSign("0");
        }
        node.setSign("2");*/
            for(int i = 0; i < 4; i++) {
                //new coordinates
                int x = node.getX_coord() + x_coord[i];
                int y = node.getY_coord() + y_coord[i];

                if(x >= 0 && y >=0 && x < 6 && y < 10) {
                    Node child = maze[x][y];
                    //show moving steps!!!!!

                    /*System.out.println("\nStep : \n");
                    for(int xx = 0; xx < 6; xx++) {
                        for(int j = 0; j < 10; j++) {
                            System.out.print(maze[xx][j].getSign() + " ");
                        }
                        System.out.print("\n");
                    }*/
                    //is current node explored?
                    if(!isExplored(child) && !child.getSign().equals("1")) {
                        //save parent for the shortest path between root and node being searched for
                        child.setParent(node);

                        //have we found a box?
                        if(child.getSign().equals("3")) {
                            System.out.println("Node number " + boxCounter + " has been found : " +
                                        child.getX_coord() + " , " + child.getY_coord());
                            //counter for rest of the existing boxes
                            boxCounter--;
                            Node temp = child;
                            printPath(temp);
                            //this is used for path printing between two nodes, and not from the main root and last node being found
                            temp.setParent(null);
                            //just jumping from box to box, so I can print where the last position on the maze is
                            child.setSign("2");
                            if(boxCounter != 0) {
                                //if there are more boxes on the maze, recursion
                                breadthFirstSearch(child, mazeGrid, boxCounter);
                            }
                            return true;

                        }
                        if(child.getSign().equals("0")) {
                            //new node to explore
                            toExplore.add(child);

                        }
                    }
                }
            }
    }

    System.out.println("Node not found!");
    return false;
}

public static void printPath(Node child) {
    while(child.getParent() != null) {
        path.add(0, child);
        child = child.getParent();
    }
    System.out.println("Shortest path : ");
    for(Node n: path) {
        System.out.println(n.getX_coord() + " - " + n.getY_coord());
    }
    path.clear();
}

public static boolean isExplored(Node node) {
    for(Node n : explored) {
        if(n.getX_coord() == node.getX_coord() && n.getY_coord() == node.getY_coord()) {
            return true;
        }
    }
    return false;
}

1 个答案:

答案 0 :(得分:2)

问题在于,对于真正的BFS,您必须为队列中的每个元素保存迷宫的整个状态。这包括整个地图,一组访问过的节点,尤其是未吃过的盒子的数量和位置。这是因为在BFS中没有“回溯”的概念,所以你必须基本上创建迷宫的多个状态。

另一种方法是使用DFS。这样,您可以在每次递归调用之前更新迷宫的状态,然后在从方法返回之前恢复状态。这样,您只能保留一个迷宫状态的副本。当然,要获得DFS中的最短路径,您必须尝试所有可能的路径,其中可能有很多路径。如果您的迷宫包含循环路径,您还必须避免重复循环。