-2

I've been working on my minesweeper project and I seem to be running into a little trouble. My program compiles, but my problem is setting the mines on my grid. I have used a random generator to set the positions, but I don't know how to implement it on my grid. What I want the program to do is when a block with a bomb is hit, its visibilty should change and a black square should show up under. Here's my code so far:

import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;

public class Minesweeper extends JFrame implements ActionListener {

    public int gridRows; // 
    public int gridColumns; //
    int mines;
    private int numMines;
    private int row, col;
    boolean secondTime;
    JMenuItem Expert, Intermediate, Easy;
    JButton[][] easyGrid; // 2d array for button grid.
    boolean[][] setMine = new boolean[row][col];
    int numberMine[][];

    public static void main(String[] args) {
        // creates frame
        Minesweeper gameWindow = new Minesweeper();
        gameWindow.setSize(400, 400);
        gameWindow.setVisible(true); // sets the visibility of the game board to true.
    }

    public Minesweeper() {
        super("Minesweeper");
    }

// class constructor.
    public void init() {

        // variables set the size of the playing board
        int rowsX = 9;
        int columnsY = 9;

        gridRows = rowsX;
        gridColumns = columnsY;

        setLayout(new GridLayout(rowsX, columnsY)); // creates and sets a grid format.
        easyGrid = new JButton[rowsX][columnsY]; // sets the grid size from the parameters given

        // loops through rows and columns to draw grid.
        for (int i = 0; i < columnsY; i++) {
            for (int j = 0; j < rowsX; j++) {
                row = i;
                col = j;
                easyGrid[i][j] = new JButton(""); //creates new button    
                easyGrid[i][j].addActionListener(this); // assigns an action to the grid buttons
                add(easyGrid[i][j]);  // adds buttons to the game board 
            }
        }


        JMenu gameMenu = new JMenu("GameOptions"); // creates menu option

        // creating each option under the JMenuBar (toolBar)
        JMenuItem easyChoice = new JMenuItem("Beginner(9x9)");
        easyChoice.addActionListener(this);
        gameMenu.add(easyChoice); // adds choice option to the drop down menu
        Easy = easyChoice;

        // button selects a 16 by 16 grid for intermediate players
        JMenuItem mediumChoice = new JMenuItem("Intermediate(16x16)");
        mediumChoice.addActionListener(this);
        gameMenu.add(mediumChoice); // adds choice option to the drop down menu
        Intermediate = mediumChoice;

        // button selects a 16 by 30 grid for more advanced players
        JMenuItem hardChoice = new JMenuItem("Advanced(16x30)");
        hardChoice.addActionListener(this);
        gameMenu.add(hardChoice); // adds choice option to the drop down menu
        Expert = hardChoice;

        JMenuBar toolBar = new JMenuBar();
        toolBar.add(gameMenu);
        setJMenuBar(toolBar);

        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // sets the button for exiting the program.
        pack(); // set frame size.
    }

// lays out the mines on the grid.
    public void createMines() {
        java.util.Random rand = new java.util.Random();     // Random class 
        int rndm1;
        int rndm2; // gives the co-ordinates of the mine 


        for (int countBomb = 0; countBomb <= mines; countBomb++) {
            rndm1 = rand.nextInt(8) + 1; // pick a row (+1 for buffer compensation)
            rndm2 = rand.nextInt(8) + 1; // pick a col

            if (!easyGrid[gridRows][gridColumns].equals(setMine[rndm1][rndm2])) {
                setMine[rndm1][rndm2] = true;
                easyGrid[rndm1][rndm2].setVisible(true);
                // checks if there is no bomb present already.
            }
        }
    }

// this method redirects the user based on a selection made from the drop down menu
    public void actionPerformed(ActionEvent event) {


        if (event.getSource() instanceof JButton) {

            ((JButton) event.getSource()).setVisible(false);

        }

        if (event.getSource() == Easy) {
            gridRows = 30;
            gridColumns = 16;
            mines = 99;
            secondTime = true;
            init();
        } else if (event.getSource() == Intermediate) {
            gridColumns = gridRows = 16;
            mines = 40;
            secondTime = true;
            init();
        } else if (event.getSource() == Expert) {
            gridRows = gridColumns = 8;
            mines = 10;
            secondTime = true;
            init();
        }

    }
}
Jonas
  • 121,568
  • 97
  • 310
  • 388
Lou
  • 21
  • 1
  • 2
  • Can you try to isolate which code block is causing you problems and paste only that? I doubt there will be many people who will try to read all your code. – Andrey Adamovich Sep 18 '11 at 09:45
  • 3
    You have made no effort to provide a [SSCCE: Short Self-Contained Correct Example](http://pscode.org/sscce.html). Please reduce your code! – Bohemian Sep 18 '11 at 12:16
  • Actually compared to some, the amount of code here is not that great, but the OP would help us out a lot if he at least told us where specifically the problem is -- if he provided a little more detail on his problem. – Hovercraft Full Of Eels Sep 18 '11 at 13:55

3 Answers3

4

It looks like you're trying to implement your program all in one class, and I strongly urge you not to do this, but rather to subdivide the code into several classes divided along natural divisions.

When I've done this myself, I've first created both "model" non-GUI classes and their respective GUI classes to try to separate out the logic from the display.

You can see my code here: minesweeper-action-events

For instance one class is called MineCellModel that has three bound boolean properties or states, flagged (the user right clicks it to "flag" it and button can't be pressed), pressed, and mineBlown, and one non-bound property/state: mined. The latter is not bound since as it doesn't change during game play, there is no need to listen to it with a PropertyChangeListener during game play.

This model is then used by a MineCell object a GUI class that extends JPanel and holds a JLabel (to hold the underlying number) and a JButton that is initially displayed. It adds a PropertyChangeListener to it's model to listen for change in state, and responds to changes in state by changing its display. For example, if the flagged state becomes true, a MineCell will display a flag image on the JButton, and the button will become unresponsive to button presses. I've had good success using a CardLayout to best swap what the mine cells' display. For instance, all cells initially can display a JButton whose Icon can be swapped by right mouse click via a MouseListener. Then when the button is clicked with the left mouse key (using an ActionListener) I use CardLayout to display a JLabel that either has an image icon of a mine or shows a number.

There's also a MineCellGridModel which holds the non-GUI logic of the entire grid. It holds a 2-dimensional array of MineCellModel objects as well as a ArrayList of mines. It too adds a PropertyChangeListener to all the MineCellModels it holds checking for button press events. If they occur, it checks for a game win or not. Here it also reacts to a mine blown event, or game lost, and has the grid to display all blown mines. Finally it reacts to a button press where the mine cell model's value is 0 (it has no neighbors who are mines) and in this situation it recursively calls a pressedAction on all the mine cell models that surround it, causing a cool effect of cascading mine button presses sometimes clearing a large swath of buttons off the grid.

Then there's a MineCellGrid, the GUI view class for the grid that uses the above class as its model, and lastly a MineSweeper class that puts the whole shebang together and displays it in a JFrame.

With regard to randomizing the mines, every class of mine has a reset() method that sets it back to its starting state, and this includes the MineCellGridModel class which randomizes an ArrayList that holds an array list of Booleans, one for each cell in the grid. It simply shuffles the arraylist and then iterates through the cellModelGrid assigning mines using the array list. I then iterate again through cellModelGrid and if I find a cell that's mined, I increment the "value" of its immediate neighbors -- the number that keeps track of how many neighbors are mined:

   public void reset() {
      buttonsRemaining = (maxRows * maxCols) - mineNumber;

      // randomize the mine location
      Collections.shuffle(mineList);
      // reset the model grid and set mines
      for (int r = 0; r < cellModelGrid.length; r++) {
         for (int c = 0; c < cellModelGrid[r].length; c++) {
            cellModelGrid[r][c].reset();
            cellModelGrid[r][c].setMined(mineList.get(r
                     * cellModelGrid[r].length + c));
         }
      }
      // advance value property of all neighbors of a mined cell
      for (int r = 0; r < cellModelGrid.length; r++) {
         for (int c = 0; c < cellModelGrid[r].length; c++) {
            if (cellModelGrid[r][c].isMined()) {
               int rMin = Math.max(r - 1, 0);
               int cMin = Math.max(c - 1, 0);
               int rMax = Math.min(r + 1, cellModelGrid.length - 1);
               int cMax = Math.min(c + 1, cellModelGrid[r].length - 1);
               for (int row2 = rMin; row2 <= rMax; row2++) {
                  for (int col2 = cMin; col2 <= cMax; col2++) {
                     cellModelGrid[row2][col2].incrementValue();
                  }
               }
            }
         }
      }
   }
Community
  • 1
  • 1
Hovercraft Full Of Eels
  • 283,665
  • 25
  • 256
  • 373
  • Thanks for the thorough explanation HoverCraft Full of Eels, i have a good idea of what i am doing now. – Lou Sep 18 '11 at 14:53
  • +1 very thorough; cg. this [version](http://pragmada.home.mchsi.com/mindet.html) in Ada. – trashgod Sep 18 '11 at 20:08
2

Because it implements a two-state button, JToggleButton may be a useful alternative for this. You may get some ideas from this related game.

trashgod
  • 203,806
  • 29
  • 246
  • 1,045
1

EDIT: I just realized that JButton has an icon field which you could use for your icon.

Perhaps have a for loop to create a grid of square image buttons, one way to make image buttons can be found here, although you could probably find many libraries with ready made gui elements as such.

I would use a 2d array to store the buttons. Each button would have a few fields such as:

boolean revealed = false; //default value
boolean isMine = false;   //default value

Then you could change the button graphics to show a mine/flag or whatever, called by the mouse click event handler.

WaelJ
  • 2,942
  • 4
  • 22
  • 28