如何让递归迷宫生成器绘制每一步?

How to have recursive maze generator draw each step?

我写完了一个递归创建迷宫的程序,但一直无法弄清楚如何让它在每一步之后绘制迷宫。迷宫的任何变化都发生在下一次递归调用之前。迷宫作为正方形网格预渲染到 JPanel 上,我试图通过在下一次递归调用之前使用 JPanel.repaint 让程序渲染每一步(我在 generate 方法,我以前尝试过重新绘制。无论我尝试什么,迷宫只是在最后一次渲染完成的产品(迷宫与所有路径,墙壁等)。附上我的递归 generate方法。

private static boolean generate(int x, int y) {
    System.out.println("xcord: " + x + ", ycord: " + y);
    //panel.repaint(); when i have repaint here, it renders the entire maze at the end
    a[x][y].visited = true;
    if (unvisitedCells == 0) { // if you have visited all of the cells, maze is done generating
        System.out.println("done");
        return true;
    }
    int movesTried = 0; // keeps track of which directions have been tried
    int currentMove = (int) (Math.random() * 4); // try moving a random direction first (0 = north, 1 = east, etc.)
    while (movesTried < 4) { // continue as long as all four moves havent been tried
        // north move
        if (a[x][y].northCell != null && a[x][y].northCell.visited != true && currentMove == 0) {
            a[x][y].northCell.visited = true;
            a[x][y].northWall = false;
            a[x][y].northCell.southWall = false;
            unvisitedCells -= 1;
            // tried repainting here, but had no effect
            if (generate(x, y - 1)) {
                return true; // move successful
            }
        }
        // east move
        if (a[x][y].eastCell != null && a[x][y].eastCell.visited != true && currentMove == 1) {
            a[x][y].eastCell.visited = true;
            a[x][y].eastWall = false;
            a[x][y].eastCell.westWall = false;
            unvisitedCells -= 1;
            // tried repainting here, but had no effect
            if (generate(x + 1, y)) {
                return true; // move successful
            }
        }
        // south move
        if (a[x][y].southCell != null && a[x][y].southCell.visited != true && currentMove == 2) {
            a[x][y].southCell.visited = true;
            a[x][y].southWall = false;
            a[x][y].southCell.northWall = false;
            unvisitedCells -= 1;
            // tried repainting here, but had no effect
            if (generate(x, y + 1)) {
                return true; // move successful
            }
        }
        // west move
        if (a[x][y].westCell != null && a[x][y].westCell.visited != true && currentMove == 3) {
            a[x][y].westCell.visited = true;
            a[x][y].westWall = false;
            a[x][y].westCell.eastWall = false;
            unvisitedCells -= 1;
            // tried repainting here, but had no effect
            if (generate(x - 1, y)) {
                return true; // move successful
            }
        }
        movesTried++; // another move has been tried
        if (currentMove == 3 && movesTried < 4) {
            currentMove = 0; // wraps back to north move if maze started at a move greater than 0, and you
                                // have more moves to try
        } else {
            currentMove++;
        }
    }
    // at this point, all 4 moves have been tried, and there are no possible moves
    // from the current maze cell
    return false;
}

使用 MazeCell class.

中保存的信息,将每个单元格单独渲染到 JPanel
public class MazeCell {

public boolean northWall = true;
public boolean eastWall = true;
public boolean southWall = true;
public boolean westWall = true;

public MazeCell northCell = null;
public MazeCell eastCell = null;
public MazeCell southCell = null;
public MazeCell westCell = null;

public boolean visited = false;

}

这里我设置了一个JPanel,它根据4个方向的每一个方向是否有墙来单独绘制每个单元格。

panel = new JPanel() {

        private static final long serialVersionUID = 1L;

        public void paintComponent(Graphics g) {
            super.paintComponent(g);
            a[0][0].northWall = false;
            a[mazeSize - 1][mazeSize - 1].southWall = false;
            for (int y = 0; y < mazeSize; y++) {
                for (int x = 0; x < mazeSize; x++) {
                    if (a[x][y].northWall) {
                        g.drawLine(100 + (x * 25), 100 + (y * 25), 100 + (x * 25) + 25, 100 + (y * 25));
                    }
                    if (a[x][y].eastWall) {
                        g.drawLine(100 + (x * 25) + 25, 100 + (y * 25), 100 + (x * 25) + 25, 100 + (y * 25) + 25);
                    }
                    if (a[x][y].southWall) {
                        g.drawLine(100 + (x * 25), 100 + (y * 25) + 25, 100 + (x * 25) + 25, 100 + (y * 25) + 25);
                    }
                    if (a[x][y].westWall) {
                        g.drawLine(100 + (x * 25), 100 + (y * 25), 100 + (x * 25), 100 + (y * 25) + 25);
                    }
                }
            }
        }
    };

SwingWorker 扭曲长进程 (generate(int x, int y)),让它更新 GUI。这是一个例子:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.GridLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingWorker;

public class RecursiveGuiUpdate extends JFrame {

    private final int SIZE = 4;
    JLabel[][] grid = new JLabel[SIZE][SIZE];

    RecursiveGuiUpdate()    {

        setDefaultCloseOperation(DISPOSE_ON_CLOSE);
        add(getGrid(), BorderLayout.NORTH);
        JButton paint = new JButton("Paint");
        paint.addActionListener(a -> updateGui());
        add(paint, BorderLayout.SOUTH);
        pack();
        setVisible(true);
    }

    private void updateGui() {
        new Task().execute();
    }

    private Component getGrid() {
        JPanel panel = new JPanel(new GridLayout(SIZE, SIZE));
        for(int i=0; i<=(SIZE-1); i++) {
            for(int j=0; j<=(SIZE-1); j++) {
                JLabel l = new JLabel(i+"-"+j, JLabel.CENTER);
                l.setOpaque(true);
                panel.add(l);
                grid[i][j] = l;
            }
        }
        return panel;
    }

    class Task extends SwingWorker<Void,Void> {

        @Override
        public Void doInBackground() {
            updateGui(0, 0);
            return null;
        }

        @Override
        public void done() { }

        //recursively set labels background
        void updateGui(int i, int j) {

            System.out.println(i+"-"+j);
            //set random, background color
            grid[i][j].setBackground(new Color((int)(Math.random() * 0x1000000)));

            try {
                Thread.sleep(500); //simulate long process
            } catch (InterruptedException ex) { ex.printStackTrace();}

            if((i==(SIZE-1))&&(j==(SIZE-1))) { return; }

            if(i<(SIZE-1)) {
                updateGui(++i, j);
            }else {
                i=0;
                updateGui(i, ++j);
            }
        }
    }

    public static void main(String[] args)  {
        new RecursiveGuiUpdate();
    }
}

如果需要,您可以覆盖 process(java.util.List) 以获取和处理临时结果。
如果您需要帮助使此类解决方案适应您的代码,请 post 另一个问题 mcve