本次扫雷小游戏的C语言的实现其实与上一个三子棋小游戏的代码实现框架大致差不多,主要分为五大部分。分别为程序框架搭建、初始化棋盘,打印棋盘、布置地雷、排除地雷,以及判断游戏的输赢状态。
1.程序框架的搭建
分别建立test.c,game.c,game.h文件,其中。test.c.主要存储主函数以及主框架代码,game.c中存储有关扫雷游戏实现的函数,game.h中存储游戏函数的声明和一些宏定义。
2.初始化棋盘以及打印棋盘
首先我可以看看扫雷小游戏的基本界面便于分析和编写打印棋盘函数。
扫雷基本界面:
我们可以看出,该简单棋盘的是9*9大小的。由于后续我们要判断一个数的周围一圈八个数的雷的个数,但是一些坐标位于边界位置就可以越界了。例如下图这样,那么如何解决呢?
所以为防止数组的越界访问,我们可以初始化棋盘为11*11的,然后操作和打印就在9*9的棋盘上操作。具体操作图如下图可示:
初始化棋盘,这里因为既要布置雷的信息,又要显示周围雷的个数,为避免不必要的冲突,通过初始化两个11*11的棋盘来分别显示布置的雷和所踩坐标周围雷的个数。这里我们将第一个数组命名为mine并初始化为‘ 0’,这里‘0’为无雷,'1'为有雷。第二个数组命名为show并初始化为'*',每次排完雷后就可以将'*'覆盖掉显示出周围雷的个数。图片如下:
实现代码如下:
数组初始化:这里引入函数参数set,就可以按照想要初始化的字符初始化数组,如'0','*'。
void init_board(char arr[ROWS][COLS], int rows, int cols, char set) //初始化函数,mine初始化为'0',show初始化为'*'
{
int i = 0;
for (i = 0; i < rows;i++)
{
int j = 0;
for (j = 0; j < cols;j++)
{
arr[i][j] = set;
}
}
}
打印棋盘:这里加入了一个for循环打印第一行的列序列,以及在每一行的行头打印行号,注意我们初始化棋盘的参数为符号'0'和符号'*',所以要用%c打印字符!!!!!注意!!!!
void display_board(char arr[ROWS][COLS],int row,int col)//打印棋盘加上每行每列的序号标识
{
int i = 0;
int j = 0;
for (j = 0; 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 ",arr[i][j]); //这里打印的是字符所以用%c
}
printf("\n");
}
}
代码运行效果图如下:
3.布置雷
这里我们将布置雷的个数宏定义为COUNT,以便后续的使用。
通过while()循环,每次排雷后,count--,直到布置完雷后跳出循环。这里因为是随机设置的雷,所以使用函数srand()和rand利用时间戳产生随机数并通过取模加一的方法获取1~9的坐标数。
具体代码实现:
void set_mine(char arr[ROWS][COLS],int row,int col,int count)//利用随机数设置雷
{
while (count)
{
int x = 0;
int y = 0;
x = rand()%row+1; //1~9
y = rand()%col+1;
if (arr[x][y] == '0')
{
arr[x][y] = '1';
count--;
}
}
}
程序效果图如下:
4.排雷
这里我们编写排雷函数,利用while循环,判断条件为win<row*col-COUNT进入循环,否则跳出循环。例如COUNT=10,我们设置10个雷,9*9棋盘上就有9*9-10=71个非雷的位置。排雷就排71次。
其中还要统计所踩坐标周围八个数的雷的个数,这里通过编写get_count函数实现。具体实现为,通过将所踩坐标的周围八个数的字符减去符号‘0’然后相加就得出这八个数的数值和。(这里就是为什么我们之前初始化棋盘为'0','1'的好处所在。)然后通过函数返回的值为int 型数据,要转为字符型并在show数组中打印出来就必须将数值转为字符。可以由ASCII码表可知,数字数值转为数字字符只需加上一个字符‘0’。
具体代码实现:
void fine_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) //9*9-10=71个非雷的位置
{
printf("请输入所排的坐标:\n");
scanf("%d %d",&x,&y);
if (x > 0 && x <= row&&y > 0 && y <= col) //判断输入坐标的合理性
{
if (mine[x][y] == '1') //注意==才是判断中的=!!!!!!!!!!!!!!!
{
printf("很遗憾,踩到雷了。\n");
break;
}
else
{
int count = get_count(mine, x, y);
show[x][y] = count+'0';
display_board(show, ROW, COL);//每猜一次,显示show数组内容
win++; //排除一个雷,win++
}
}
else
printf("坐标输入错误,请重新输入。\n");
}
if (win == row*col - COUNT)
{
printf("恭喜!您已经通关!");
}
}
5.判断游戏输赢
第一种情况:踩到雷了,你输了:
判断你所输入的坐标在mine数组中是否为'1',是的话就踩到雷了,游戏结束。
第二种情况:排雷完成,你赢了:
每次排完一个雷之后,win++,因为while循环的跳出条件是win=row*col-COUNT。
所以只需在while循环外判断win是否等于row*col-COUNT则表明,雷已经排完,恭喜你,获得胜利
下面是扫雷游戏的试玩,这里我们将雷的个数设置为80,即只需排一次雷,这里我们先将雷的位置打印出来,然后排雷,尝试程序的有效性。
6.总结
这次是通过C语言实现扫雷小游戏,感觉与上次的三子棋小游戏有着大同小异的区别。我认为利用两个棋盘分别打印雷和雷数以及排雷时将雷的个数统计出来并在另一个数组中打印出来是这次游戏代码的亮点所在。扫雷游戏代码还有待改进与优化,还需继续学习,努力!!!