Home > Software design >  Minesweeper in C using matrix
Minesweeper in C using matrix

Time:10-06

I need to make a minefield but without gameplay, just showing the map. First I made a matrix, allocated it (i didn't show the code to get smaller) and asked the user to enter with the rows and columns and the number of bombs.

I need to:

  1. allocate the bombs in this matrix
  2. distribute them randomly
  3. then make the positions 1,2,3 on the map indicate the amount of bombs nearby, but I'm not able to develop, can someone help me?
#include <stdio.h>
#include <stdlib.h>

int main()
{
    int i, j, rows, columns, bombs;
    int **m;
    int ro, col;

    printf("\Enter the rows: ");
    scanf("%d", &rows);
    printf("Enter the columns:");
    scanf("%d", &columns);
    printf("Enter the bombs:");
    scanf("%d", &bombs);

    if (bombs>= (rows*colums)){
        printf("Error");
        exit(1);
    }
    if (bombs<= 0){
        printf("Error);
        exit(1);
    }
    
    m = alocMatrix(rows, columns);

    for (i = 0; i < rows; i  )
    {
        for (j = 0; j < columns; j  )
        {
            m[i][j] = rand() % 4;
        }
    }  

    while(bombs> 0) // random bombs
    {
    lin = rand() % rows;
    col = rand() % columns;
}

    // show the map //

    for (i = 0; i < rows; i  )
    {
        for (j = 0; j < columns; j  )
        {
            printf("%d", m[i][j]);
   
        }

        printf("\n\n");
    }  
    for (i = 0; i < rows; i  )
    {
        free (m[i]);
    }
    free (m);
    return 0;
}
``

CodePudding user response:

How about using this function to place the bombs? Call it by passing the address of m. Keep in mind that marking the rest of the squares with the appropriate number has to happen after the bombs have been placed (and it shouldn't depend on a call to rand). Also, the map has to be initialized to avoid surprises.

void placeBombs(int*** map, int numOfRows, int numOfColumns, int numOfBombs)
{
    while (numOfBombs > 0) {
        int column = rand() % numOfColumns;
        int row = rand() % numOfRows;
        if ((*map)[row][column] != -1) {
            (*map)[row][column] = -1;
            --numOfBombs;
        }
        /* Else, if a bomb already exists in the cell,
         * we iterate without placing a bomb
         */
    }
}

CodePudding user response:

Data Structures

Instead of using an int then remembering magical numbers like -1 indicates a mine, it's more natural to say what these mean explicitly. Then you can change your mind or add to it without worrying about rewriting your whole programme. In the whole minefield, it's useless to have int **m without cols and rows. This interdependence is a sign that you should also package them in a structure to pass as one variable.

struct tile { unsigned nearby : 4, is_mine : 1, is_revealed : 1; };
struct map { size_t x, y; struct tile **tile; };

These definitions are very similar to what you had before, but they express the intent of the code much better.

Arrays

I would forget your complicated alocMatrix and just use one allocation, but then you have to use tiles[y * map->x x]. Personal preference; I think it's easier to have a constructor that returns one allocated block.

struct map { size_t x, y; struct tile *tile; };
...
if(!(map = malloc(sizeof *map   sizeof *tile * x * y)))
    { if(!errno) errno = ERANGE; return 0; }
...
map->tile = (struct tile *)(map   1);
memset(map->tile, 0, sizeof *tile * x * y);

Mines

A method of laying mines uniformly at random is to repeatedly choose a random tile, throwing out the tiles you've seen. Another method is to visit all the tiles and calculate the probability of each, P(mines left / tiles left). It depends on the number of mines which will be faster.

const size_t x1 = map->x, y1 = map->y;
size_t x, y, squares = x1 * y1;
assert(map && mines < squares);
for(x = 0; x < x1; x  ) {
    for(y = 0; y < y1; y  ) {
        struct tile *tile = &map->tile[y * x1   x];
        tile->is_revealed = 0;
        tile->is_mine = rand() < RAND_MAX / squares * mines;
        mines -= tile->is_mine;
        squares--;
    }
}
for(x = 0; x < x1; x  ) for(y = 0; y < y1; y  )
    map->tile[y * x1   x].nearby =
    (x && y && map->tile[(y-1) * x1   (x-1)].is_mine)  
    ...
    (x && y < y1 - 1 && map->tile[(y 1) * x1   (x-1)].is_mine);

CodePudding user response:

If constraints are small, see the 2-D matrix as 1-D matrix with n*m values. use a random function to get a value in 1-D, remove it and allocate a bomb in the same position in 2-D. Repeat this till number of bombs are over. Use some function to convert back the values (like : (x/n) --> row, (x%m) --> col). finally run the loop over matrix and search in all 8 corners to see how many bombs are there.

  • Related