1、扫雷游戏的要求
我们用控制台实现一个扫雷游戏
有菜单选项选择游戏功能
9*9的棋盘,我们要存放10个雷
如果排到雷,就被炸死了,退出游戏;
如果没有雷,就计算周围有几个雷;
2.基本框架
首先我们玩游戏时先玩一把再说的,那我们就用do...while循环;玩了一把,还能再玩一把;
再用函数封装一个菜单;选择,我们就用switch选择语句;如果是1;玩游戏;如果是0,退出游戏,如果输入的是其他,那就再输入一遍,那循环条件就是input;
void meun()
{
printf("************************\n");
printf("******* 1.play *********\n");
printf("******* 0.exit *********\n");
printf("************************\n");
}
int main()
{
int input = 0;
do
{
meun();
printf("请选择:>");
scanf("%d",&input);
switch (input)
{
case 1:
//game();
break;
case 0:
printf("退出游戏!\n");
break;
default:
printf("选择错误,请重新选择!\n");
break;
}
} while (input);
return 0;
}
3、设计思路
3.1棋盘数组
我们做的事一个初级扫雷游戏,是在一个9*9的一个棋盘,那我们放雷,也就是要放入数据,我们就需要一个9*9的数组;
3.2放雷和排雷数组
假设我们再9*9的棋盘里面,用0表示非雷(没有雷),1表示雷;那么当这个位置不是雷,我们计算周围有几个雷,刚好这个位置周围有1个雷,那这个位置显示1;这就会产生歧义,这个位置是雷呢?还是周围有1个雷呢?,那我们这样,分为两个9*9的数组,一个能存放雷的信息的数组,一个是排查雷的数组,把周围有几个雷的信息,放到另一个数组里面去;
3.3数组越界
假设我们计算这个几个位置周围有几个雷,最简单的方法就是计算周围8个坐标有没有雷,但是如果再这些位置,那怎么计算,你不会还要计算周围3个位置的雷,还要计算周围5个位置的雷,这样台麻烦了,我们直接再这个棋盘上扩大一圈;上面个下面扩大一行,左边和右边扩大一列;那就能再哪个位置都能计算周围8个位置有没有雷;解决了数组越界的问题;那么我们实际上是要创建两个11*11的数组,一个放雷,一个排雷;
3.4数组类型
我们创建数组,是整型数组,还是字符数组?用字符数组,再排雷数组里,我们除了打印排雷的信息,其他的位置我们用 * 星号来表示,增加神秘感,那放雷的数组我们就用' 0 '字符0表示非雷,
’1‘字符1表示雷;
4、游戏代码
我们采用多文件的方式去实现游戏,用game.c/game.h
4.1创建数组
创建两个11*11的数组;一个存放雷,一个排雷
void game()
{
//创建数组
char mine[11][11];//存放雷的信息的数组
char show[11][11];//排查雷的信息的数组
}
4.2初始化数组
两数组都要初始化,我们用函数来实现,还能复用;
text.c
初始化函数需要数组参数,行和列,并把要初始化的内容变为一个参数,给方便;
void game()
{
//创建数组
char mine[11][11];//存放雷的信息的数组
char show[11][11];//排查雷的信息的数组
//初始化数组
Initboard(mine,11,11,'0');
Initboard(show,11,11,'1');
}
game.h
//初始化
void Initboard(char board[11][11],int row, int col,char set);
game.c
void Initboard(char board[11][11], int row, int col,char set)
{
int i = 0;
int j = 0;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
board[i][j] = set;
}
}
}
写到这里我们发现有很多的11,我们可以在game.c那里用define,进行更好的处理;ROWS表示行11,COLS表示列11;注意要包含game.c和text.c文件要包含game.h头文件,因为声明是在game.h头文件里面;
game.h
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
//初始化
void Initboard(char board[ROWS][COLS],int row, int col,char set);
game.c
void Initboard(char board[ROWS][COLS], int row, int col,char set)
{
int i = 0;
int j = 0;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
board[i][j] = set;
}
}
}
text.c
void game()
{
//创建数组
char mine[ROWS][COLS];//存放雷的信息的数组
char show[ROWS][COLS];//排查雷的信息的数组
//初始化数组
Initboard(mine,ROWS,COLS,'0');
Initboard(show,ROWS,COLS,'1');
}
4.3打印数组
我们初始化后,先打印看一下数组初始化对不对;也用函数来进行打印;
函数需要数组参数,虽然数组是一个11*11的数组,但是我们打印的是9*9的数组,我们只要看9行9列就行,ROW和COL作为行和列的参数;但是我们现在只是检查有没有成功初始化;现在还不是打印的时候;注释掉;
text.c
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);
}
game.h
//打印数组
void Displayboard(char board[ROWS][COLS],int row, int col);
game.c
打印数组,那就循环遍历数组的下标;打印完后,我们要修饰一下棋盘;然后我们再把每个行号打印出来,每个列号打印出来。因为我们到时候是根据坐标来排查雷的;
但是我们game.c有用printf函数,需要头文件,但是每个文件都有game.h头文件,可以把stdio.h头文件放在game.h头文件中;
void Displayboard(char board[ROWS][COLS], int row, int col)
{
int i = 0;
int j = 0;
printf("-------扫雷--------\n");
for (i = 0; i <= col; i++) //每一个列号
{
printf("%d ",i);
}
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");
}
4.4放雷
放雷用函数来完成
text.c
放雷是在mine数组里放的,虽然mine数组是11行11列,但是我们放雷是在9行9列;
void game()
{
srand((unsigned int)time(NULL));
//创建数组
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);
//放雷
Setboard(mine,ROW,COL);
//Displayboard(mine, ROW, COL);
}
game.c
假设我们用count表示10个雷;每放一个雷,-1;连续放10个;我们用循环解决;
我们要随机放雷,那就需要随机的下标,要用到rand函数产生随机数,随机下标
如果这个位置不是雷(’ 1 ‘);那就放雷(’ 1 ‘);count--;
注意我们使用rand函数,只需要在main函数里面调用一次srand函数就行了;
count变量的值,我们也在game.h头文件中定义。
void Setboard(char mine[ROWS][COLS], int row, int col)
{
int count = 10; //10个雷
while (count)
{
//行1~9
int x = rand() % 8 + 1;
//列1~9
int y = rand() % 8 + 1;
if (mine[x][y] != '1')
{
mine[x][y] = '1';
count--;
}
}
}
game.h
注意使用rand函数、srand函数、time函数的头文件;
EASY表示10;
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define EASY 10
//放雷
void Setboard(char mine[ROWS][COLS],int row, int col);
4.5排查雷
text.c
我们在mine数组里排查雷,把排查完雷的信息放在show数组里;
//排查雷
Findboard(mine,show,ROW,COL);
game.h
//排查雷
void Findboard(char mine[ROWS][COLS],char show[ROWS][COLS],int row, int col);
game.c
我们排查雷是多次的排查过程,我们先写一次;输入坐标;判断你这个坐标是否在范围内;如果不是;就重新输入;如果是,则判断此处是不是雷,如果是,就被炸死,退出游戏;如果不是,则判断周围有几个雷;我们用函数来计算;计算你输入的坐标在mine数组里面的其他的8个坐标;
但是我们是字符数组,那数字0-数字0是0;那字符0-字符0也是0;字符1-字符0是1;因为字符0的ASCII码是48,字符1的ASCII码是49;49-48=1;所以我们把每个坐标都减去字符0;再全部加起来;全部加起来减去8个字符0;8个字符0 == 8 * ’ 0 ‘ 。那这个Getboard函数的返回值是int,但是放在show数组的是字符,所以我们将返回的值加上字符' 0 ' 。
注意我们只是写了排查一次的情况,但是我们要排查多次,需要循环;我们一直在9*9的棋盘范围内排查下去,那就有81个位置,再减去10个雷的位置,那就是71个位置,也就是说我们需要排查71个位置后,才能完成游戏;那么循环条件就是row*col - EASY,排查完一个win++;如果排查到雷,break跳到下面,循环结束也跳到下面,但是循环结束的话,就是排查完71个位置了,所以我们在下面还需要一个判断排查完的情况;
我们调试看是否能正常排查完71个位置游戏结束,我们可以把EASY改为80个,表示这个棋盘81个位置存放80个雷,这样就更好调试出来了;
int Getboard(char mine[ROWS][COLS], int x, int y) //计算周围有几个雷
{
return 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] + mine[x][y + 1]
+ mine[x - 1][y + 1] - 8 * '0';
}
void Findboard(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 - EASY) //71个位置
{
printf("请输入坐标:");
scanf("%d %d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col) //判断坐标是否在范围内
{
if (mine[x][y] == '1')
{
printf("此处是雷,你被炸死了!\n");
Displayboard(mine, ROW, COL);
break;
}
else
{
win++;
printf("你还有%d个位置需要排查\n",row*col-EASY-win);
int c = Getboard(mine,x,y);
show[x][y] = c + '0';
Displayboard(show, ROW, COL);
}
}
else
{
printf("输入错误,请重新输入!\n");
}
}
if(win == row*col-EASY)
{
printf("恭喜你完成扫雷游戏!\n");
Displayboard(mine, ROW, COL);
}
}
5、完整的代码
game.h
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define EASY 10
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
//初始化
void Initboard(char board[ROWS][COLS],int row, int col,char set);
//打印数组
void Displayboard(char board[ROWS][COLS],int row, int col);
//放雷
void Setboard(char mine[ROWS][COLS],int row, int col);
//排查雷
void Findboard(char mine[ROWS][COLS],char show[ROWS][COLS],int row, int col);
game.c
#define _CRT_SECURE_NO_WARNINGS
#include "game.h"
void Initboard(char board[ROWS][COLS], int row, int col,char set)
{
int i = 0;
int j = 0;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
board[i][j] = set;
}
}
}
void Displayboard(char board[ROWS][COLS], int row, int col)
{
int i = 0;
int j = 0;
printf("-------扫雷--------\n");
for (i = 0; i <= col; i++) //每一个列号
{
printf("%d ",i);
}
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 Setboard(char mine[ROWS][COLS], int row, int col)
{
int count = EASY; //10个雷
while (count)
{
//行1~9
int x = rand() % row + 1;
//列1~9
int y = rand() % col + 1;
if (mine[x][y] != '1')
{
mine[x][y] = '1';
count--;
}
}
}
int Getboard(char mine[ROWS][COLS], int x, int y) //计算周围有几个雷
{
return 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] + mine[x][y + 1]
+ mine[x - 1][y + 1] - 8 * '0';
}
void Findboard(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 - EASY) //71个位置
{
printf("请输入坐标:");
scanf("%d %d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col) //判断坐标是否在范围内
{
if (mine[x][y] == '1')
{
printf("此处是雷,你被炸死了!\n");
Displayboard(mine, ROW, COL);
break;
}
else
{
win++;
printf("你还有%d个位置需要排查\n",row*col-EASY-win);
int c = Getboard(mine,x,y);
show[x][y] = c + '0';
Displayboard(show, ROW, COL);
}
}
else
{
printf("输入错误,请重新输入!\n");
}
}
if(win == row*col-EASY)
{
printf("恭喜你完成扫雷游戏!\n");
Displayboard(mine, ROW, COL);
}
}
text.c
#define _CRT_SECURE_NO_WARNINGS
#include "game.h"
void meun()
{
printf("************************\n");
printf("******* 1.play *********\n");
printf("******* 0.exit *********\n");
printf("************************\n");
}
void game()
{
srand((unsigned int)time(NULL));
//创建数组
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);
//放雷
Setboard(mine,ROW,COL);
//Displayboard(mine, ROW, COL);
Displayboard(show, ROW, COL);
//排查雷
Findboard(mine,show,ROW,COL);
}
int main()
{
int input = 0;
do
{
meun();
printf("请选择:>");
scanf("%d",&input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("退出游戏!\n");
break;
default:
printf("选择错误,请重新选择!\n");
break;
}
} while (input);
return 0;
}
感谢观看!感谢指正!