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
相关产品推荐
相关产品推荐

