扫雷游戏就是在一个棋盘内放置一定的雷数,玩家可以不断地排除雷来实现扫雷,如果附近没有雷的话就可以排除附近一片附近没有雷的棋子,如果碰到雷了游戏就失败了,如果棋盘只剩下雷的话排雷就成功了。
如果没有玩过扫雷的话可以点击这里体验一下:扫雷
最终实现的样式如下(可以根据自身需要进一步加以改进):
扫雷视屏演示
提供选项供玩家选择,是开始游戏还是退出游戏
void menu(void)
{
printf("***********************\n");
printf("***** 1、开始游戏 *****\n");
printf("***** 0、退出游戏 *****\n");
printf("***********************\n");
}
在布置棋盘的时候,我们需要创建两个棋盘也就是二维数组,因为我们在进行扫雷的时候需要将雷隐藏起来,不能让玩家看到,而且不能将雷的位置改变,所以我们创建两个棋盘,一个用来存放雷的位置(简称雷盘),一个用来展示。我们就可以根据雷盘的信息来打印棋盘。首先需要初始化棋盘将雷盘全部初始化为字符‘0’,将棋盘全部初始化为‘*’。
void init_board(char board[ROWS][COLS], int row, int col, char ch) //ch用来控制棋子的样式
{
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
board[i][j] = ch; //将二维数组里的全部元素都初始化为
}
}
}
布置雷的时候需要使用随机数函数rand来实现雷的随机布置,在使用rand函数之前又需要调用函数srand,使用srand 的时候又需要使用时间戳函数time。这跟三子棋中电脑下棋是一样的。
void init_mine(char board[ROWS][COLS], int row, int col)
{
int count = COUNT_MINE; //自定义雷数
do {
int x = (rand() % 9) + 1; //控制雷的生成位置
int y = (rand() % 9) + 1;
if (board[x][y] == '0') //判断当前位置是否为雷,如果是不是雷的话就布置雷
{
board[x][y] = '1';
count--;
}
} while (count);
}
将棋盘全部打印出来中间可以使用一些符号隔开来,方便区分行和列。这一步在每一次下扫雷后都需要进行一次
void print(char board[ROWS][COLS], int row, int col)
{
for (int i = 0; i <= ROW; i++) //打印列数
{
printf("%d ", i);
}
printf("\n");
printf("————————————————————\n"); //行与行之间的分割
for (int i = 1; i <= row; i++)
{
printf("%d ", i); //打印列数
for (int j = 1; j <= col; j++)
{
printf("| %c ", board[i][j]); //列与列之间的分割
}
putchar('|');
printf("\n");
printf("————————————————————\n");
}
}
如果当前位置为雷,就立马结束游戏。
char is_continue(char board[ROWS][COLS], int row, int col)
{
if (board[row][col] == '1') //判断当前位置是否为雷
return '1';
else
return '0';
}
如果当前位置不是雷就显示附近的雷数。
char count_mine(char board[ROWS][COLS], int row, int col)
{
char count = '0';
for (int i = row - 1; i <= row + 1; i++)
{
for (int j = col - 1; j <= col + 1; j++)
{
if (board[i][j] == '1') //判断当前位置是不是雷
count++; //计数
}
}
return count;
}
如果当前位置没有雷并且其附近的位置也没有雷,就可以使用递归展开这些位置。在递归的时候需要注意:不能超过棋盘的边界,并且这个位置不可以是雷,递归的时候需要首先判断这两个条件,满足这两个条件之后再进行递归。
void spread_board(char put_board[ROWS][COLS], char show_board[ROWS][COLS], int row, int col)
{
if (row == 0 || col == 0 || row > ROW || col > COL) //判断有没有超过边界
return;
if (show_board[row][col] != '*') //判断当前位置是不是雷
return;
char count = count_mine(put_board, row, col); //计算当前位置附近的雷数
show_board[row][col] = count; //展开
if (count == '0')
{
for (int i = row - 1; i <= row + 1; i++)
{
for (int j = col - 1; j <= col + 1; j++)
{
spread_board(put_board, show_board, i, j); //递归展开
}
}
}
}
要是棋盘上面的没有被排查的个数大于雷数,那就继续游戏,如果等于雷数,那就扫雷成功了!!!(这一步也同样可以用来验证代码的正确性)所以这时候只需要遍历棋盘并计算没有没有被排查的个数就可以了。
int is_discion(char board[ROWS][COLS], int row, int col)
{
int count = 0;
for (int i = 1; i <= row; i++)
{
for (int j = 1; j <= col; j++)
{
if (board[i][j] == '*') //判断当前位置有没有被排查
{
count++; //计数
}
}
}
return count;
}
在实现扫雷的时候有什么不懂的地方可以参考这里的代码:扫雷