扫雷游戏的分析和设计:
1.棋盘是 9*9 的格子
2.随机布置 10 个雷
3.可以排查雷
若位置不是雷,则显示周围有几个雷
若位置是雷,则游戏结束
找出所有的10个雷,游戏成功
设计思路:
设计mine数组(9*9)用来存放雷,规定1为雷,0为非雷。(注:这样设计便于后面对雷进行排查);
设计show数组(9*9)用来存放排查格子周围雷的信息,数字为雷的个数,'*'表示未排查,这个数组作为游戏界面。(注:分为两个数组进行存放,可以更好的设计雷,并且统计雷的个数);
注意事项:
在进行雷的排查时,对于中间部分的方格(红底),可以将方格周围的数字相加(注:雷是1,非雷是0),通过所得的值即为雷的数量。但对于边界方格(绿底),周围不存在方格,所以可以在方格外面加以一个边框,直接统计周围数值之和就可以排查雷的数量。
加上边框后:将边框设值为0,所以此时mine数组的大小为11*11,为了使两个数组一一对应。故将show数组也设置为11*11。并且统一将两个数组设置为char型,这样可以将一个函数作用于两个数组。
游戏开始界面:
用户需要选择玩游戏或者退出游戏,所以要给出一个菜单供选择。
void menu()
{
printf("*****************************\n");
printf("***** 1. play *****\n");
printf("***** 0. exit *****\n");
printf("*****************************\n");
}
int main()
{
int input;
do
{
menu();
printf("请选择:>\n");
scanf("%d", &input);
switch (input)
{
case 1:
printf("扫雷游戏开始:\n");
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("选择错误重新选择\n");
break;
}
} while (input);
return 0;
}
菜单执行结果:
游戏的主程序设计:
定义行和列:
采用全局变量定义行(ROW)和列(COL),而ROWS和COLS是加了边框后的行和列。这样方便随时修改变量的大小。
#define ROW 9//行
#define COL 9//列
#define ROWS ROW+2
#define COLS COL+2
#define EASY_COUNT 10//十个雷
初始化数组:
首先建立两个char型的二维数组,mine数组(9*9)用来存放雷,规定1为雷,0为非雷。show数组(9*9)用来存放排查格子周围雷的信息,数字为雷的个数,'*'表示未排查。创建函数InitBoard对两个数组初始化,由于初始化的值不同,固又要多加一个参数表示初始化的字符,但两个数组进行初始化时仍可以采用同一个函数。
在mine数组中布置雷:
首先,雷是随机进行布置,所以要采用rand函数来布置,在使用rand函数前要使用time函数和srand函数,使其生成随机数。而time函数和srand函数只需使用一次,故放在main函数中。
int main()
{
int input;
srand((unsigned int)time(NULL));
do
{
menu();
printf("请选择:>\n");
scanf("%d", &input);
switch (input)
{
case 1:
printf("扫雷游戏开始:\n");
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("选择错误重新选择\n");
break;
}
} while (input);
return 0;
}
由于添加边界,所以在布置雷时仅仅将mine函数中间的值变为1即可,传参时传入ROW,COL即可。注意在布置雷时要先判断该方格中是否没有雷。
void SetMine(char mine[ROWS][COLS], int row, int col)//布置雷
{
int count = EASY_COUNT;
while (count)
{//随机数布置雷
int x = rand() % row + 1;
int y = rand() % row + 1;
if (mine[x][y] == '0')
{
mine[x][y] = '1';
count--;
}
}
}
棋盘的打印:
show数组作为游戏界面,需进行打印,然而只用打印中间9*9的方格即可,为了方便坐标的输入,在打印时加入提示信息和数组下标。
void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
int i = 0, j = 0;
printf("--------扫雷游戏--------\n");
for (i = 0; i <= row; i++)//打印列数
printf("%d ", i);
printf("\n");
for (i = 1; i <= row; i++)
{
printf("%d ", i);//打印1行数
for (j = 1; j <= col; j++)
{
printf("%c ", board[i][j]);
}
printf("\n");
}
printf("------------------------\n");
}
雷的排查和数量统计:
数组mine用来存放雷。所以指定坐标后只需计算周围对应数值之和就是雷的数量,并且将这个和传入对应位置的show数组中。注意此处的和是int型,而show元素是char型,所以要实现数字向字符的转换,数字+字符'0'=该数字对应字符。
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)//排查雷
{
int x = 0, y = 0;
int num = 0;
while (num<row*col-EASY_COUNT)
{
printf("请输入要排查的坐标:>\n");
scanf("%d%d", &x, &y);
if (x >= 1 && x <= ROW && y >= 1 && y <= ROW)
{
if (mine[x][y] == '1')
{
printf("游戏失败,此处是雷!\n");
DisplayBoard(mine, ROW, COL);
break;
}
else
{
int count = GetMineCount(mine, x, y);
show[x][y]=count + '0';//数字加上字符'0'对应数字对应字符
// 1 + '0' = '1' 2 + '0' = '2'
DisplayBoard(show, ROW, COL);
num++;
}
}
else
{
printf("坐标错误重新输入:>\n");
}
}
if (num == row * col - EASY_COUNT)
{
printf("恭喜你,排雷成功!\n");
DisplayBoard(show, ROW, COL);
}
}
GetMineCount函数:
用来统计坐标周围雷的数量,mine数组(9*9)用来存放雷,规定1为雷,0为非雷所以只要计算周围对应数值之和就是雷的数量。
int GetMineCount(char mine[ROWS][COLS],int x,int y)//查找雷的数量
{
//由于雷是1,非雷是0,可以使周围数字相加之和就是雷的数量
return (mine[x - 1][y - 1] +
mine[x - 1][y] +
mine[x - 1][y + 1] +
mine[x][y - 1] +
mine[x][y + 1] +
mine[x + 1][y - 1] +
mine[x + 1][y]+
mine
运行结果:
mine数组是后台布置雷,而show数组则是游戏界面,通过对数组的初始化,对数组mine布置雷。通过用户的不断输入猜测坐标对数组mine排查周围雷的数量,并且将雷的数量赋值给在show数组对应位置上,通过show数组的不断改变从而达到游戏目的。
源码:
#define ROW 9//行
#define COL 9//列
#define ROWS ROW+2
#define COLS COL+2
#define EASY_COUNT 10//十个雷
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
void menu()
{
printf("*****************************\n");
printf("***** 1. play *****\n");
printf("***** 0. exit *****\n");
printf("*****************************\n");
}
void InitBoard(char board[ROWS][COLS], int rows, int cols,char set)
{
int i = 0, 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, j = 0;
printf("--------扫雷游戏--------\n");
for (i = 0; i <= row; i++)//打印列数
printf("%d ", i);
printf("\n");
for (i = 1; i <= row; i++)
{
printf("%d ", i);//打印1行数
for (j = 1; j <= col; j++)
{
printf("%c ", board[i][j]);
}
printf("\n");
}
printf("------------------------\n");
}
void SetMine(char mine[ROWS][COLS], int row, int col)//布置雷
{
int count = EASY_COUNT;
while (count)
{//随机数布置雷
int x = rand() % row + 1;
int y = rand() % row + 1;
if (mine[x][y] == '0')
{
mine[x][y] = '1';
count--;
}
}
}
int GetMineCount(char mine[ROWS][COLS],int x,int y)//查找雷的数量
{
//由于雷是1,非雷是0,可以使周围数字相加之和就是雷的数量
return (mine[x - 1][y - 1] +
mine[x - 1][y] +
mine[x - 1][y + 1] +
mine[x][y - 1] +
mine[x][y + 1] +
mine[x + 1][y - 1] +
mine[x + 1][y]+
mine[x + 1][y + 1]-8*'0');
}
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)//排查雷
{
int x = 0, y = 0;
int num = 0;
while (num<row*col-EASY_COUNT)
{
printf("请输入要排查的坐标:>\n");
scanf("%d%d", &x, &y);
if (x >= 1 && x <= ROW && y >= 1 && y <= ROW)
{
if (mine[x][y] == '1')
{
printf("游戏失败,此处是雷!\n");
DisplayBoard(mine, ROW, COL);
break;
}
else
{
int count = GetMineCount(mine, x, y);
show[x][y]=count + '0';//数字加上字符'0'对应数字对应字符
// 1 + '0' = '1' 2 + '0' = '2'
DisplayBoard(show, ROW, COL);
num++;
}
}
else
{
printf("坐标错误重新输入:>\n");
}
}
if (num == row * col - EASY_COUNT)
{
printf("恭喜你,排雷成功!\n");
DisplayBoard(show, ROW, COL);
}
}
void game()
{
char mine[ROWS][COLS];
char show[ROWS][COLS];
//初始化函数
InitBoard(mine, ROWS, COLS, '0');
InitBoard(show, ROWS, COLS, '*');
//棋盘的打印
//DisplayBoard(mine, ROW, COL);
DisplayBoard(show, ROW, COL);//只打印一个9*9
//布置雷
SetMine(mine, ROW, COL);//只在中间9*9的格子里面放雷
//DisplayBoard(mine, ROW, COL);
//排查雷
FindMine(mine, show, ROW, COL);
}
int main()
{
int input;
srand((unsigned int)time(NULL));
do
{
menu();
printf("请选择:>\n");
scanf("%d", &input);
switch (input)
{
case 1:
printf("扫雷游戏开始:\n");
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("选择错误重新选择\n");
break;
}
} while (input);
return 0;
}