3
\$\begingroup\$

I'm quite a beginner with Java and just this month started learning about GUI and JFrame so naturally the first thing I wanted to do was build a Minesweeper Game. Apparently that's a common thing for beginners. However, I may have bitten off more than I can chew.

The game works fine and all, but when you click the Start button, it take a long time to close the Start Menu Panel and show the Main Game Panel. It seems to take longer if I pick Medium difficulty, and even longer if I pick Hard difficulty so I think the problem is the section where I'm drawing all the buttons. Easy mode is a grid of 10x10 buttons, Medium is 15x15, and Hard is 25x25. If someone knows what I can do differently, I'd appreciate it. It's kinda long, but I tried to comment as best I could.

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;


public class MineSweeper extends JFrame{

   //OPTIONS
   private int width = 650;
   private int height = 650;
   private int sides = 10;
   private int mines = 10;
   private int time = 0;

   //GAME
   private JPanel gamePanel;  //main board
   private Cell[][] cell;     //cells to click
   private int remainingBombs; //how many bombs are remaining
   private int timePassed;  //how much time is remaining

   //LABELS

   //START PANEL
   private JPanel startPanel;
   private JRadioButton easyButton;
   private JRadioButton mediumButton;
   private JRadioButton hardButton;
   private ButtonGroup optionsGroup;
   private JButton startButton;

   //PROGRESS BAR
   private JPanel progressPanel;
   private JLabel bombsLeftLabel;
   private JTextField bombsLeftText;
   private JLabel timeLeftLabel;
   private JTextField timeLeftText;

   //MENU BAR
   private JMenuBar menuBar;
   private JMenu fileMenu;
   private JMenu optionsMenu;
   private JRadioButtonMenuItem easy;
   private JRadioButtonMenuItem medium;
   private JRadioButtonMenuItem hard;

   public MineSweeper(){

      setTitle("Minesweeper");
      setSize(width, height);
      setDefaultCloseOperation(EXIT_ON_CLOSE);
      setLayout(new BorderLayout());

      //MENU BAR
      menuBar = new JMenuBar();

      createFile();
      createOptions();

      menuBar.add(fileMenu);
      menuBar.add(optionsMenu);

      setJMenuBar(menuBar);

      //BUILD START PANEL
      buildStartPanel();   

      //ASSEMBLE
      add(startPanel, BorderLayout.CENTER);

      //VISIBLE
      setVisible(true);

   }

   //CREATE THE FILE MENU
   public void createFile(){

      JMenuItem item;   
      fileMenu = new JMenu("File");
      fileMenu.setMnemonic(KeyEvent.VK_F);

      item = new JMenuItem("New");
      item.setMnemonic(KeyEvent.VK_N);
      item.addActionListener(new MenuListener());
      fileMenu.add(item);      

      item = new JMenuItem("Pause");
      item.setMnemonic(KeyEvent.VK_P);
      fileMenu.add(item);

      item = new JMenuItem("Unpause");
      item.setMnemonic(KeyEvent.VK_U);
      fileMenu.add(item);

      item = new JMenuItem("Exit");
      item.setMnemonic(KeyEvent.VK_X);
      item.addActionListener(new MenuListener());
      fileMenu.add(item);

   }

   //CREATE THE OPTIONS MENU
   public void createOptions(){

      JMenuItem item;
      optionsMenu = new JMenu("Options");      
      optionsGroup = new ButtonGroup();     

      item = new JRadioButtonMenuItem("Easy", true);
      optionsMenu.add(item);
      optionsGroup.add(item);

      item = new JRadioButtonMenuItem("Medium");
      optionsMenu.add(item);
      optionsGroup.add(item);      

      item = new JRadioButtonMenuItem("Hard");
      optionsMenu.add(item);
      optionsGroup.add(item);   
   }

   //START PANEL
   public void buildStartPanel(){

      //INITIALIZE
      startPanel = new JPanel();
      easyButton = new JRadioButton("Easy", true);
      mediumButton = new JRadioButton("Medium");
      hardButton = new JRadioButton("Hard");
      optionsGroup = new ButtonGroup();
      startButton = new JButton("Start");

      //LISTENERS
      easyButton.addActionListener(new RadioButtonListener());
      mediumButton.addActionListener(new RadioButtonListener());
      hardButton.addActionListener(new RadioButtonListener());
      startButton.addActionListener(new ButtonListener());

      //LINK OPTIONS GROUP
      optionsGroup.add(easyButton);
      optionsGroup.add(mediumButton);
      optionsGroup.add(hardButton);

      //ADD EVERYTHING TO THE PANEL
      startPanel.add(easyButton);
      startPanel.add(mediumButton);
      startPanel.add(hardButton);
      startPanel.add(startButton);
   }

   //PROGRESS BAR
   public void buildProgressPanel(){

      //INITIALIZE
      progressPanel = new JPanel();
      bombsLeftLabel = new JLabel("Remaining Mines: ");
      bombsLeftText = new JTextField(2);
      bombsLeftText.setEditable(false);
      timeLeftLabel = new JLabel("Time remaining: ");
      timeLeftText = new JTextField(4);
      timeLeftText.setEditable(false);

      progressPanel.setLayout(new FlowLayout(FlowLayout.CENTER));
      progressPanel.add(bombsLeftLabel);
      progressPanel.add(bombsLeftText);
      progressPanel.add(timeLeftLabel);
      progressPanel.add(timeLeftText);

      //SET REMAINING BOMBS/TIME
      remainingBombs = mines;
      bombsLeftText.setText(String.valueOf(remainingBombs));
      timePassed = time;
      timeLeftText.setText(String.valueOf(timePassed));
   }

   //MAIN GAME PANEL
   public void buildGamePanel(){

      //INITIALIZE
      gamePanel = new JPanel();
      gamePanel.setLayout(new GridLayout(sides, sides));
      cell = new Cell[sides][sides];

      //DRAW AND ADD CELLS TO CLICK
      for (int i = 0; i < sides; i++){
         for (int j = 0; j < sides; j++){
            cell[i][j] = new Cell();
            gamePanel.add(cell[i][j].getButton());
         }
      }

      //PLANT THE MINES!
      plantMines(); 
      setValue(); 

   }

   //PLANT THE MINES
   public void plantMines(){
      int rand_x;
      int rand_y;
      int plantedMine = 0;

      while(plantedMine < mines){
         //random x,y coords for planting
         rand_x = 0 + (int)(Math.random() * ((sides - 0)));
         rand_y = 0 + (int)(Math.random() * ((sides - 0)));

         //make sure there isn't already a bomb there
         if (cell[rand_x][rand_y].getMineValue() != -1){ 
            cell[rand_x][rand_y].setMineValue(-1);
            plantedMine++;
         } 
      }
   }

   //CHECK SURROUNDING CELLS
   public void checkForZero(){
      for (int i = 0; i < sides; i++){
         for (int j = 0; j < sides; j++){
            if (cell[i][j].getIsActive() == true){

               //N
               if (i > 0 && !cell[i-1][j].getIsActive()){
                  cell[i-1][j].checkMineValue();
               }
               //NW
               if (i > 0 && j < sides - 1 && !cell[i-1][j+1].getIsActive()){
                  cell[i-1][j+1].checkMineValue();
               }
               //W
               if (j < sides - 1 && !cell[i][j+1].getIsActive()){
                  cell[i][j+1].checkMineValue();
               }
               //SW
               if (i < sides - 1 && j < sides - 1 && !cell[i+1][j+1].getIsActive()){
                  cell[i+1][j+1].checkMineValue();
               }
               //S
               if (i < sides - 1 && !cell[i+1][j].getIsActive()){
                  cell[i+1][j].checkMineValue();
               }
               //SE
               if (i < sides - 1 && j > 0 && !cell[i+1][j-1].getIsActive()){
                  cell[i+1][j-1].checkMineValue();
               }
               //E
               if (j > 0 && !cell[i][j-1].getIsActive()){
                  cell[i][j-1].checkMineValue();
               }

            }
         }
      }
   }

   //SET VALUE OF THE CELLS
   public void setValue(){
      for (int i = 0; i < sides; i++){
         for (int j = 0; j < sides; j++){
            //if the cell we are checking is not a bomb
            if (cell[i][j].getMineValue() != -1){
               //NE
               if (i > 0 && j > 0 && cell[i-1][j-1].getMineValue() == -1){
                  cell[i][j].setMineValue(cell[i][j].getMineValue()+1);
               }
               //N
               if (i > 0 && cell[i-1][j].getMineValue() == -1){
                  cell[i][j].setMineValue(cell[i][j].getMineValue()+1);
               }
               //NW
               if (i > 0 && j < sides - 1 && cell[i-1][j+1].getMineValue() == -1){
                  cell[i][j].setMineValue(cell[i][j].getMineValue()+1);
               }
               //W
               if (j < sides - 1 && cell[i][j+1].getMineValue() == -1){
                  cell[i][j].setMineValue(cell[i][j].getMineValue()+1);
               }
               //SW
               if (i < sides - 1 && j < sides - 1 && cell[i+1][j+1].getMineValue() == -1){
                  cell[i][j].setMineValue(cell[i][j].getMineValue()+1);
               }
               //S
               if (i < sides - 1 && cell[i+1][j].getMineValue() == -1){
                  cell[i][j].setMineValue(cell[i][j].getMineValue()+1);
               }
               //SE
               if (i < sides - 1 && j > 0 && cell[i+1][j-1].getMineValue() == -1){
                  cell[i][j].setMineValue(cell[i][j].getMineValue()+1);
               }
               //E
               if (j > 0 && cell[i][j-1].getMineValue() == -1){
                  cell[i][j].setMineValue(cell[i][j].getMineValue()+1);
               }            
            }
         }
      }
   }

   //START OPTIONS
   private class RadioButtonListener implements ActionListener{
      public void actionPerformed(ActionEvent e){

         if (e.getSource() == easyButton){
            mines = 10;
            sides = 10;
         }else if (e.getSource() == mediumButton){
            mines = 30;
            sides = 15;
         }else if (e.getSource() == hardButton){
            mines = 99;
            sides = 25;
         }
      }
   }

   //MENU BAR LISTENER
   private class MenuListener implements ActionListener{

      public void actionPerformed(ActionEvent e){

         String actionCommand = e.getActionCommand();

         switch(actionCommand){
            case "New":
               if (!startPanel.isVisible()){
                  gamePanel.setVisible(false);
                  progressPanel.setVisible(false);
                  startPanel.setVisible(true);    
               }        
            break;

            case "Exit":

               System.exit(0);
            break;
         }
      }
   }

   //START GAME
   private class ButtonListener implements ActionListener{
      public void actionPerformed(ActionEvent e){

         if (e.getActionCommand() == "Start"){

            //leave start menu
            startPanel.setVisible(false);

            //build panels
            buildProgressPanel();
            buildGamePanel();

            //add to main panel
            add(progressPanel,BorderLayout.NORTH);
            add(gamePanel, BorderLayout.CENTER);  
         }
      }
   }

   //CLASS FOR EACH INDIVDUAL CELL
   public class Cell extends JFrame{
      private MineSweeper board;

      private JButton button;  //cell

      private JPanel buttonPanel;   //panel for the call

      private ImageIcon covered;
      private ImageIcon mine;
      private ImageIcon flag;
      private ImageIcon one;
      private ImageIcon two;
      private ImageIcon three;
      private ImageIcon four;
      private ImageIcon five;
      private ImageIcon six;
      private ImageIcon seven;
      private ImageIcon eight;

      private int mineValue; //-1 for bomb, 0 for empty cell, 1-8 for how many bombs the cell is touching
      private boolean isActive; //for checking cascading uncover
      private boolean isUncovered; //if we've left-clicked on the cell
      private boolean flagPlanted; //if we've right-clicked on the cell

      public Cell(){   
         setLayout(new BorderLayout());

         //ADD THE IMAGES
         covered = new ImageIcon(new ImageIcon("covered.png").getImage().getScaledInstance(35,35,Image.SCALE_DEFAULT));
         mine = new ImageIcon(new ImageIcon("mine.jpg").getImage().getScaledInstance(35,35,Image.SCALE_DEFAULT));
         flag = new ImageIcon(new ImageIcon("flag.png").getImage().getScaledInstance(35,35,Image.SCALE_DEFAULT));
         one = new ImageIcon(new ImageIcon("one.png").getImage().getScaledInstance(35,35,Image.SCALE_DEFAULT));
         two = new ImageIcon(new ImageIcon("two.png").getImage().getScaledInstance(35,35,Image.SCALE_DEFAULT));
         three = new ImageIcon(new ImageIcon("three.png").getImage().getScaledInstance(35,35,Image.SCALE_DEFAULT));
         four = new ImageIcon(new ImageIcon("four.png").getImage().getScaledInstance(35,35,Image.SCALE_DEFAULT));
         five = new ImageIcon(new ImageIcon("five.png").getImage().getScaledInstance(35,35,Image.SCALE_DEFAULT));
         six = new ImageIcon(new ImageIcon("six.png").getImage().getScaledInstance(35,35,Image.SCALE_DEFAULT));
         seven = new ImageIcon(new ImageIcon("seven.png").getImage().getScaledInstance(35,35,Image.SCALE_DEFAULT));
         eight = new ImageIcon(new ImageIcon("eight.png").getImage().getScaledInstance(35,35,Image.SCALE_DEFAULT));

         //CREATE BUTTON
         button = new JButton("");
         //SET ICON
         button.setIcon(covered);
         //LISTENER FOR MOUSE CLICKS
         button.addMouseListener(new MouseAdapter());
         //ADD TO PANEL
         add(button);
      }

      //GETTERS/SETTERS          
      public JButton getButton(){ return button; }      
      public int getMineValue(){ return mineValue; }
      public boolean getIsActive(){ return isActive; }  
      public void setMineValue(int mv){ this.mineValue = mv; }

      //CHECK VALUE OF THE CELL
      public void checkMineValue(){
         //bomb
         if (mineValue == -1){
            isUncovered = true;
            button.setIcon(null);
            button.setIcon(mine);
            System.out.print("You Lose");
         }
         //no bomb nearby
         if (mineValue == 0){
            isActive = true;
            isUncovered = true;
            checkForZero();
            button.setVisible(false);
         }
         //bomb nearby
         if (mineValue > 0){
            isUncovered = true;
            button.setIcon(null);
            if (mineValue == 1){ button.setIcon(one);}
            if (mineValue == 2){ button.setIcon(two);}
            if (mineValue == 3){ button.setIcon(three);}
            if (mineValue == 4){ button.setIcon(four);}
            if (mineValue == 5){ button.setIcon(five);}
            if (mineValue == 6){ button.setIcon(six);}
            if (mineValue == 7){ button.setIcon(seven);}
            if (mineValue == 8){ button.setIcon(eight);}
         }
      }

      //PLANT THE FLAG 
      public void plantFlag(){

         flagPlanted = true;
         isUncovered = true;
         //update progress
         remainingBombs -= 1;
         bombsLeftText.setText(String.valueOf(remainingBombs));
         //update icon
         button.setIcon(null);
         button.setIcon(flag);
         //check if done
         if (checkDone()){
            JOptionPane.showMessageDialog(null, "Game Over");
         }
      }

      //UNPLANT THE FLAG
      public void unplantFlag(){

         flagPlanted = false;
         isUncovered = false;
         //update progress
         remainingBombs += 1;
         bombsLeftText.setText(String.valueOf(remainingBombs));
         //update icon
         button.setIcon(null);
         button.setIcon(covered);
      }

      //CHECK IF WE'RE FINISHED
      public boolean checkDone(){

         for (int i = 0; i < sides; i++){
            for (int j = 0; j < sides; j++){
               if (!cell[i][j].isUncovered){
                  return false;
               }
            }
         }
         return true;

      }

      //LISTENER FOR CLICKING THE CELL
      private class MouseAdapter implements MouseListener{

         private boolean pressed;

         //MOUSE PRESSED
         public void mousePressed(MouseEvent e){
            pressed = true;
         }

         //MOUSE CLICKED
         public void mouseClicked(MouseEvent e){ 

            if (pressed){
               if (SwingUtilities.isLeftMouseButton(e)){
                  checkMineValue();
               }else if (SwingUtilities.isRightMouseButton(e)){
                  if (!isUncovered && !flagPlanted){
                     plantFlag();
                  }else if (isUncovered && flagPlanted){
                     unplantFlag();
                  }
               }
            }
            //HAVE WE CHECKED ALL THE CELLS?
            if (checkDone()){
               JOptionPane.showMessageDialog(null, "Game Over");
            }
         }

         public void mouseReleased(MouseEvent e){}
         public void mouseEntered(MouseEvent e){}
         public void mouseExited(MouseEvent e){}

      }
   }

   public static void main(String[] args){
      new MineSweeper();
   }
}
\$\endgroup\$
  • 3
    \$\begingroup\$ Before guessing, you should take some measurements, e.g. by simply building the difference between two System.currentTimeMillis() calls at the start and end of an operation. Not heeding my own advice here: I guess that the time lag is due to your loading of the icons in the constructor of every cell. You should probably load these once, and simply reference the icons you loaded. \$\endgroup\$ – mtj Apr 26 '18 at 8:57
  • \$\begingroup\$ @mtj Good guess! Such a simple fix that I couldn't see. I was looking at it as the cell class being built once and then being referenced multiple times, but I appear to have been wrong. \$\endgroup\$ – Sean Apr 26 '18 at 11:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.