Search code examples
javaalgorithmrecursionhelperminesweeper

Java MineSweeper console Recursion Error


I'm new to Stack overflow.

I have been having trouble with my minesweeper text-based program, and I just can't get my recursion to work in the way I want it to.

Can someone help me with my recursion for revealing all cells that are blank and are neighbors to the "clicked" cell?

The problem with my code is that everytime I reveal a spot within the 10 by 10 board,

for example:

when you input r to reveal, and put in the row 3 and column 3

the code reveals all locations of the map excluding the mines, instead of reveal only the numbers nearby and not connected to other 'blank' locations.

These are outdated now

The output should be:

 1|  .  .  .  .  .  .  .  .  .  . 
 2|  .  .  .  .  .  .  .  .  .  . 
 3|  .  .  3  .  .  .  .  .  .  . 
 4|  .  .  .  .  .  .  .  .  .  . 
 5|  .  .  .  .  .  .  .  .  .  . 
 6|  .  .  .  .  .  .  .  .  .  . 
 7|  .  .  .  .  .  .  .  .  .  . 
 8|  .  .  .  .  .  .  .  .  .  . 
 9|  .  .  .  .  .  .  .  .  .  . 
10|  .  .  .  .  .  .  .  .  .  . 
     1  2  3  4  5  6  7  8  9 10 

However the actual output is:

 1|  1  1  1  1  1  1  0  0  0  0 
 2|  1  .  1  1  .  1  0  0  0  0 
 3|  2  3  3  2  2  2  1  0  0  0 
 4|  1  .  .  1  1  .  2  1  1  0 
 5|  1  3  3  2  2  2  3  .  2  1 
 6|  0  2  .  2  1  .  3  3  .  1 
 7|  0  2  .  2  1  1  2  .  2  1 
 8|  1  2  3  2  1  0  1  1  1  0 
 9|  2  .  4  .  1  1  1  2  1  1 
10|  2  .  .  2  1  1  .  2  .  1 
     1  2  3  4  5  6  7  8  9 10 

These are my guidelines for recursion:

Recursive algorithm for minesweeper

When the user clicks on a cell

If the cell hasn't yet been revealed, reveal it

If the true nature of the cell is a mine, game over

Otherwise if the true nature of the cell is blank, then recursively reveal each its 8 neighbors if they are within bounds and haven't been revealed.

This algorithm naturally uncovers all adjacent empty cells and terminates when it reaches number cells on the edges.

here is my new Code:

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Scanner;

public class P4_Icel_Murad_MinesweeperConsole {
     char resp = ' ';
     int row =  0;
     int col = 0;
     final static int MINES = 5;
     public boolean won = false;
     public boolean fail = false;
    public static void main(String[] args) {

        P4_Icel_Murad_MinesweeperConsole hello = new P4_Icel_Murad_MinesweeperConsole(10, MINES);
        System.out.println();
        hello.revealBoard();
    }


        private static class Cell {

            final int FLAGGED = 1;
            final int QUESTION = 2;
            final int BLANK = 3;


            public boolean hidden = true;
            public final boolean mine;
            public int flagType;
            public int neighbors = 0;


            public Cell(boolean mine) {
                this.mine = mine;
            }
            public void setFlag(int myFlagType){
                if(myFlagType == 1){
                    this.flagType = myFlagType;
                }else if (myFlagType == 2) {
                    this.flagType = myFlagType;
                }else if (myFlagType == 3) {
                    hidden = true;
                    this.neighbors = myFlagType;
                }
            }
            public boolean getflagType(int i) {
                if(i == 1){
                    return true;
                }else
                return false;
            }
        }

        private final int size;
        private Cell[][] board;

        private void revealBoard(){
            for (int i = 0; i < board.length; i++) {
                for (int j = 0; j < board[0].length; j++) {
                    Cell f = board[i][j];
                    f.hidden = false;

                }
            }
            showBoard();
        }
        private void revealCell(int i, int j){          
                    Cell f = board[i][j];
                    f.hidden = false;
                    f.setFlag(0);

        }



        private P4_Icel_Murad_MinesweeperConsole(int size, int numberOfMines) {
            this.size = size;
            initBord(numberOfMines);
            showBoard();
            while(!won && !fail){
                questionAsk();
                showBoard();
            }
        }

        private void questionAsk(){
            Scanner s = new Scanner(System.in);
            System.out.println("Would you like to flag a cell or reveal a cell?");
            System.out.println("Enter 'f' or 'r': >");
            resp = s.next().charAt(0);
             System.out.println("Enter row: ");
             row = s.nextInt() - 1;
             System.out.println("Enter col: ");
             col = s.nextInt() - 1;
             if(row > size || col > size){
                 System.out.println("This row/col amount is too high.");
                 showBoard();
                 questionAsk();
             }
             userInput(row,col,true);
        }
        private void initBord(int numberOfMines) {
            List<Cell> mines = new ArrayList<Cell>();
            for (int i = 0; i < size * size; i++) {
                mines.add(new Cell(i < numberOfMines));
            }
            Collections.shuffle(mines);
            board = new Cell[size][size];
            for (int i = 0; i < size; i++) {
                for (int j = 0; j < size; j++) {
                    board[i][j] = (i == 0 || j == 0 || i == size || j == size)
                            ? new Cell(false)
                            : mines.remove(0);
                }
            }
            calculateNeighbors();
        }
        // F>HIDDEN IS DONE ONLY FOR ONE POS, MUST FIX
        private void userInput(int row, int col, boolean revealMines){
            Cell f = board[row][col];
            if (resp == 'r') {
                if (f.mine && !revealMines) {
                    return;
                }
            if (f.hidden) { 
                revealCell(row,col);

                if(f.mine){
                    failed();   
                }else if (f.neighbors == 0){

                        if (isInBounds(row + 1,col)){
                            Cell neighbor = board[row + 1][col];
                            if (neighbor.hidden && neighbor.neighbors == 0) {
                                userInput(row + 1,col,false);
                            }else if (neighbor.hidden && !neighbor.mine){
                                revealCell(row + 1,col);
                            }
                        }
                        if (isInBounds(row - 1,col)){
                            Cell neighbor = board[row - 1][col];
                            if (neighbor.hidden && neighbor.neighbors == 0) {
                                userInput(row - 1,col,false);
                            }else if (neighbor.hidden && !neighbor.mine){
                                revealCell(row - 1,col);
                            }
                        }
                        if (isInBounds(row,col - 1)){
                            Cell neighbor = board[row][col - 1];
                            if (neighbor.hidden && neighbor.neighbors == 0) 
                            userInput(row,col - 1,false);
                            else if (neighbor.hidden && !neighbor.mine){
                                revealCell(row,col-1);
                            }
                        }
                        if (isInBounds(row , col + 1)){
                            Cell neighbor = board[row][col + 1];
                            if (neighbor.hidden && neighbor.neighbors == 0) 
                            userInput(row,col + 1,false);   
                            else if (neighbor.hidden && !neighbor.mine){
                                revealCell(row,col+1);
                            }
                        }
                        if (isInBounds(row - 1,col - 1)){
                            Cell neighbor = board[row - 1][col - 1];
                            if (neighbor.hidden && neighbor.neighbors == 0) 
                            userInput(row - 1,col - 1,false);
                            else if (neighbor.hidden && !neighbor.mine){
                                revealCell(row -1 ,col - 1);
                            }
                        }
                        if (isInBounds(row + 1,col - 1)){
                            Cell neighbor = board[row + 1][col - 1];
                            if (neighbor.hidden && neighbor.neighbors == 0) 
                            userInput(row + 1,col - 1,false);
                            else if (neighbor.hidden && !neighbor.mine){
                                revealCell(row + 1 ,col - 1);
                            }
                        }
                        if (isInBounds(row + 1,col + 1)){
                            Cell neighbor = board[row + 1][col + 1];
                            if (neighbor.hidden && neighbor.neighbors == 0) 
                            userInput(row + 1,col + 1,false);
                            else if (neighbor.hidden && !neighbor.mine){
                                revealCell(row + 1 ,col + 1);
                            }
                        }
                        if (isInBounds(row - 1,col + 1) && f.hidden){
                            Cell neighbor = board[row - 1][col + 1];
                            if (neighbor.hidden && neighbor.neighbors == 0) 
                            userInput(row - 1,col + 1,false);   
                            else if (neighbor.hidden && !neighbor.mine){
                                revealCell(row - 1 ,col + 1);
                            }
                        }

                }

            }
            }
            if(resp == 'f'){
                if (f.hidden) {
                    f.setFlag(1);
                    revealCell(row,col);

                }else if(f.flagType == 1){
                    f.setFlag(2);
                }else if(f.flagType == 2){
                    f.setFlag(3);
                }else if(f.flagType == 3){
                    f.setFlag(1);
                }

            }
            for (int i = 0; i < board.length; i++) {
                for (int j = 0; j < board.length; j++) {
                if(f.getflagType(1) == f.mine)
                    won = true;
                }
            }



                }



        private boolean isInBounds(int row, int col){
            if((row < size && row >= 0) && (col < size && col >= 0)){
                return true;
            }
            return false;
        }



        private void failed(){
            System.out.println("You Lost! :(");
            fail = true;
        }


        private void calculateNeighbors() {
            int count = 0;
            for (int i = 0; i < size; i++) {
                for (int j = 0; j < size; j++) {            
                    for (int di = -1; di <= 1; di++) {
                        for (int dj = -1; dj <= 1; dj++) {
                            if(isInBounds(i + di,j + dj))
                                if (board[i + di][j + dj].mine) count++;  
                        }
                    }
                    board[i][j].neighbors = count;
                    count = 0;
                }
            }

        }

        private void showBoard() {
            for(int i = 0; i < size; i++) {
                System.out.printf("%2d| ",i + 1);
               for(int j = 0; j < size; j++) {
                   Cell f = board[i][j];
                   if(f.hidden || f.flagType == 3) {
                       System.out.printf("%3s",". ");
                   }  else if (f.mine) {
                       System.out.printf("%3s","* ");
                   } else if (f.flagType == 1){
                       System.out.printf("%3s","F ");
                   }else if (f.flagType == 2){
                       System.out.printf("%3s","? ");
                   }else{
                       calculateNeighbors();
                       System.out.printf("%3s", f.neighbors + " ");
                   }
               }          
               System.out.println();
            }
            System.out.print("    ");
            for(int i = 0; i < size; i++) {
                System.out.printf("%3s",i + 1 + " ");
            }
            System.out.println();
        }

    }





Thank you in advance.

Solution

  • You just need to pass a boolean to your userInput function indicating whether or not to reveal mines. If the function is called with actual user input, you should pass true, because the mine should be revealed and it should be game over. If the function is called recursively, pass false, because you only want to recursively reveal empty cells.

    Test like this:

    private void userInput(int row, int col, boolean revealMines){
        Cell f = board[row][col];
        if (resp == 'r') {
    
            // if this cell is a mine and we are not revealing mines, return:
            if (f.mine && !revealMines)
                return;
    
            if (f.hidden) {
    

    Call like this in the questionAsk function:

     userInput(row,col,true);
    

    and false when called recursively.