使用随机Prim's算法生成迷宫的问题

时间:2019-08-07 15:56:14

标签: java graph-theory maze

我试图在维基百科https://en.wikipedia.org/wiki/Maze_generation_algorithmRandomized_Prim的s_algorithm上遵循此伪代码 但是我的代码只会生成一个完整的网格。我对算法的功能了解不足。有人可以帮我解释我在做什么吗?

我看过一些资料,但是我无法将其包裹住

public class MazeGen {
private int dimension, nodeCounter;
private Node[][] nodes;
private List<Edge> walls;

public static void main(String[] args) {
    MazeGen g = new MazeGen(20);
    g.generate();
    g.printMaze();
}

private void generate() {
    pickCell();
    generateMaze();
}

private void generateMaze() {
    while (!walls.isEmpty()) {
        int v;
        Edge wall = walls.get(ThreadLocalRandom.current().nextInt(walls.size()));
        if ((!wall.nodes[0].visited && wall.nodes[1].visited)
                || (wall.nodes[0].visited && !wall.nodes[1].visited)) {
            if (!wall.nodes[0].visited)
                v = 0;
            else
                v = 1;

            includeNode(wall.nodes[v]);
            wall.nodes[Math.abs(v - 1)].visited = true;
        }
        walls.remove(wall);
    }
}

private void pickCell() {
    int i = ThreadLocalRandom.current().nextInt(dimension);
    int j = ThreadLocalRandom.current().nextInt(dimension);

    includeNode(nodes[i][j]);
}

private void includeNode(Node node) {
    node.visited = true;
    node.partOfMaze = true;
    walls.addAll(node.edges);
}

public void printMaze() {
    for (int i = 0; i < dimension; i++) {
        System.out.println();
        for (int j = 0; j < dimension; j++) {
            if (nodes[i][j].partOfMaze) {
                System.out.print(".");
            } else
                System.out.print("p");
        }
    }
}

public MazeGen(int n) {
    nodes = new Node[n][n];
    walls = new ArrayList<Edge>();
    dimension = n;

    createNodes();
    connectAdjacents();
}

private void connectAdjacents() {
    for (int i = 0; i < dimension; i++) {
        for (int j = 0; j < dimension; j++) {
            verifyConnection(i, j, i, j + 1);
            verifyConnection(i, j, i + 1, j);
        }
    }
}

private void verifyConnection(int i, int j, int arg1, int arg2) {
    if (arg1 < dimension && arg2 < dimension)
        connect(i, j, arg1, arg2);
}

private void createNodes() {
    for (int i = 0; i < dimension; i++) {
        for (int j = 0; j < dimension; j++) {
            nodes[i][j] = new Node();
        }
    }
}

private void connect(int row, int col, int row2, int col2) {
    nodes[row][col].edges.add(new Edge(nodes[row][col], nodes[row2][col2]));
    nodes[row2][col2].edges.add(new Edge(nodes[row][col], nodes[row2][col2]));
}

private class Node {
    boolean visited, partOfMaze;
    int number;
    List<Edge> edges;

    Node() {
        number = nodeCounter++;
        edges = new ArrayList<Edge>();
    }

    @Override
    public String toString() {
        return String.valueOf(number);
    }
}

private class Edge {
    Node[] nodes;

    Edge(Node n, Node n2) {
        nodes = new Node[2];
        nodes[0] = n;
        nodes[1] = n2;
    }

    @Override
    public String toString() {
        return nodes[0] + "-" + nodes[1];
    }
}

2 个答案:

答案 0 :(得分:0)

我认为您的算法是正确的,但您没有保留正确的输出。 所有节点都应该是迷宫的一部分。应该是迷宫的一部分的墙壁是当您处理它们时连接两个访问的节点的墙壁。

制作另一个输出壁数组,并在generateMaze方法中设置值。

private void generateMaze() {
    while (!walls.isEmpty()) {
        int v;
        Edge wall = walls.get(ThreadLocalRandom.current().nextInt(walls.size()));
        if ((!wall.nodes[0].visited && wall.nodes[1].visited)
                || (wall.nodes[0].visited && !wall.nodes[1].visited)) {
            if (!wall.nodes[0].visited)
                v = 0;
            else
                v = 1;

            includeNode(wall.nodes[v]);
            wall.nodes[Math.abs(v - 1)].visited = true;
            /////////////////////////////////////
            // remove this wall from the output walls
            /////////////////////////////////////
        } else {
            ////////////////////////////////
            // add this wall to the output walls
            ////////////////////////////////
        }
        walls.remove(wall);
    }
}

答案 1 :(得分:0)

忘记维基百科,他们会对言论自由进行审查,并操纵信息,特别是在政治和社会领域。因此,我还删除了我在“迷宫生成”上的Wikipedia页面上添加的所有内容(请参阅页面历史记录)。

“ Prim's” MST算法的思想是在断开连接的子图之间保持“切割”(一组边),并始终选择最便宜的边来连接这些子图。标记访问过的顶点以避免生成循环。

通过在完整网格图中使用边缘随机权重或从空网格图开始并动态添加随机加权边缘,可以将其用于迷宫生成。

有关迷宫生成的信息,请参见我的GitHub存储库:

https://github.com/armin-reichert/mazes

https://github.com/armin-reichert/mazes/blob/master/mazes-algorithms/src/main/java/de/amr/maze/alg/mst/PrimMST.java

public void createMaze(int x, int y) {
        cut = new PriorityQueue<>();
        expand(grid.cell(x, y));
        while (!cut.isEmpty()) {
            WeightedEdge<Integer> minEdge = cut.poll();
            int u = minEdge.either(), v = minEdge.other();
            if (isCellUnvisited(u) || isCellUnvisited(v)) {
                grid.addEdge(u, v);
                expand(isCellUnvisited(u) ? u : v);
            }
        }
    }

    private void expand(int cell) {
        grid.set(cell, COMPLETED);
        grid.neighbors(cell).filter(this::isCellUnvisited).forEach(neighbor -> {
            cut.add(new WeightedEdge<>(cell, neighbor, rnd.nextInt()));
        });
    }