C语言(扫雷游戏)
Hi~!这里是奋斗的小羊,很荣幸各位能阅读我的文章,诚请评论指点,关注+收藏,欢迎欢迎~~
💥个人主页:小羊在奋斗
💥所属专栏:C语言
本系列文章为个人学习笔记,在这里撰写成文一为巩固知识,二为同样是初学者的学友展示一些我的学习过程及心得。文笔、排版拙劣,望见谅。
一、扫雷游戏
1、扫雷游戏规则
2、扫雷游戏的实现
2.1打印游戏菜单
2.2游戏分析
2.3打印游戏棋盘
2.4埋雷
2.5扫雷
一、扫雷游戏
1、扫雷游戏的规则
首先我们来介绍一下扫雷游戏的玩法,扫雷游戏的常规界面(9*9)如下:
上面游戏板上有许多个格子,有些格子里面埋有雷,玩家需要点击格子揭开它们,如果揭开的格子里是雷则被炸死游戏结束,若果揭开的格子不是雷则显示点开的格子周围有多少个雷,玩家需要通过给出的信息进行逻辑判断和猜测来排除所有的雷。
2、扫雷游戏的实现
2.1打印游戏界面
了解完游戏的玩法后,我们就要来好好想想要怎么通过代码来实现这个小游戏。
首先,我们需要新建一个 main.c 文件来存放函数的主体代码,新建一个 game.c 文件用来游戏实现代码,新建一个 game.h 来包含其中会用到的一些头文件和相关函数的声明。
跟其他游戏一样,我们得有个游戏菜单吧,在 —> 猜数字小游戏 这篇文章中我们已经有了一种打印游戏菜单的方法,不妨我们就继续延用这种办法吧。
main.c
#define _CRT_SECURE_NO_WARNINGS #include "game.h"//这里我将头文件包含到game.h,再在main.c和 //game.c文件中包含game.h,避免重复引用 void menu() { printf("##########################\n"); printf("######## 1.play ########\n"); printf("######## 0.exit ########\n"); printf("##########################\n"); } int main() { int input = 0; do { menu(); printf("请选择:"); scanf("%d", &input); switch (input)//通过输入的input来选择开始游戏还是退出游戏 { case 1: printf("开始游戏!\n"); break; case 0: printf("退出游戏!"); break; default: //如果不小心输入错误的值,还要提示重新选择 printf("选择错误,请重新选择!\n"); break; } } while (input);//do—while循环可以帮助我们实现重复玩游戏 return 0; }
代码运行先打印一个简易的游戏菜单,提示我们选择1开始游戏,选择0退出游戏,选择其他值则提示选择错误,重新选择。当我们选择1开始游戏,游戏结束后通过 break 跳出来到 while 判断,input 的值为1继续循环开始游戏;当我们选择0则退出游戏,通过 break 跳出来到 while 判断,input 的值为0退出循环;当我们选择其他非0的值通过 break 跳出来到 while 判断,非0继续循环。
通过代码执行可以试验出我们当前的逻辑是正确的。我们在写工程量比较大的代码时,写完一段程序最好运行试验一下是否符合我们的想法。
2.2游戏分析
接下来我们就要分析一下该如何实现这个游戏了。首先我们得有一个矩形棋盘吧,这里我们就先设计一个简单的 9*9 游戏棋盘。提到矩形 9*9 棋盘我们就很容易联想到之前学习过的二维数组,二维数组就能很好的帮我们实现这个事情,并且二维数组还能通过坐标唯一确定一个小格子。有了游戏棋盘在玩游戏之前还应该由系统自动布置好雷的位置,并且位置是随机的,影藏在棋盘下我们看不到。
我们设计的这个棋盘不仅要事先随机布置隐藏好雷,还要在我们玩的时候显示周围雷的个数,是不是对这个棋盘要求太高了,我们实现起来也比较复杂。这里我们有一个还不错的解决办法,我们可以定义两个二维数组,一个用来随机产生并且隐藏雷,在我们玩游戏的时候并不打印;另一个在我们玩的时候打印显示排雷的信息也就是周围雷的个数。
提到定义两个二维数组就不得不想清楚我们究竟要定义两个什么类型的二维数组呢?在这之前,我们需要考虑一下怎么区分雷和非雷。其实这一步有很多种方法,想要怎么设计完全由你自己决定,这里我们不妨就定义字符 ‘0’ 为雷,字符 ‘1’ 为非雷吧,至于为什么要定义为字符而不是我们常见的数字1和0,其实是有原因的。
我们前面说过,如果揭开的格子下不是雷,就要将这个格子周围的雷的数目加起来并在我们揭开的这个格子上显示,要显示的话当然显示的是数字,如果这个格子周围恰好是一个雷就要在这个格子上显示数字1,这就非常容易与我们定义的雷(0)或非雷(1)冲突,我们定义为字符的话就可以很好的避免这个问题。
还有一个隐藏的问题,如果我们想排查(8,7)这个坐标,很明显越界了,那我们要判断这个坐标是不是雷之前还要先判断数组是否越界,因为数组越界是比较危险的事情,谁也不知道越界访问到的是什么数据,严重还会导致程序崩溃,所以我们要想办法避免这个问题。
我们可以把之前定义的两个字符型二维数组大小改为 11 行 11 列,而不是用 9 行 9 列,在操作的时候外面一圈不操作,只在 9*9 的棋盘内排雷,这样就不会有越界的问题。
2.3打印游戏棋盘
接上所述,我们定义了两个 11 行 11 列的字符型二维数组,定义好后我们先将埋雷的二维数组初始化为 ‘1’,将显示排雷信息的二维数组初始化为 * ,因为埋雷的二维数组并不打印,所以我们就实现了用一个棋盘覆盖另一个棋盘的效果。
到这里我们先来看一下效果:
测试效果跟我们预期的一样,当然,在真正玩的时候上面埋雷的棋盘是不打印的,这里我们只是测试一下棋盘是否初始化成功。
相关代码如下:
main.c
#define _CRT_SECURE_NO_WARNINGS #include "game.h"//这里我将头文件包含到game.h,再在main.c和 //game.c文件中包含game.h,避免重复引用 void menu() { printf("##########################\n"); printf("######## 1.play ########\n"); printf("######## 0.exit ########\n"); printf("##########################\n"); } void game() { //定义两个二维数组作棋盘 char mine[ROWS][COLS] = { 0 };//存放雷 char show[ROWS][COLS] = { 0 };//存放排雷的信息 //初始化二维数组 Init_Board(mine, ROWS, COLS, '1'); Init_Board(show, ROWS, COLS, '*'); //打印棋盘 Display_Board(mine, ROW, COL); Display_Board(show, ROW, COL); } int main() { int input = 0; do { menu(); printf("请选择:"); scanf("%d", &input); switch (input)//通过输入的input来选择开始游戏还是退出游戏 { case 1: game(); break; case 0: printf("退出游戏!"); break; default: //如果不小心输入错误的值,还要提示重新选择 printf("选择错误,请重新选择!\n"); break; } } while (input);//do—while循环可以帮助我们实现重复玩游戏 return 0; }
game.c
#define _CRT_SECURE_NO_WARNINGS #include "game.h" void Init_Board(char board[ROWS][COLS], int rows, int cols, char set) { int i = 0; for (i = 0; i
还没有评论,来说两句吧...