一.扫雷游戏分析和设计
设计一个9*9的格子,在其中实现随机埋雷。
用户通过控制台选择要排查的位置,如果是雷,被炸死,游戏结束。如果不是雷,则显示周围有几个雷,直到所有非雷位置被排完,排雷成功游戏结束。
可以通过菜单选择是否继续玩或者退出游戏。
1.菜单设计
通过输入数字实现对菜单的选择,然后封装到函数中
void menu()//不需要返回值,void
{
printf("\n***********************\n");
printf("***********************\n");
printf("****** 1.play *******\n");
printf("****** 0.exit *******\n");
printf("***********************\n");
printf("***********************\n");
}
int main()
{
int put = 0;
do {
menu();
printf("请输入你的选择:");
scanf(" %d", &put);
switch (put)
{
case 1:
printf("\n请开始扫雷\n");
game();
break;
case 0:
printf("\n已退出游戏!\n");
break;
default:
printf("\n选择错误,请重新输入!\n");
break;
}
} while (put);
return 0;
}
2.游戏内容的实现
初始化棋盘
当玩家进入游戏后,首先会看到一个9*9的棋盘,但是我们在初始化棋盘的时候要创建一个(9+2)*(9+2)的棋盘,这是因为如果玩家没有踩到雷就要显示周围雷的个数,在判断周围雷的个数时在边缘的位置和中心的计算方法不同,为了计算方便我们在棋盘多加了两行两列。
#define ROWS ROW+2//设置的存储的棋盘的长宽
#define COLS COL+2
在初始化棋盘时,一个位置要存放是不是雷,和周围有几个雷的数据在一个数组中不易实现因此设计两个数组 ,一个是布置雷,一个是给玩家展示 。
//初始化棋盘
InitBoard(mine, ROWS, COLS, '0');//用于存放雷的棋盘,初始化为0
InitBoard(show, ROWS, COLS, '*');//用于显示给用户看的,初始化为*
void InitBoard(char arr[ROWS][COLS], int rows, int cols, char set)//接收数组,行,列,所要初始的内容
{
int i = 0; //控制行
for (i = 0; i < rows; i++)
{
int j = 0;
for (j = 0; j < cols; j++)//控制列
{
arr[i][j] = set;//初始化数组
}
}
}
随机布雷
rand()%row+1是为了生成小于等于行数的随机数
//在棋盘中布置雷
srand((unsigned int)time(NULL));//生成一个随机数,time函数无参返回,返回类型强制转换为unsigned
void SetMine(char arr[ROWS][COLS], int row, int col)
{
int count = number;//设置雷的数量为10
while (count)
{ //使用rand函数需要调用srand函数,设置在主函数里面
int x = rand() % row + 1;//棋盘x的坐标,%row值为0-8,+1值变成0-9
int y = rand() % col + 1;//棋盘y的坐标,同上0-9
if (arr[x][y] == '0')//首先判断当前的随机位置是否有雷,无雷进入
{
arr[x][y] = '1';//没有雷就在当前位置下放一个‘1’表示雷
count--;//放置成功后,雷的数量减一
}
}
}
打印棋盘
/打印棋盘
void DisplayBoard(char arr[ROWS][COLS], int row, int col)//打印显示的棋盘
{
int i = 0; //控制行
for (i = 0; i <= col; i++)//打印列号
{
printf("%d ", i);
}
printf("\n");
for (i = 1; i <= row; i++)
{
int j = 0;
printf("%d ", i);//打印行号
for (j = 1; j <= col; j++)//控制列
{
printf("%c ", arr[i][j]);//循环打印数组里的所有内容
}printf("\n");//每一行打印完之后换行
}
printf("\n");
}
开始游戏
//排查雷
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
int x, y;//排查的坐标
int count = 0;//可排查的次数
while (count < row * col - number)
{
printf("请输入要排查的坐标(中间用空格隔开):");
scanf("%d %d", &x, &y);//输入排查坐标
if (x >= 1 && x <= row && y >= 1 && y <= col)//排查坐标需要在1-9之间
{
if (mine[x][y] == '1')//如果输入的坐标位置是‘1’,则被炸死
{
printf("很遗憾,你被炸死啦!!!!\n");
printf("\n");
DisplayBoard(mine, ROW, COL);//被炸死了,将布置雷的棋盘打印出来
break;//跳出
}
else//输入位置不是雷,则显示当前位置的周围有几个雷
{
ExpandBlank(mine, show, x, y);
DisplayBoard(show, ROW, COL);//显示排查过后的用户棋盘
if (EndMine(show, ROW, COL))//返回为真
{
printf("恭喜你排雷成功!!!\n");//排雷成功
DisplayBoard(mine, ROW, COL);//打印布置的棋盘
break;
}
}
}
else
{
printf("输入坐标错误,请重新输入\n");
}
}
}
显示输入坐标周围有几个雷
//排查输入坐标周围的雷
int GetMine(char mine[ROWS][COLS], int x, int y)
{
//每个坐标相加并减去字符0的大小(字符0的ASII码值为48),转换成数字
return mine[x - 1][y] + mine[x + 1][y] + mine[x - 1][y - 1] +
mine[x][y - 1] + mine[x + 1][y - 1] +
mine[x - 1][y + 1] + mine[x][y + 1] +
mine[x + 1][y + 1] - 8 * '0';
}
无雷区域的扩展
//无雷区域的扩展,使用递归实现
void ExpandBlank(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y)
{
int num = GetMine(mine, x, y);//九宫格雷的数量函数
if (num)
{
// 将雷的数量放入show数组中, + ‘0’是将num由int类型转换为字符char类型
show[x][y] = num + '0';
}
else if (show[x][y] == '*')
{
show[x][y] = ' ';//将没有雷的地方赋值为空格
int i = 0, j = 0;//使用循环作为递归的条件,找出无雷区域
for (i = x - 1; i <= x + 1; i++)
{
for (j = y - 1; j <= y + 1; j++)
{
ExpandBlank(mine, show, i, j);
}
}
}
}
开始排雷
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
int x, y;//排查的坐标
while (count < row * col - number)
{
printf("请输入要排查的坐标(中间用空格隔开):");
scanf("%d %d", &x, &y);//输入排查坐标
if (x >= 1 && x <= row && y >= 1 && y <= col)//排查坐标需要在1-9之间
{
if (mine[x][y] == '1')//如果输入的坐标位置是‘1’也就是雷,则被炸死
{
printf("很遗憾,你被炸死啦!!!!\n");
printf("\n");
DisplayBoard(mine, ROW, COL);//被炸死了,将布置雷的棋盘打印出来
break;//跳出
}
else//输入位置不是雷,则显示当前位置的周围有几个雷
{
ExpandBlank(mine, show, x, y);
DisplayBoard(show, ROW, COL);//显示排查过后的用户棋盘
if (EndMine(show, ROW, COL))//返回为真
{
printf("恭喜你排雷成功!!!\n");//排雷成功
DisplayBoard(mine, ROW, COL);//打印布置的棋盘
break;
}
}
}
else
{
printf("输入坐标错误,请重新输入\n");
}
}
}
二.代码整合
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define number 10//雷的个数
#define ROW 9//棋盘显示的长宽
#define COL 9
#define ROWS ROW+2//设置的存储的棋盘的长宽
#define COLS COL+2
void InitBoard(char arr[ROWS][COLS], int rows, int cols, char set);//接收数组,行,列,所要初始的内容
void DisplayBoard(char arr[ROWS][COLS], int row, int col);//数组大小不变,但是传过来显示的棋盘变成9×9
void SetMine(char arr[ROWS][COLS], int row, int col);//布置雷
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);//排查雷
//初始化棋盘
void InitBoard(char arr[ROWS][COLS], int rows, int cols, char set)//接收数组,行,列,所要初始的内容
{
int i = 0; //控制行
for (i = 0; i < rows; i++)
{
int j = 0;
for (j = 0; j < cols; j++)//控制列
{
arr[i][j] = set;//初始化数组
}
}
}
//打印棋盘
void DisplayBoard(char arr[ROWS][COLS], int row, int col)//打印显示的棋盘
{
int i = 0; //控制行
for (i = 0; i <= col; i++)//打印列号
{
printf("%d ", i);
}
printf("\n");
for (i = 1; i <= row; i++)
{
int j = 0;
printf("%d ", i);//打印行号
for (j = 1; j <= col; j++)//控制列
{
printf("%c ", arr[i][j]);//循环打印数组里的所有内容
}printf("\n");//每一行打印完之后换行
}
printf("\n");
}
//在棋盘中布置雷
void SetMine(char arr[ROWS][COLS], int row, int col)
{
int count = number;//设置雷的数量为10
while (count)
{ //使用rand函数需要调用srand函数,设置在主函数里面
int x = rand() % row + 1;//棋盘x的坐标,%row值为0-8,+1值变成0-9
int y = rand() % col + 1;//棋盘y的坐标,同上0-9
if (arr[x][y] == '0')//首先判断当前的随机位置是否有雷,无雷进入
{
arr[x][y] = '1';//没有雷就在当前位置下放一个‘1’表示雷
count--;//放置成功后,雷的数量减一
}
}
}
//排查输入坐标周围的雷
int GetMine(char mine[ROWS][COLS], int x, int y)
{
//每个坐标相加并减去字符0的大小(字符0的ASII码值为48),转换成数字
return mine[x - 1][y] + mine[x + 1][y] + mine[x - 1][y - 1] +
mine[x][y - 1] + mine[x + 1][y - 1] +
mine[x - 1][y + 1] + mine[x][y + 1] +
mine[x + 1][y + 1] - 8 * '0';
}
//获胜条件函数
int EndMine(char show[ROWS][COLS], int row, int col)
{
int count = 0;
for (int i = 1; i <= row; i++)
{
for (int j = 1; j <= col; j++)
{
if (show[i][j] == '*')//在棋盘上查找没有被排查的点
count++;//统计没有被排查的点的数量
}
}
if (count == number)//如果没有被排查的点的数量等于雷的数量
{
return 1;
}
else
{
return 0;
}
}
//无雷区域的扩展,使用递归实现
void ExpandBlank(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y)
{
int num = GetMine(mine, x, y);//九宫格雷的数量函数
if (num)
{
// 将雷的数量放入show数组中, + ‘0’是将num由int类型转换为字符char类型
show[x][y] = num + '0';
}
else if (show[x][y] == '*')
{
show[x][y] = ' ';//将没有雷的地方赋值为空格
int i = 0, j = 0;//使用循环作为递归的条件,找出无雷区域
for (i = x - 1; i <= x + 1; i++)
{
for (j = y - 1; j <= y + 1; j++)
{
ExpandBlank(mine, show, i, j);
}
}
}
}
//排查雷
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
int x, y;//排查的坐标
int count = 0;//可排查的次数
while (count < row * col - number)
{
printf("请输入要排查的坐标(中间用空格隔开):");
scanf("%d %d", &x, &y);//输入排查坐标
if (x >= 1 && x <= row && y >= 1 && y <= col)//排查坐标需要在1-9之间
{
if (mine[x][y] == '1')//如果输入的坐标位置是‘1’,则被炸死
{
printf("很遗憾,你被炸死啦!!!!\n");
printf("\n");
DisplayBoard(mine, ROW, COL);//被炸死了,将布置雷的棋盘打印出来
break;//跳出
}
else//输入位置不是雷,则显示当前位置的周围有几个雷
{
ExpandBlank(mine, show, x, y);
DisplayBoard(show, ROW, COL);//显示排查过后的用户棋盘
if (EndMine(show, ROW, COL))//返回为真
{
printf("恭喜你排雷成功!!!\n");//排雷成功
DisplayBoard(mine, ROW, COL);//打印布置的棋盘
break;
}
}
}
else
{
printf("输入坐标错误,请重新输入\n");
}
}
}
void menu()//不需要返回值,void
{
printf("\n***********************\n");
printf("***********************\n");
printf("****** 1.play *******\n");
printf("****** 0.exit *******\n");
printf("***********************\n");
printf("***********************\n");
}
void game()//不需要返回值,void
{
srand((unsigned int)time(NULL));//生成一个随机数,time函数无参返回,返回类型强制转换为unsigned
char mine[ROWS][COLS];//设置成可变量方便于修改游戏难度
char show[ROWS][COLS];
//初始化棋盘
InitBoard(mine, ROWS, COLS, '0');//用于存放雷的棋盘,初始化为0
InitBoard(show, ROWS, COLS, '*');//用于显示给用户看的,初始化为*
//打印棋盘
DisplayBoard(show, ROW, COL);//打印9×9显示给用户看的棋盘
//布置雷
SetMine(mine, ROW, COL);
//开始排查雷
FindMine(mine, show, ROW, COL);
}
int main()
{
int put = 0;
do {
menu();
printf("请输入你的选择:");
scanf(" %d", &put);
switch (put)
{
case 1:
printf("\n请开始扫雷\n");
game();
break;
case 0:
printf("\n已退出游戏!\n");
break;
default:
printf("\n选择错误,请重新输入!\n");
break;
}
} while (put);
return 0;
}