Search code examples
crecursionminesweeper

Minesweeper revealing cells in C


I am trying to write a minesweeper program in C. What I am trying to achieve here is when user steps on one cell, the cells near without bombs and hint numbers will be revealed. For example, if x is the cell stepped on, o is an empty but concealed square, . is an empty but revealed cell and * is the bomb (hidden when playing of course):

x o o o o
o o o * o
o o o o o

will result in:

. . 1 o o
. . 1 * o
. . 1 o o

Here is part of the code:

while (1)
{
    printf("Row? ");
    scanf("%d", &row);
    printf("column? ");
    scanf("%d", &clos);
    if (row < 9 && row >= 0 && clos < 8 && clos >= 0)
        break;
    printf("\nInvalid Location\n\n");
}

if (real_map[row][clos] =='*')
{
    print_map_win(display_map,real_map);
    printf("\n");
    printf("Flags Left = %d\n\n\n", flag_left);
    printf("Game Over\n");
    exit(0);
}
else
{
    if (real_map[row][clos] == ' ')
    {
        display_map[row][clos] = real_map[row][clos];
        bonos_reveal(display_map, real_map, clos, row);
        // [[[bonos_reveal is the function I am asking for]]]
        printf("\n");
    }
    else
    {
        display_map[row][clos] = real_map[row][clos];
    }
}

in which real_map has the hint number and bombs in it, and display_map is the current state of the map.
edit: I have the following code, and it only reveals in one direction:

int bonos_reveal(int disp_map[MAP_ROWS][MAP_COLS], int real_map[MAP_ROWS][MAP_COLS], int clos, int row)
{
    disp_map[row][clos] = real_map[row][clos];

    if (row < 9 && row >= 0 && clos < 8 && clos >= 0)
    {
        if (real_map[row][clos+1] == ' ')
        {
            bonos_reveal(disp_map, real_map, clos + 1, row);
        }
        else
        {
            disp_map[row][clos+1] = real_map[row][clos+1];
            return 1;
        }
    }
    else
    {
        return 1;
    }
    return 1;
}

I have no idea how to loop through the cells.


Solution

  • Okay, here's an example implementation. It uses the following values for tiles:

    • 0 to 8: an unmined tile; the number represents the pre-calculated number of adjacent mines
    • 9: a mine; this special value is defined as BOMB.

    Covered tiles have 10 added to that, flagged tiles (not used here) have 20 added to that. You can test whether a tile is mined with:

    board[row][col] % 10 == BOMB
    

    I'll let the code do the explaining:

    #include <stdlib.h>
    #include <stdio.h>
    #include <time.h>
    
    #define ROWS 12
    #define COLS 20
    #define BOMBS 8
    
    #define BOMB 9
    
    void inc(int board[ROWS][COLS], int row, int col)
    {
        if (row < 0 || row >= ROWS) return;
        if (col < 0 || col >= COLS) return;
        if (board[row][col] % 10 == BOMB) return;
        board[row][col]++;
    }
    
    /*
     *      Set up board and pre-calculate adjacent bombs
     */
    void board_init(int board[ROWS][COLS])
    {
        int i, j, n;
    
        for (j = 0; j < ROWS; j++) {
            for (i = 0; i < COLS; i++) {
                board[j][i] = 10;
            }
        }
    
        n = 0;
        while (n < BOMBS) {
            j = rand() % ROWS;
            i = rand() % COLS;
    
            if (board[j][i] % 10 != BOMB) {
                board[j][i] = 19;
                inc(board, j - 1, i - 1);
                inc(board, j - 1, i);
                inc(board, j - 1, i + 1);
                inc(board, j,     i - 1);
                inc(board, j,     i + 1);
                inc(board, j + 1, i - 1);
                inc(board, j + 1, i);
                inc(board, j + 1, i + 1);
                n++;
            }
        }
    }
    
    /*
     *      Reveal tile and propagate revelation
     */
    void board_reveal(int board[ROWS][COLS], int row, int col)
    {
        if (row < 0 || row >= ROWS) return;     /* skip off-board tiles */
        if (col < 0 || col >= COLS) return;
    
        if (board[row][col] < 10) return;       /* already revealed, skip */
        if (board[row][col] >= 20) return;      /* must remove flag first, skip */
    
        if (board[row][col] % 10 == BOMB) {
            int i, j;
    
            printf("Bang!\n");
    
            for (j = 0; j < ROWS; j++) {
                for (i = 0; i < COLS; i++) {
                    if (board[j][i] % 10 == BOMB) board[j][i] = BOMB;
                }
            }     
        } else {
            board[row][col] %= 10;
            if (board[row][col] == 0) {
                board_reveal(board, row - 1, col);
                board_reveal(board, row, col - 1);
                board_reveal(board, row, col + 1);
                board_reveal(board, row + 1, col);
            }
        }
    }
    
    void board_print(int board[ROWS][COLS])
    {
        int i, j;
    
        for (j = 0; j < ROWS; j++) {
            putchar(' ');
    
            for (i = 0; i < COLS; i++) {
                const char *tile = ".12345678*##########PPPPPPPPPP";
                int k = board[j][i];
    
                putchar(tile[k]);
            }
    
            putchar('\n');
        }
    }
    
    int main()
    {
        int board[ROWS][COLS];
    
        srand(time(NULL));
        board_init(board);
        board_reveal(board, 0, 0);
        board_print(board);
    
        return 0;
    }