目录
一、预览
- 主页面
- 游戏页面
二、预处理模块
- 文件引用
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <time.h>
- 宏定义
#define ROW 9
#define COL 9
#define ROWS ROW + 2
#define COLS COL + 2
#define EASY_COUNT 10 //简单版本
- 函数声明
在本程序中使用了几个自定义的函数,这些函数的功能及声明形式代码如下:
void InitBoard(char board[ROWS][COLS], int rows, int cols, char set);//初始化数组的内容
void DisplayBoard(char board[ROWS][COLS], int row, int col);//打印地图
void SetMine(char board[ROWS][COLS], int row, int col);//布置雷
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);//排查雷
int get_mine_count(char board[ROWS][COLS], int x, int y);
三、主函数设计
- 功能概述
在扫雷游戏的main()函数中主要实现了调用menu()函数显示主功能选择菜单,并且在switch分支选择结构中调用game()函数实现游戏的进行。
1.主函数的实现
编号 | 功能 |
---|---|
0 | 退出游戏 |
1 | 进入游戏 |
主函数main()的实现代码如下:
int main()
{
int input = 0;
srand((unsigned int)time(NULL));//设置随机数的生成起点
do
{
menu();
printf("请选择:>");
scanf("%d", &input);
system("cls");
switch (input)
{
case 1:
game();
break;
case 0:
printf("下次再玩吧!\n");
break;
default:
printf("ERROR!\n");
break;
}
} while (input);
return 0;
}
2.主页面的显示
在主函数中,通过调用menu()
函数来显示主页面。
它的实现代码如下:
void menu()
{
printf(":------------ 扫 雷 ------------:\n");
printf(": :\n");
printf(": :\n");
printf(": 1 play :\n");
printf(": :\n");
printf(": 0 exit :\n");
printf(": :\n");
printf(": :\n");
printf(":---------------------------------:\n");
}
四、game()函数的说明
1.game()函数
代码如下:
void game()
{
char mine[ROWS][COLS] = { 0 };//存放布置好的雷的信息
char show[ROWS][COLS] = { 0 };//存放排查出的雷的信息
//初始化数组的内容
InitBoard(mine, ROWS, COLS, '0');//mine 数组在没有布置雷的时候,都是'0'
InitBoard(show, ROWS, COLS, '*');//show 数组在没有排查雷的时候,都是'*'
SetMine(mine, ROW, COL);//布置雷
DisplayBoard(show, ROW, COL);
FindMine(mine, show, ROW, COL);//排查雷 现在mine数组里看用户输入的坐标是否是雷
//是雷 游戏结束
//不是雷 统计他周围有几个雷 同时把数值显示到show数组里去
}
2.其余函数的说明
① 数组的初始化
将一个11×11的二维数组初始化为0,原因在思路中有讲到
void InitBoard(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;
}
}
}
② 打印数组
这里通过for循环打印扫雷小游戏所需的页面,使其合理与美观
void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
int i = 0;
int j = 0;
printf("----- 扫 雷 -----\n");
printf(" ");
for (j = 1; j <= col; 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");
}
③ 布置雷的信息
这边定义EASY_COUNT
是为了方便以后的更改,可以更改更高难度的版本
void SetMine(char board[ROWS][COLS], int row, int col)
{
int count = EASY_COUNT;
while (count)
{ //x,y必须要在while循环里面定义,如果第一次判断不成功,便再次赋值一个随机值
int x = rand() % row + 1; // 1~9
int y = rand() % col + 1; // 1~9
if (board[x][y] == '0')//如果等于0就说明不是雷,就给这个变量赋值为1,使得它变为雷
{
board[x][y] = '1';
count--;
}
}
}
④ 统计周围的雷
这里的get_mine_count()
函数是为了得到这个坐标周围的雷数然后返回,这个函数将用于FindMine()
函数
int get_mine_count(char board[ROWS][COLS], int x, int y)
{
int i = 0;
int j = 0;
return (board[x + 1][y + 1] +
board[x + 1][y] +
board[x + 1][y - 1] +
board[x][y + 1] +
board[x][y - 1] +
board[x - 1][y + 1] +
board[x - 1][y] +
board[x - 1][y - 1] - 8 * '0');
}
⑤ 排查雷
- 排查雷 现在mine数组里看用户输入的坐标是否是雷
- 是雷 - 游戏结束
不是雷 - 统计他周围有几个雷 同时把数值显示到show数组里去
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
int x = 0;
int y = 0;
int win = 0;//排查的个数 如果排查的次数等于81-10=71次,说明成功了
while (win < row * col - EASY_COUNT )
{
printf("请输入要排查的坐标:>");
scanf("%d %d", &x, &y);
system("cls");
if (x >= 1 && x <= row && y >= 1 && y <= col)//判断坐标的合法性
{
if (show[x][y] != '*')
{
printf("该坐标被排查过了,不能重复排查\n");
}
if (mine[x][y] == '1')//1表示有雷 0表示没有
{
system("cls");
printf("很遗憾,你被炸死了\n");
DisplayBoard(show, ROW, COL);//让用户知道自己死在哪儿
Sleep(3000);
system("cls");
break;
}
else//不是雷,统计周围有多少个雷 由于1的ASCII值为49 字符0的ASCII值为48
//这里可以使用'1'-'0'= 1,即字符1减去字符0等于数字0
//同理 可以将这个坐标周围的八个字符相加后减去8×'0',这样就能够统计周围的雷
{
win++;
int count = get_mine_count(mine, x, y);
//统计mine数组中的(x, y)坐标周围有几颗雷
show[x][y] = count + '0';//转换成数字字符
DisplayBoard(show, ROW, COL);
}
}
else
{
printf("ERROR!\n");
}
}
if (win == row * col - EASY_COUNT)
{
printf("恭喜你,排雷成功!\n");
DisplayBoard(show, ROW, COL);
}
}
五、思路
- 每个格子可以使用9x9的数组进行存放,可以用两个9x9的数组分别存放 布置好雷的信息mine[9][9]1和 排查出的雷的信息show[9][9]2
- 当我们的雷布置到边界时,为了避免坐标越界和判断坐标的有效性以提高效率,我们可以将其视为将这个边界扩大一圈,但是这个扩大的范围里不存放雷,即mine[11][11]和show[11][11]
整体代码
\\#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <time.h>
#define ROW 9
#define COL 9
#define ROWS ROW + 2
#define COLS COL + 2
#define EASY_COUNT 10 //简单版本
void InitBoard(char board[ROWS][COLS], int rows, int cols, char set);
void DisplayBoard(char board[ROWS][COLS], int row, int col);
void SetMine(char board[ROWS][COLS], int row, int col);
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);
int get_mine_count(char board[ROWS][COLS], int x, int y);
void menu()
{
printf(":------------ 扫 雷 ------------:\n");
printf(": :\n");
printf(": :\n");
printf(": 1 play :\n");
printf(": :\n");
printf(": 0 exit :\n");
printf(": :\n");
printf(": :\n");
printf(":---------------------------------:\n");
}
void InitBoard(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;
}
}
}
void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
int i = 0;
int j = 0;
printf("----- 扫 雷 -----\n");
printf(" ");
for (j = 1; j <= col; 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");
}
void SetMine(char board[ROWS][COLS], int row, int col)
{
int count = EASY_COUNT;
while (count)
{ //x,y必须要在while循环里面定义,如果第一次判断不成功,便再次赋值一个随机值
int x = rand() % row + 1; // 1~9
int y = rand() % col + 1; // 1~9
if (board[x][y] == '0')//如果等于0就说明不是雷,就给这个变量赋值为1,使得它变为雷
{
board[x][y] = '1';
count--;
}
}
}
int get_mine_count(char board[ROWS][COLS], int x, int y)
{
int i = 0;
int j = 0;
return (board[x + 1][y + 1] +
board[x + 1][y] +
board[x + 1][y - 1] +
board[x][y + 1] +
board[x][y - 1] +
board[x - 1][y + 1] +
board[x - 1][y] +
board[x - 1][y - 1] - 8 * '0');
}
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
int x = 0;
int y = 0;
int win = 0;//排查的个数 如果排查的次数等于81-10=71次,说明成功了
while (win < row * col - EASY_COUNT )
{
printf("请输入要排查的坐标:>");
scanf("%d %d", &x, &y);
system("cls");
if (x >= 1 && x <= row && y >= 1 && y <= col)//判断坐标的合法性
{
if (show[x][y] != '*')
{
printf("该坐标被排查过了,不能重复排查\n");
}
if (mine[x][y] == '1')//1表示有雷 0表示没有
{
system("cls");
printf("很遗憾,你被炸死了\n");
DisplayBoard(show, ROW, COL);//让用户知道自己死在哪儿
Sleep(3000);
system("cls");
break;
}
else//不是雷,统计周围有多少个雷 由于1的ASCII值为49 字符0的ASCII值为48
//这里可以使用'1'-'0'= 1,即字符1减去字符0等于数字0
//同理 可以将这个坐标周围的八个字符相加后减去8×'0',这样就能够统计周围的雷
{
win++;
int count = get_mine_count(mine, x, y);
//统计mine数组中的(x, y)坐标周围有几颗雷
show[x][y] = count + '0';//转换成数字字符
DisplayBoard(show, ROW, COL);
}
}
else
{
printf("ERROR!\n");
}
}
if (win == row * col - EASY_COUNT)
{
printf("恭喜你,排雷成功!\n");
DisplayBoard(show, ROW, COL);
}
}
void game()
{
char mine[ROWS][COLS] = { 0 };//存放布置好的雷的信息
char show[ROWS][COLS] = { 0 };//存放排查出的雷的信息
//初始化数组的内容
InitBoard(mine, ROWS, COLS, '0');//mine 数组在没有布置雷的时候,都是'0'
InitBoard(show, ROWS, COLS, '*');//show 数组在没有排查雷的时候,都是'*'
SetMine(mine, ROW, COL);//布置雷
DisplayBoard(show, ROW, COL);
FindMine(mine, show, ROW, COL);//排查雷 现在mine数组里看用户输入的坐标是否是雷
//是雷 游戏结束
//不是雷 统计他周围有几个雷 同时把数值显示到show数组里去
}
int main()
{
int input = 0;
srand((unsigned int)time(NULL));//设置随机数的生成起点
do
{
menu();
printf("请选择:>");
scanf("%d", &input);
system("cls");
switch (input)
{
case 1:
game();
break;
case 0:
printf("下次再玩吧!\n");
break;
default:
printf("ERROR!\n");
break;
}
} while (input);
return 0;
}