1.菜单
通过printf函数打印出游戏的大致内容,使玩家更好地上手
2.棋盘
2.1创建棋盘
在创建棋盘之前我们应该先想一下,我们要创建多大的棋盘?假设做一个9*9的扫雷游戏,我们同样只是创建了一个9*9的棋盘,那么当我们想要排查那些边界处的雷时是否会造成越界错误呢?
这么一想,是否创建一个11*11的棋盘来实现9*9的扫雷游戏更好呢?
再根据扫雷游戏的内容,我们不难想出创建出两块棋盘来实现游戏会更加简单
一块棋盘则用来展示给玩家
另一块棋盘放置炸弹并在这个棋盘上进行是否有炸弹的判定
可以理解为一个是花架子用来看的,另一个才是真正用来做事的。
注意事项:尽量使用宏定义的常量,这样的话在后期想要更改棋盘大小时只需要简单的对宏定义常量进行修改。
2.2初始化棋盘
展示用的棋盘可以全部初始化为'*',给玩家一种未知的感觉
而用来存放炸弹的我们就先全初始化为'0'
那么代码的实现可以写成:
注意事项:之所以它多加一个字符变量可以实现初始化成你想要的字符而不用再去写一个类似的函数
void initboard(char board[ROWS][COLS], char init) { int i = 0; int j = 0; for (i = 0; i < ROWS; i++) { for (j = 0; j < COLS; j++) { board[i][j] = init; } }
2.3打印棋盘
老生常谈的问题,老样子,直接上循环:
注意事项:每打印一行记得换行
void printboard(char board[ROWS][COLS]) { int i = 0; int j = 0; for (j = 0; j <= ROW; j++) { printf("%d ", j); } printf("\n"); for (i = 1; i <= ROW; i++) { printf("%d ", i); for (j = 1; j <= COL; j++) { printf("%c ", board[i][j]); } printf("\n"); } printf("\n"); }
3.炸弹
3.1放入炸弹
假设我们要放10个炸弹进去,那么可以通过循环来实现,每循环一次改变一个随机坐标的字符,并对炸弹数减1,随机值可以通过rand和srand来实现
随机值:
1. srand((unsigned int)time(NULL)); 2. c=rand();//c此时就是随着时间戳函数变化的随机值
具体实现:
注意事项:rand()%ROW的值是0~ROW-1,我们要实现的行列属于1~ROW,因为棋盘真实大小为11*11,我们的目标只是打印9*9的棋盘,因此写作rand()%ROW+1
void putboom(char boomboard[ROWS][COLS], int p_count) { int i = 0; int j = 0; while (p_count) { i = rand() % ROW + 1; j = rand() % COL + 1; if (boomboard[i][j] != '1') { boomboard[i][j] = '1'; p_count -= 1; } } }
3.2 9宫格炸弹计数
将一个坐标周围的八个字符都加在一起,再减去8个字符0也就是我们之前初始化的内容,便可以得到这个坐标周围的雷数,把雷数再传回这个坐标,便可以将这个坐标修改为周围的雷数。
注意事项:由于计算出来的是雷的数目这是个整型变量,那么在外面也应该用整型接收,并加上一个'0'才是相对应的数字字符。
int boomcount(char boomboard[ROWS][COLS], int bc_i, int bc_j) { int a = boomboard[bc_i][bc_j - 1] + boomboard[bc_i][bc_j + 1] + boomboard[bc_i + 1][bc_j] + boomboard[bc_i - 1][bc_j] + boomboard[bc_i + 1][bc_j + 1] + boomboard[bc_i + 1][bc_j - 1] + boomboard[bc_i - 1][bc_j + 1] + boomboard[bc_i - 1][bc_j - 1] - 8 * '0'; return a; }
3.3排雷判定
4种情况
注意事项:不要越界操作!!!
(1)是雷
printf("请输入坐标,中间有空格\n"); scanf("%d %d", &i, &j); if (boomboard[i][j] == '1') { printf("很遗憾,你被炸死了\n"); break; }
(2)不是雷
if (boomboard[i][j] != '1' && i <= ROW && j <= COL&&i>=1&&j>=1) { int a = boomcount(boomboard, i, j); board[i][j] = a + '0'; printboard(board); }
(3)重复输入
printf("请输入坐标,中间有空格\n"); scanf("%d %d", &i, &j); if (board[i][j] != '*' && i <= ROW && j <= COL) { printf("该坐标已经排查过了\n"); }
(4)非法输入
printf("请输入坐标,中间有空格\n"); scanf("%d %d", &i, &j); if( i> ROW || j> COL||i<1||j<1) { printf("语法错误,请重新错入\n"); }
综上所述,不难写出:
(为了游戏能够结束可以设置一个计数板,如win)
void boom(char boomboard[ROWS][COLS], char board[ROWS][COLS], int b_count) { int win = 0; int i = 0; int j = 0; while (win < ROW * COL - b_count) { printf("请输入坐标,中间有空格\n"); scanf("%d %d", &i, &j); if (boomboard[i][j] == '1') { printf("很遗憾,你被炸死了\n"); break; } else if (i >= 1 && j >= 1 && j <= COL && i <= ROW ) { if (board[i][j] != '*' && i <= ROW && j <= COL) { printf("该坐标已经排查过了\n"); } else { int a = boomcount(boomboard, i, j); board[i][j] = a + '0'; if (board[i][j] == '0') { zhangkai(board, boomboard, i, j); } printboard(board); win += 1; } } else { printf("语法错误,请重新错入\n"); } } if (win == ROW * COL - b_count) { printf("恭喜扫雷成功\n"); } }
3.4无雷展开
难点在于不要越界和不要重复这两个点
(1)避免越界
if (z_i > ROW || 1 > z_i || z_j > COL || 1 > z_j) return;
(2)避免重复
if(board[z_i][z_j] == ' ' || boomcount(boomboard, z_i, z_j)) return;
综合一下
void zhangkai(char board[ROWS][COLS], char boomboard[ROWS][COLS], int z_i, int z_j) { if (z_i > ROW || 1 > z_i || z_j > COL || 1 > z_j|| board[z_i][z_j] == ' ' || boomcount(boomboard, z_i, z_j)) return; else { board[z_i][z_j] = ' '; zhangkai(board, boomboard, z_i + 1, z_j); zhangkai(board, boomboard, z_i, z_j + 1); zhangkai(board, boomboard, z_i, z_j - 1); zhangkai(board, boomboard, z_i - 1, z_j); } }