Pro-grammar
Pro-grammar

Reputation: 43

Minesweeper, How can I know how many 0's are next to each other?

What i want to do is be able to "turn" every 0 that's next to each other, just like the normal minesweeper game.

#include <cmath>
#include <cstdlib>
#include <iomanip>
#include <ctime>
#include <iostream>

int buscamina();
using namespace std;

int main() {
    buscamina();
  return 0;
}


int buscamina(){
  srand(time(NULL));

  int size=12, minastot=10;
  int tablero[size][size];
  char lqeuv[size-2][size-2];
  int x, y, cm=0;

  for(int i=0; i<size-2; i++)
    for(int j=0; j<size-2; j++)
      lqeuv[i][j]=88;

  for(int i=0; i<size; i++)
    for(int j=0; j<size; j++)
      tablero[i][j]=0;

  for(int i=0; i<minastot; i++){
    int a=0, b=0;

    a=rand()%(size-2);
    b=rand()%(size-2);
    ++a;  ++b;

    if(tablero[a][b]==9)
      minastot++;

    tablero[a][b]=9;
  }

  for(int i=0; i<size; i++)
    for(int j=0; j<size; j++)
      if(tablero[i][j]==9)
        for(int a=i-1; a<i+2; a++)
          for(int b=j-1; b<j+2; b++)
            if(tablero[a][b]!=9)
              tablero[a][b]++;

  for(int i=0; i<size; i++)
    for(int j=0; j<size; j++)
      if(tablero[i][j]==9)
        ++cm;

  do{
    cout << endl;
    cout << setw(5);
    for(int i=0; i<size-2; i++)
      cout << i << " ";
    cout << endl << endl;
    for(int i=0; i<size-2; i++){
      cout << i << setw(4);
      for(int j=0; j<size-2; j++)
        cout << lqeuv[i][j] << " ";
      cout << endl;
    }

    do {
      cout << "Coordenadas: ";
    } while(scanf("%d %d", &x, &y)!=2);

    if(tablero[x+1][y+1]==0)
      lqeuv[x][y]=32;
    else
    lqeuv[x][y]=(tablero[x+1][y+1]+48);

  }while (tablero[x+1][y+1]!=9);

  for(int i=0; i<size; i++){
    for(int j=0; j<size; j++)
      cout << tablero[i][j] << " ";
    cout << endl;
  }
  return 0;
}

So let's say the user enters the coordinates 0 2, and it happens to be a zero, what i want to do is to be able to not only change that particular coordinate from X into a blank space, but also all the other 0's that are next to it, just like the regular Minesweeper, also the variable names i used are in spanish, so let me type a translation too.

Upvotes: 2

Views: 379

Answers (1)

Maroš Beťko
Maroš Beťko

Reputation: 2329

For this you can use a flood fill algorithm. Start it from a position player picks and then flood fill all the tiles around it that also has a zero.

Also what I would strongly suggest is to use 'X' and ' ' instead of 88 and 9. Placing the tiles into struct that can tell you what is inside, what is showing, if it was picked and how many neighbouring mines it has would be really useful, but that was not the point of this question.

So here is a modified version I've made:

#include <cmath>
#include <cstdlib>
#include <iomanip>
#include <ctime>
#include <iostream>

using namespace std;

template <size_t size>
class Buscamina {
public:
    Buscamina() : minastot(3) {}

    void run() {
        srand(time(NULL));
        int x, y, cm=0;

        // Fill draw with X
        for(int i=0; i<size; i++)
            for(int j=0; j<size; j++)
                lqeuv[i][j]= 'X';

        // Fill mines with empty
        for(int i=0; i<size; i++)
            for(int j=0; j<size; j++)
                tablero[i][j]=0;

        // Generate mines
        for(int i=0; i<minastot; i++){
            int a=0, b=0;

            a=rand()%(size-2);
            b=rand()%(size-2);
            ++a;  ++b;

            if(tablero[a][b]==9)
                minastot++;

            tablero[a][b]=9;
        }

        // Set count of surrounding mines
        for(int i=0; i<size; i++)
            for(int j=0; j<size; j++)
                if(tablero[i][j]==9)
                    for(int a=i-1; a<=i+1; a++)
                        for(int b=j-1; b<=j+1; b++)
                            if(tablero[a][b]!=9)
                                tablero[a][b]++;

        // Set total mines
        for(int i=0; i<size; i++)
            for(int j=0; j<size; j++)
                if(tablero[i][j]==9)
                    ++cm;

        // Main loop
        do{
            // Print table
            cout << endl;
            cout << setw(5);
            for(int i=0; i<size; i++)
                cout << i << " ";
            cout << endl << endl;
            for(int i=0; i<size; i++){
                cout << i << setw(4);
                for(int j=0; j<size; j++)
                    cout << lqeuv[i][j] << " ";
                cout << endl;
            }

            // Get input
            do {
                cout << "Coordenadas: ";
            } while(scanf("%d %d", &x, &y)!=2);

            // Pick a mine
            floodfill(x, y);

        }while (tablero[x][y]!=9);

        for(int i=0; i<size; i++){
            for(int j=0; j<size; j++)
                cout << tablero[i][j] << " ";
            cout << endl;
        }
    }

    void floodfill(int x, int y) {
        if (x < 0 || y < 0 || x >= size  || y >= size || lqeuv[x][y] != 'X')
            return;
        if (tablero[x][y] == 0) {
            lqeuv[x][y] = ' ';
            floodfill(x, y - 1);
            floodfill(x - 1, y);
            floodfill(x + 1, y);
            floodfill(x, y + 1);
        } else {
            lqeuv[x][y]=(tablero[x][y]+48);
        }

    }

    int minastot;
    int tablero[size][size];
    char lqeuv[size][size];
};

int main() {
    Buscamina<10> game;
    game.run();
    return 0;
}

I've put you whole buscamina function into a class so I can easily access the 2 arrays. Also I've made the two arrays the same size and included range guards. Having them of different size made it really unnecesarily difficult to work with.

If you don't want to use class you can always make floodfill non-member function just like your buscamina was and add 2 arguments, passing in a reference to lqeuv and tablero.

So the solution to your problem is in flood fill function. You simply call it on x and y player entered. First it does a bounds check and also checks if the tile wasn't already picked. If yes it simply returns. Then just like in your version it checks if the tile is 0. If it is it sets the lqeuv to ' ' and calls itself for all 4 surrounding tiles. This makes it so all connected tiles with 0 will be set to ' '. Then if the tile has a neighbouring mine (therefore tablero != 0) it sets lqeuv to the said number.
And the result for input 0 0 looks like this:

    0 1 2 3 4 5 6 7 8 9 

0                       
1       1 1 2 1 1       
2       1 X X X 1       
3       1 X X X 1       
4         1 X 1         
5         1 X 1         
6         1 1 1         
7                       
8                       
9 

If you have any other questions feel free to ask. Also if you would like some tips on how to organize your program better, I will be happy to help.

Upvotes: 1

Related Questions