Skip to content

Minesweeper V.1

The minesweeper project is one the first full projects that I made way back in my CS 2 course. It was a good introduction to the Model-View-Controller Architecture as well as java swing. Personally I think the real reason we were assigned to use Java swing for the GUI and Java for the Model is because this course is usually taken your second semester in this college meaning the people here do not have a lot of exposure to some of the more powerful language options. For example using Cpp and QT or even just Cpp for the Model and creating a pipeline to a C# GUI using WPF or some other matter. Both of these options however is a little more complicated then just utilizing Java Swing. Although with how long it takes for Swing to be updated(Since it only updates alongside the Java SDK), using Java Fx would be more suitable. Nevertheless this program was not well designed and when I made it I was just starting out writing programs.

For reference Minesweeper V.2 is in progress that will showcase the difference of ability from where I started in college to where I am at now.

Model – View – Controller

  • Model – This is the back end of the program in which the functions and data are stored.
  • View – This is what the user sees and interacts with.
  • Controller – This is the component that enables intractability between the Model and View. The View will send a callback command to the controller who handles calling the functions in the Model. The Model will then perform that action and update its internal data structure which in this case is just a double int array. Then the controller will call its update function to reflect the updated internal data back to the view.

The Model

Click here to Expand this section

    public MinesweeperClass() {
        board = new int[10][10];
        boardLoader(board);
        

        interactiveBoard = new String[10][10];
        falseBoardLoader(interactiveBoard);

        boardPrinter();
    }

Here we have the default constructor for the Minesweeper Class. It is a very simple setup. We first create our Gameboard’s internal data with the double int array. Then we Call Board Loader which loads the internal board array with either 0(Bomb) or 1(Safe). Then we create a double string array and set all of the cells as ‘?’ which we then call boardPrinter() that prints the current internal board to the console for debugging purposes. This was originally implemented to test the functionality of the game before I added in the GUI components.

Here is the Board Loader Function

    public void boardLoader(int[][] a) {// loads data board with information about mine positions
        int totalMinecount = 0;
        int rowMinecount = 0;

        for (int i = 0; i < 10; i++) {
            for (int j = 0; j < 10; j++) {
                if (totalMinecount == MINE_COUNT) {
                    a[i][j] = 0;
                } else {
                    if (j == 0 && i != 0) {
                        rowMinecount = 0;
                    }
                    if (Math.floor(Math.random() * 2) == 1 && rowMinecount < Math.floor(Math.random() * 3 + 1)) {
                        a[i][j] = 1;
                        totalMinecount++;
                        rowMinecount++;
                    } else {
                        a[i][j] = 0;
                    }
                }
            }
        }

    }

All this does is randomly populate the board until the final mine count variable has been reached. The weird math here is to try and encourage an even distrubution of mines along the game board or else the frequency was too high near the top.

Here is board printer

    public void boardPrinter() { // function that will print out board after command is called.

        for (int i = 0; i < 10; i++) {
            for (int j = 0; j < 10; j++) {
                if (i == 0 && j == 0) {
                    System.out.print("     ");
                    for (int m = 0; m < 10; m++) {
                        System.out.print("c ");
                    }
                    System.out.println();
                    System.out.print("     ");
                    for (int k = 0; k < 10; k++) {
                        System.out.print(k + " ");
                    }
                    System.out.println();
                }

                if (j == 0) {
                    System.out.println("");
                    System.out.print("r" + i + "   ");
                }
                System.out.print(interactiveBoard[i][j] + " ");
            }
        }
        if (gameoverflag) {
        } else {
            System.out.println();
        }
    }

All this does is iterate through our interactive board and print out the revealed tiles. If we end with a game over this wont update to console anymore. This function is called every time we update the board state so we can get a play by play to the console.

There are two pieces of code that do the majority of the work. This is check and findaround. All check does is make sure we are not in a game over state before then actually checking that square and returning the number of mines surrounding that actual square.

    public void check(int r, int c) {
    if(interactiveBoard[r][c] == "f"){
    
    } else if (board[r][c] == 1 ) {
            // give game over command, reveal on interactive board where mines are
            gameoverflag = true;
            gameover();

        }else{

            interactiveBoard[r][c] = String.valueOf(findAround(r, c));
            boardPrinter();
        }

    }

   public int findAround(int r, int c){//finds mine in 3x3 area around selected r/c
        //need edge cases corners, every side
        int numberOfMines = 0;
        if(r == 0 && c == 0  ){//top left corner edge case
            for(int i = r; i <= r+1 ; i++){
                for(int j = c; j <=c+1; j++){
                    if(board[i][j] == 1){
                        
                        numberOfMines++;
                    } 
                }
            }
        }else if(r == 9 && c == 9){//bottom right edge case
            for(int i = r-1; i <= r ; i++){
                for(int j = c-1; j <=c; j++){
                    if(board[i][j] == 1){
                        
                        numberOfMines++;
                    } 
                }
            }
        }else if(r == 9 && c == 0){//bottom left edge case
            for(int i = r-1; i <= r ; i++){
                for(int j = c; j <=c+1; j++){
                    if(board[i][j] == 1){
                       
                        numberOfMines++;
                    } 
                }
            }
        }else if(r == 0 && c == 9){//top right edge case
            for(int i = r; i <= r+1 ; i++){
                for(int j = c-1; j <=c; j++){
                    if(board[i][j] == 1){
                        
                        numberOfMines++;
                    } 
                }
            }
        }else if(c == 0){//left side edge case
            for(int i = r-1; i<= r+1; i++){
                for(int j = c; j<=c+1;j++){
                    if(board[i][j] == 1){
                        numberOfMines++;
                    } 
                }
            }
        
        }else if(c ==9){//right side edge case
            for(int i = r-1; i <= r+1; i++){
                for(int j = c-1; j<=c; j++){
                    if(board[i][j] == 1){
                        numberOfMines++;
                    } 
                }
            }
        }else if(r ==0){//top edge case
            for(int i = r; i<= r+1;i++){
                for(int j = c-1; j<= c+1; j++){
                    if(board[i][j] == 1){
                        numberOfMines++;
                    } 
                }
            }
        }else if(r == 9){//bottom edge case
            for(int i = r-1; i <= r; i++){
                for(int j = c-1; j<= c+1; j++){
                    if(board[i][j] == 1){
                        numberOfMines++;
                    } 
                }
            }
        }else{//general case
            for(int i = r-1; i <= r+1; i++){
                for(int j = c-1; j<=c+1; j++){
                if(board[i][j] == 1){
                    numberOfMines++;
             } 
            }
         }
        }

        return numberOfMines;
    }

Find around is easily the only real piece of logic code in the program and even then there is a lot wrong with this version of the minesweeper. For instance there are 8 separate edge cases that are checked that only pertain to 38 cells out of the 100 we populate for a 10 by 10 grid. That means 62% of the time we have to check 8 different cases before we get to the base case. This is highly inefficient and while sometimes this is necessary we can do better.