Search code examples
javaswingjframeminesweeper

Cannot properly reset JFrame


I am a java Beginner and I'm working on a MineSweeper project now. I encountered a strange problem where I cannot reset the level properly when clicking the "New" button.(Although it could work for the first few times). I think it might have something to do with Swing EDT but not too sure how to fix it exactly.

public class GUI extends JFrame {
private CenterPanel centerPanel;

public GUI() {
    super("Minesweeper");
    setLayout(new BorderLayout());
    setDefaultCloseOperation(EXIT_ON_CLOSE);
    JMenuBar menuBar = new JMenuBar();
    JMenu menu = new JMenu("File");
    JMenuItem newGame = new JMenuItem("New");
    centerPanel = new CenterPanel();

    menuBar.add(menu);
    menu.add(newGame);

    newGame.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            centerPanel.removeAll();
            centerPanel.setup();
            centerPanel.revalidate();
            centerPanel.repaint();
        }
    });

    add(menuBar, BorderLayout.NORTH);
    add(centerPanel, BorderLayout.CENTER);

    pack();
}
}

public class Board {
    private int width;
    private int height;
    private Square[][] board;
    private int mines;

    public Board(int x, int y, int z) {
        width = x;
        height = y;
        mines = z;
        board = new Square[x][y];
        setup();
    }

public void setup() {
    for (int i = 0; i < mines; i++) {
        int randRow = (int) (Math.random() * width);
        int randColumn = (int) (Math.random() * height);
        while (board[randRow][randColumn] == Square.MINE) {
            randRow = (int) (Math.random() * width);
            randColumn = (int) (Math.random() * height);
            board[randRow][randColumn] = Square.MINE;
        }
        board[randRow][randColumn] = Square.MINE;
    }
    for (int i = 0; i < height; i++) {
        for (int j = 0; j < width; j++) {
            int neighbourcount = 0;
            if (board[i][j] != Square.MINE) {
                if (i > 0 && j > 0 && board[i - 1][j - 1] == Square.MINE) {
                    neighbourcount++;
                }
                if (i > 0 && board[i - 1][j] == Square.MINE) {
                    neighbourcount++;
                }
                if (i > 0 && j < width - 1
                        && board[i - 1][j + 1] == Square.MINE) {
                    neighbourcount++;
                }
                if (j > 0 && board[i][j - 1] == Square.MINE) {
                    neighbourcount++;
                }
                if (i < height - 1 && j > 0
                        && board[i + 1][j - 1] == Square.MINE) {
                    neighbourcount++;
                }
                if (i < height - 1 && board[i + 1][j] == Square.MINE) {
                    neighbourcount++;
                }
                if (i < height - 1 && j < width - 1
                        && board[i + 1][j + 1] == Square.MINE) {
                    neighbourcount++;
                }
                if (j < width - 1 && board[i][j + 1] == Square.MINE) {
                    neighbourcount++;
                }
                board[i][j] = Square.getByNumber(neighbourcount);
            }
        }
    }
}

public Square getSquare(int i, int j) {
    return board[i][j];
}
}

public enum Square {
    ZERO(0), ONE(1), TWO(2), THREE(3), FOUR(4), FIVE(5), SIX(6), SEVEN(7), EIGHT(
            8), MINE(9);
    private int number;

    private Square(int i) {
        number = i;
    }

    public int getNumber() {
        return number;
    }

    public static Square getByNumber(int i) {
        for (Square sr : Square.values()) {
            if (i == sr.getNumber()) {
                return sr;
            }
        }
        return null;
    }
}

public class CenterPanel extends JPanel {
private JPanel[][] PanelArray;
private Board board;
public CenterPanel() {
    setLayout(new GridLayout(9, 9));
    setup();
}
public void setup(){
    PanelArray= new JPanel[9][9];
    board = new Board(9, 9, 10);
    for (int i = 0; i < 9; i++) {
        for (int j = 0; j < 9; j++) {
            final int row = i;
            final int column = j;
            final JButton button = new JButton();
            PanelArray[i][j] = new JPanel();
            PanelArray[i][j].setLayout(new GridLayout(1,1));
            PanelArray[i][j].add(button);

            button.addMouseListener(new MouseListener() {

                public void mouseClicked(MouseEvent e) {

                }

                public void mouseEntered(MouseEvent e) {

                }

                public void mouseExited(MouseEvent e) {

                }

                public void mousePressed(MouseEvent e) {

                }

                public void mouseReleased(MouseEvent e) {
                    if (e.getButton() == MouseEvent.BUTTON3) {
                        if (button.getText().equals("")) {
                            button.setText("F");
                        } else {
                            button.setText("");
                        }
                    }
                    if (e.getButton() == MouseEvent.BUTTON1) {
                        if (button.getText().equals("F")) {
                        } else {
                            int k = board.getSquare(row,
                                    column).getNumber();
                            if (k == 0) {
                                PanelArray[row][column].remove(button);
                                revalidate();
                                repaint();
                            } else if (k == 9) {
                                removeAll();
                                for (int i = 0; i < 9; i++) {
                                    for (int j = 0; j < 9; j++) {
                                        int m = board.getSquare(i, j)
                                                .getNumber();
                                        if (m == 0) {
                                            add(new JLabel(""));
                                        } else if (m == 9) {

                                            add(new JLabel(
                                                    "                         *"));

                                        } else {
                                            add(new JLabel(
                                                    "                         "
                                                            + Integer
                                                                    .toString(m)));
                                        }
                                    }
                                }
                                revalidate();
                                repaint();
                            } else {
                                PanelArray[row][column].remove(button);
                                PanelArray[row][column].add(new JLabel("                         "
                                        + Integer.toString(k)));
                                revalidate();
                                repaint();
                            }
                        }

                    }
                }

            });
            add(PanelArray[i][j]);
        }
    }
}
}

public class Main {

public static void main(String[] args) {
    GUI game = new GUI();
    game.setVisible(true);
}

}

Appreciate your help!


Solution

  • I would have preferred to put this as a comment, but there's really not enough place to put my explanation in there.

    Your loop that fills your board with mines is flawed and can enter an infinite-loop--> your application will freeze (you can also probably see that one of your CPU is used at 100%).

    Let's check that loop:

     for (int i = 0; i < mines; i++) {
        int randRow = (int) (Math.random() * width);
        int randColumn = (int) (Math.random() * height);
        while (board[randRow][randColumn] == Square.MINE) {
            randRow = (int) (Math.random() * width);
            randColumn = (int) (Math.random() * height);
            board[randRow][randColumn] = Square.MINE;
        }
        board[randRow][randColumn] = Square.MINE;
    }
    

    At the end of the while, you call:

    board[randRow][randColumn] = Square.MINE;
    

    then the while loop will check the condition: board[randRow][randColumn] == Square.MINE. Since you just assigned a MINE to that position, the condition is always true--> Here is your infinite loop.

    You should have written something like:

     Random r = new Random();
     for (int i = 0; i < mines; i++) {
        int randRow = r.nextInt(width);
        int randColumn = r.nextInt(height);
        while (board[randRow][randColumn] == Square.MINE) {
            randRow = r.nextInt(width);
            randColumn = r.nextInt(height);
            // Don't do anything here !!!
        }
        // Now that you found an empty spot, put a mine
        board[randRow][randColumn] = Square.MINE;
    }