1

我正在尝试创建某种没有鬼的 PacMan 模拟,它由 6x10 的矩阵表示。我已经实现了 BFS 的一个变体,我在两个正在搜索的节点之间递归调用算法,它给了我令人满意的结果。然而,我真正想做的是在每次吃豆人运动后打印迷宫的状态,吃豆人用“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 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

依此类推,抱歉图片混乱,我只写了前 3 行。

这是一个函数和所有相关函数的代码,也是完整源代码的链接。我也发表了一些评论,并阻止了我尝试过的最后一件事。任何建议都可以。谢谢。

源代码: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;
}
4

1 回答 1

2

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

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

于 2013-05-22T17:46:54.857 回答