扫雷大家应该都知道,翻开一个格子,显示的数字就是周围 8 格所含的雷数。例如,红色框框里的 1 周围 8 格就只有一个雷。
我们定义两个数组来实现,show 数组存放玩家看到的棋盘,mine 数组存放隐藏的雷盘
这两个数组搭配使用,就能计算某个位置周围的雷数,并且修改 show 数组来显示这个位置的雷数。
但是如果计算边缘格子周围的雷数时,数组会越界。
我们只要在周围留一圈就能解决这个问题
void init_board(char board[ROWS][cols], int rows, int cols, char set)
{
int i = 0;
int j = 0;
for (i = 0; i < rows; i++)
{
for (j = 0; j < cols; j++)
{
board[i][j] = set;
}
}
}
打印雷盘
//打印 show 雷盘void display_board(char board[ROWS][cols], int row, int col)
{
int i = 0;
int j = 0;//这里打印上面一行数字printf("|");for (j = 0; j <= col; j++){printf(" %-2d |", j);}printf("\n");for (i = 1; i <= row; i++){printf("|");for (j = 0; j <= col; j++){printf("----|");//打印两行之间的分割线}printf("\n");printf("|");printf(" %-2d |", i);//打印左边一列数字for (j = 1; j <= col; j++){printf(" %2c |",board[i][j]);//打印show数组}printf("\n");}}
效果图:
随机布置雷,将 mine 中的 ‘0’ 改为 ‘1’
随机布置雷,在 mine 数组里随机设置 COUNT 个雷
void set_mine(char mine[ROWS][cols], int row, int col)
{
int count = COUNT;
while (count)
{
int x = rand() % row + 1;
int y = rand() % col + 1;if (mine[x][y] == '0'){mine[x][y] = '1'; //地雷设置为 '1'count--;}}
}
1… 计算该坐标在 mine 中 周围 '1’的个数
2… 获取一个格子周围的雷数
int get_mine_count(char mine[ROWS][cols], int x, int y)
{
//mine 中存放的是字符'0' 和 '1'
return (mine[x][y + 1] +
mine[x - 1][y + 1] +
mine[x - 1][y] +
mine[x - 1][y - 1] +
mine[x][y - 1] +
mine[x + 1][y - 1] +
mine[x + 1][y] +
mine[x + 1][y + 1] - 8 \* '0');
}
void expand(char mine[ROWS][cols], char show[ROWS][cols], int x, int y, int\* win)
{if (x >= 1 && x <= ROW && y >= 1 && y <= COL) //限制在棋盘内展开,防止越界{int count = get_mine_count(mine, x, y);//获取雷数if (count == 0) //四周没雷,进入递归展开{show[x][y] = ' ';//四周没雷的改为 空格 ' 'int i = 0;//向四周共8个位置递归for (i = x - 1; i <= x + 1; i++){int j = 0;for (j = y - 1; j <= y + 1; j++){//只对 '*' 进行展开,防止死循环if (show[i][j] == '*'){expand(mine, show, i, j, win);}}}}else //四周有雷显示雷数{show[x][y] = count + '0';}//记录展开的数量(*win)++;}
}
void find_mine(char mine[ROWS][cols], char show[ROWS][cols], int row, int col)
{
int x = 0;
int y = 0;
int win = 0;//初始化 翻开的格子数量while (win < row * col - COUNT)//当翻开的格子数量 = 行 x 列 - 雷数 ===> 排雷成功{printf("请输入要排查的坐标:>");scanf("%d %d", &x, &y);//检查坐标是否越界if (x >= 1 && x <= row && y >= 1 && y <= col){//检查坐标是否排查过了if (show[x][y] == '*'){if (mine[x][y] == '1'){system("cls");show_mine(mine, show, row, col);printf("-----------很遗憾,你被炸死了-----------\n");break;}else{//展开expand(mine, show, x, y, &win);system("cls");//清屏display_board(show, row, col);printf("--------------还需翻开%d格--------------\n", row * col - COUNT - win);}}else{printf("该坐标已排查,请重新输入\n");}}else{printf("坐标非法,请重新输入\n");}}if (win == row* col - COUNT){system("cls");show_mine(mine, show, row, col);//展示地雷位置printf("------------恭喜你,排雷成功-----------\n");}}
显示地雷位置,排雷成功或被炸死后 向玩家展示地雷位置
void show_mine(char mine[ROWS][cols], char show[ROWS][cols], int row, int col)
{
int i = 0;
for (i = 1; i <= row; i++)
{
int j = 0;
for (j = 1; j <= COL; j++)
{
if (mine[i][j] == '1')
{
show[i][j] = '@'; //将地雷改成 '@'
}
}
}
display_board(show, row, col); //打印
}
![]() | ![]() |
![]() | ![]() |
头文件 常量定义,函数声明
#pragma once#include
#include
#include //玩家看到的大小
#define ROW 10
#define COL 10//实际数组大小,防止越界
#define ROWS ROW+2
#define COLS COL+2#define COUNT 10//雷数//初始化棋盘
void init_board(char board[ROWS][cols], int rows, int cols, char set);//打印棋盘
void display_board(char board[ROWS][cols], int row, int col);//随机布置雷
void set_mine(char mine[ROWS][cols], int row, int col);//获取坐标周围地雷数
int get_mine_count(char mine[ROWS][cols], int x, int y);//显示地雷位置并打印
void show_mine(char mine[ROWS][cols], char show[ROWS][cols], int row, int col);//递归展开
void expand(char mine[ROWS][cols], char show[ROWS][cols], int x, int y, int\* win);//排查雷
void find_mine(char mine[ROWS][cols],char show[ROWS][cols],int row, int col);
游戏测试文件
#define \_CRT_SECURE_NO_WARNINGS 1#include "game.h"//菜单
void menu()
{
printf("======================\n");
printf("|| 扫雷 ||\n");
printf("|| 1-开始游戏 ||\n");
printf("|| 0-退出游戏 ||\n");
printf("======================\n");
}//游戏流程
void game()
{
char mine[ROWS][cols] = { 0 };//存放布置的雷(隐藏的)
char show[ROWS][cols] = { 0 };//存放排查的雷(游戏看到的)//初始化棋盘//mine 全为'0'//show 全为'*'init_board(mine, ROWS, COLS, '0');init_board(show, ROWS, COLS, '*');//随机布置雷set_mine(mine,ROW,COL);//打印棋盘//display_board(mine, ROW, COL);display_board(show, ROW, COL);printf("--------------需要翻开%d格--------------\n", ROW * COL - COUNT);//排查雷(游戏开始)find_mine(mine, show, ROW, COL);}int main()
{
int input = 0;
srand((unsigned int)time(NULL));do{menu();printf("请选择:>");scanf("%d", &input);switch (input){case 1:system("cls");game();break;case 0:printf("退出游戏\n");break;default:printf("选择错误,请重新输入\n");break;}} while (input);return 0;}
函数定义
#define \_CRT_SECURE_NO_WARNINGS 1#include "game.h"//将两个数组初始化,show 全为'\*' ,mine 全为'0'void init_board(char board[ROWS][cols], int rows, int cols, char set)
{
int i = 0;
int j = 0;
for (i = 0; i < rows; i++)
{
for (j = 0; j < cols; j++)
{
board[i][j] = set;
}
}
}//打印 show 棋盘void display_board(char board[ROWS][cols], int row, int col)
{
int i = 0;
int j = 0;//这里打印上面一行数字printf("|");for (j = 0; j <= col; j++){printf(" %-2d |", j);}printf("\n");for (i = 1; i <= row; i++){printf("|");for (j = 0; j <= col; j++){printf("----|");//打印两行之间的分割线}printf("\n");printf("|");printf(" %-2d |", i);//打印左边一列数字for (j = 1; j <= col; j++){printf(" %2c |",board[i][j]);//打印show数组}printf("\n");}}//随机设置雷,在 mine 数组里随机设置 COUNT 个雷void set_mine(char mine[ROWS][cols], int row, int col)
{
int count = COUNT;
while (count)
{
int x = rand() % row + 1;
int y = rand() % col + 1;if (mine[x][y] == '0'){mine[x][y] = '1'; //地雷设置为 '1'count--;}}}//获取一个格子周围的雷数int get_mine_count(char mine[ROWS][cols], int x, int y)
{
//mine 中存放的是字符'0' 和 '1'
return (mine[x][y + 1] +
mine[x - 1][y + 1] +
mine[x - 1][y] +
mine[x - 1][y - 1] +
mine[x][y - 1] +
mine[x + 1][y - 1] +
mine[x + 1][y] +
mine[x + 1][y + 1] - 8 \* '0');
}//递归展开void expand(char mine[ROWS][cols], char show[ROWS][cols], int x, int y, int\* win)
{if (x >= 1 && x <= ROW && y >= 1 && y <= COL) //限制在棋盘内展开,防止越界{int count = get_mine_count(mine, x, y);//获取雷数if (count == 0) //四周没雷,进入递归展开{show[x][y] = ' ';//四周没雷的改为 空格 ' 'int i = 0;//向四周共8个位置递归调用for (i = x - 1; i <= x + 1; i++){int j = 0;for (j = y - 1; j <= y + 1; j++){//只对 '*' 进行展开,防止死循环if (show[i][j] == '*'){expand(mine, show, i, j, win);}}}}else //四周有雷显示雷数{show[x][y] = count + '0';}//记录展开的数量(*win)++;}}//显示地雷位置,排雷成功或被炸死后 向玩家展示地雷位置void show_mine(char mine[ROWS][cols], char show[ROWS][cols], int row, int col)
{
int i = 0;
for (i = 1; i <= row; i++)
{
int j = 0;
for (j = 1; j <= COL; j++)
{
if (mine[i][j] == '1')
{
show[i][j] = '@'; //将地雷改成 '@'
}
}
}
display_board(show, row, col); //打印
}//玩家排查雷void find_mine(char mine[ROWS][cols], char show[ROWS][cols], int row, int col)
{
int x = 0;
int y = 0;
int win = 0;//初始化 翻开的格子数量while (win < row * col - COUNT)//当翻开的格子数量 = 行 x 列 - 雷数 ===> 排雷成功{printf("请输入要排查的坐标:>");scanf("%d %d", &x, &y);//检查坐标是否越界if (x >= 1 && x <= row && y >= 1 && y <= col){//检查坐标是否排查过了if (show[x][y] == '*'){if (mine[x][y] == '1'){system("cls");show_mine(mine, show, row, col);printf("-----------很遗憾,你被炸死了-----------\n");break;}else{//展开expand(mine, show, x, y, &win);system("cls");//清屏display_board(show, row, col);printf("--------------还需翻开%d格--------------\n", row * col - COUNT - win);}}else{printf("该坐标已排查,请重新输入\n");}}else{printf("坐标非法,请重新输入\n");}}if (win == row* col - COUNT){system("cls");show_mine(mine, show, row, col);//展示地雷位置printf("------------恭喜你,排雷成功-----------\n");}}