You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C语言扫雷游戏点击(1,1)空白格出现额外行bug原因咨询

扫雷游戏expand函数引发的棋盘异常问题

我用C语言开发了一款扫雷游戏,多数情况下运行正常,但发现一个怪异bug:点击第一行第一列的空白格(数值为0)时,棋盘要么出现额外行,要么有行位置错乱移至顶部。我确定问题源于expand函数,因为实现该函数前并未出现此问题。

游戏代码

#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define DIM 8
#define DENSITY 0.2

void print_matrix(int (*)[DIM], int);
void generate_map(float, int(*)[DIM], int);
void generate_numbers(int(*)[DIM], int(*)[DIM], int, int*);
void minesweeper(int (*)[DIM], int(*)[DIM], int(*)[DIM], int*, int, int, int);
int win(int (*)[DIM], int, int);
void expand(int (*)[DIM], int (*)[DIM], int, int, int, int, int);

int main(void) {
    int map[DIM][DIM], numbers[DIM][DIM], row, column, game, mines = 0;
    char exit;

    do {
        game = 1; mines = 0;
        int visible[DIM][DIM] = { [0 ... DIM-1][0 ... DIM-1] = -1 };
        srand(time(NULL));
        do generate_map(DENSITY, map, DIM); while (mines < DIM);
        generate_numbers(numbers, map, DIM, &mines);
        do {
            print_matrix(numbers, DIM);
            puts("Map");
            print_matrix(map, DIM);
            printf("\nNumber of mines: %d", mines);
            do {
                printf("\nEnter the selected row (MAX. %d): ", DIM);
                scanf("%d", &row);
            } while (row <= 0 || row > DIM);
            do {
                printf("\nEnter the selected column (MAX. %d): ", DIM);
                scanf("%d", &column);
            } while (column <= 0 || column > DIM);
            system("cls");

            minesweeper(numbers, map, visible, &game, row - 1, column - 1, DIM);
            print_matrix(visible, DIM);
            puts("Numbers");

            if (win(visible, DIM, mines)) {
                printf("CONGRATULATIONS, YOU WON!!");
                game = 0;
            }
        } while (game);

        printf("\nEND OF THE GAME");
        printf("\nDo you want to play again? (Y/N): ");
        fflush(stdout);
        scanf(" %c", &exit);

    } while (toupper(exit) == 'Y');
}

void generate_map(float density, int(*map)[DIM], int dim) {
    int r, c;
    for (r = 0; r < dim; r++) {
        for (c = 0; c < dim; c++) {
            map[r][c] = (float)rand() / RAND_MAX > density ? 0 : 1;
        }
    }
}

void generate_numbers(int (*numbers)[DIM], int (*map)[DIM], int dim, int *mines) {
    int counter, r, c, i, j;
    for (r = 0; r < dim; r++) {
        for (c = 0; c < dim; c++) {
            counter = 0;
            for (i = r - 1; i <= r + 1; i++) {
                if (i > -1 && i < dim) {
                    for (j = c - 1; j <= c + 1; j++) {
                        if (j > -1 && j < dim) {
                            if (map[i][j] != 0) {
                                counter++;
                            }
                        }
                    }
                }
            }
            numbers[r][c] = counter;
            if (map[r][c] != 0) *mines += 1;
        }
    }
}

void minesweeper(int (*numbers)[DIM], int (*map)[DIM], int (*visible)[DIM], int *game, int row, int column, int dim) {
    if (map[row][column] == 0) {
        if (numbers[row][column] == 0) {
            expand(numbers, visible, dim, row, column, row, column);
        } else {
            visible[row][column] = numbers[row][column];
        }
    } else {
        visible[row][column] = -2;
        *game = 0;
    }
}

void print_matrix(int (*m)[DIM], int dim) {
    int r, c;
    for (r = 0; r < dim; r++) {
        for (c = 0; c < dim; c++) {
            if (m[r][c] == -1) {
                printf("| x ");
            } else if (m[r][c] == -2) {
                printf("| * ");
            } else {
                printf("| %d ", m[r][c]);
            }
        }
        printf("|\n");
    }
}

int win(int (*visible)[DIM], int dim, int mines) {
    int c, r, counter;
    for (r = 0; r < dim; r++) {
        for (c = 0; c < dim; c++) {
            if (visible[r][c] == -1) {
                counter++;
            }
        }
    }
    return (counter == mines) ? 1 : 0;
}

void expand(int (*numbers)[DIM], int (*visible)[DIM], int dim, int row, int column, int i_o, int j_o) {
    int i, j;
    for (i = row - 1; i <= row + 1; i++) {
        if (i > -1 && i < dim) {
            for (j = column - 1; j <= column + 1; j++) {
                if (j > -1 && j < dim) {
                    if ((i == i_o && j == j_o) || (i == row && j == column)) {
                        continue;
                    } else if (numbers[i][j] == 0 && visible[i][j] == -1) {
                        visible[i][j] = numbers[i][j];
                        expand(numbers, visible, dim, i, j, row, column);
                    } else {
                        visible[i][j] = numbers[i][j];
                    }
                }
            }
        }
    }
}

实现逻辑与bug现象

我的实现流程是:

  • 先创建存储地雷位置的map矩阵
  • 再生成存储每个单元格周围地雷数量的numbers矩阵
  • 最后用visible矩阵显示玩家可见内容

当单元格数值为0时会触发expand函数,该函数会显示所有周边单元格(这些单元格都不含地雷);若其中某个单元格数值也为0,则递归调用expand函数,并传入上一次的0单元格坐标(i_o, j_o)以避免无限递归。minesweeper函数处理玩家点击单元格的逻辑。我原本认为这不是边界问题,因为代码中始终有边界检查。

bug的具体表现:
点击(1,1)单元格(数值为0,触发expand)后,棋盘打印了9行而非8行,顶部行是第7行的副本;同时(1,1)单元格始终不可见,直到点击(1,2)才会显示,其他功能正常(截图来自早期西班牙语版本)。

临时解决与疑问

我在expand函数的continue语句前添加visible[i][j] = numbers[i][j];后,问题得以解决,但我仍想知道为何会出现额外行?


内容的提问来源于stack exchange,提问作者Gonzalo Martín

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 11:03:10