前言
🎈大家好,我是何小侠🎈
🌀大家可以叫我**小何或者小侠🌀**
🔴我是一名普通的博客写作者🔴
💐希望能通过写博客加深自己对于学习内容的理解💐
🌸也能帮助更多人理解和学习🌸
🍃我的主页:何小侠的主页🍃
这篇博客我们一起来学习如何用C语言所学知识来实现扫雷,另外我们还将学习一个难点TNT式展开。希望能帮助大家理解和学习
🍊
引子🍊
扫雷最原始的版本可以追溯到1973年一款名为“方块”的游戏。
不久,“方块”被改写成了游戏“Rlogic”。在“Rlogic”里,玩家的任务是作为美国海军陆战队队员,为指挥中心探出一条没有地雷的安全路线,如果路全被地雷堵死就算输。两年后,汤姆·安德森在“Rlogic”的基础上又编写出了游戏“地雷”,由此奠定了现代扫雷游戏的雏形。1981年, 微软公司的 罗伯特·杜尔 和 卡特·约翰逊 两位工程师在Windows
3.1系统上加载了该游戏,扫雷游戏才正式在全世界推广开来。 扫雷很快在全球范围内流行开来,成为Windows操作系统中最受欢迎的游戏之一。许多人在办公室和家庭中都玩这个游戏来消磨时间。**
随着移动设备的普及,扫雷也进入了移动设备领域。现在,扫雷已经成为了一种经典的游戏,被广泛地应用于各种平台和设备中。
游戏思路🍊
我们看一下我们的扫雷游戏的图片
这就是我们熟悉的扫雷游戏,虽然我们现在没有能力将它100%的复刻出来,但是大部分的逻辑在我们的努力下是能够做到的。
首先我们看一下简单的逻辑
我们点击这个数字为2的方格后,这个方格显示了2的数字,这就是告诉我们在这个九宫格内,一共有两个雷。
我点击随机点击这个九宫格,直达有雷,最后我们看到确实是这样。(当然我们后面也会介绍TNT式展开)
现在我们应该就能大致理解这个游戏了,大概的思路是:
- 首先要有雷。
- 然后再排雷。
- 如果排到了雷就游戏结束,如果没有排到,就应该显示一下周围有几个雷,然后继续排。
- 游戏胜利——我们将所有的雷找出来,或者拍完所有非雷坐标。
但是我们肯定需要东西来存储扫雷的数据,用什么呢?
对, 应该是数组而且是二维数组,由于我们后面主要将9x9,所以我们就需要一个9x9的二维数组,但是这其中还是有一点细节的。下面我们将会探讨。
我们在给二维数组初始化的时候,如果用‘1’表示雷,‘0’表示非雷。
由于‘0’太多了我就不画完了。
我们会发现一个问题如果在九宫格里只有一个雷的时候,我们这个‘1’就存在歧义了,
但是有人想说,那我就不用‘1’‘0’表示雷和非雷不就行了吗?我用‘’和‘#’表示雷与非雷就行
但是如果这样我们的数组的内容就很杂乱,我们和我们玩的扫雷就存在很大的差距,我们在电脑上玩的扫雷游戏总体上只有三种内容,要么是空格,要么是数字,要么是雷。那我们应该怎么办呢?
我们就可以用两个大小相同的二维数组,一个专门放置雷,一个就专门用来展示有关于雷的信息,这个信息也是从放置雷的数组得来的。
下面给出参考
我们在放置雷的数组中只用‘1’,‘0’。在展示给玩家的数组中,没有被排查的位置全部置为‘’保持神秘感,然后排查的位置就用与九宫格雷数相等的字符数字来表示
所以我们定义两个数组 char mine[ 9 ][ 9 ], char show[ 9 ][ 9 ]
但是我们现在任然存在一个问题。
我们在mine数组检测玩家点击的方格时,如果玩家点击到的是最外层的方格,我们就会越界访问。
怎么解决呢?
那我们就直接把数字开大一点就行char mine[ 11 ][ 11 ],我特意画了一个图来展示。
可以看到即使我们在9x9棋盘的边缘查找,也不会越界。为了保证mine数组和show数组是严格对应的,我们也把show数组开大一点,变成show[ 11 ][ 11 ]。
这就是我们大概的游戏思路,接下来我们开始实现。
定义和初始化
void game() { //定义二维数组 char mine[ROWS][COLS]; char show[ROWS][COLS]; ······ }
我们暂时先给出一点代码,避免干扰思路,
注意看我们用的常量ROWS,和COLS来定义。
这是我们在头文件用#define定义的,为什么我们还非要写ROW,和COL呢?因为我们有时候不需要操作整个数组,只需要操作9x9就行。
然后是我们的初始化->
void game() { //定义二维数组 char mine[ROWS][COLS]; char show[ROWS][COLS]; //初始化二维数组 init_arr(mine, ROWS, COLS, '0'); init_arr(show, ROWS, COLS, '*'); ·······
//初始化二维数组 void init_arr(char arr[ROWS][COLS], int rows, int cols, char ch) { int i = 0; int j = 0; for (i = 0; i < rows; i++) { for (j = 0; j < cols; j++) { arr[i][j] = ch; } } }
可以看到我们传的最后一个参数,我们可以根据你要初始化什么字符来使用这个函数,也是这个初始化比较好的部分。
这个还有一个要注意的地方,我们写形参的时候不能写char arr[ROW][COL],因为我们传的是整个数组。我们后来用小写 rows,cols表示ROWS,COLS增加可读性,避免一直用大写ROWS,COLS,当然用也没什么问题,但是我感觉小写看着舒服一点。
打印棋盘
打印棋盘没有太多要讲的,格式大家可以多调一调。
void game() { //定义二维数组 char mine[ROWS][COLS]; char show[ROWS][COLS]; //初始化二维数组 init_arr(mine, ROWS, COLS, '0'); init_arr(show, ROWS, COLS, '*'); //打印二维数组 display (show, ROW, COL); ··········
void display(char arr[ROWS][COLS], int row, int col) { printf("·················扫雷·················\n"); int i = 0; int j = 0; for (i = 0; i <= row; i++) { printf(" %d ", i); if (i > 0) printf(" "); } printf("\n"); printf("\n"); for (i = 1; i <= row; i++) { printf(" %d ", i); for (j = 1; j <= col; j++) { printf(" %c ", arr[i][j]); if (j <= col -1) printf("|"); } printf("\n"); if (i <= row - 1) { printf(" "); for (j = 0; j < col; j++) { printf("---"); if (j < col - 1) printf("|"); } printf("\n"); } } printf("·················扫雷··················\n"); }
有过要注意的点,我们打印的数组下标是从1开始,因为最外围是我们不需要用的,我上面有一张图可以看,这里就不再插入图片了。
如果有人看不太懂可以去看看我三子棋的博客>:链接: link
打印出来效果就是这样。我感觉看起来比起一堆数字还是舒服一点。但是这个提示的几行几列数字不是很好打印,要多调整调整。当然我们也可以打印show数组,打印出来就全是‘*’
布置雷
我们想要布置雷,那我们一定是要在mine数组,我们只需要在9x9的领域布置,那我们就只需要传ROW,COL。我们也还有设定一下雷的数量,埋完就不埋了。
void game() { //定义二维数组 char mine[ROWS][COLS]; char show[ROWS][COLS]; //初始化二维数组 init_arr(mine, ROWS, COLS, '0'); init_arr(show, ROWS, COLS, '*'); //打印二维数组 display (show, ROW, COL); //埋雷 set_mine (mine, ROW, COL); ······ }
void set_mine(char mine[ROWS][COLS], int row, int col) { int x = 0; int y = 0; int count = EASY; while (count) { x = rand() % row + 1; y = rand() % col + 1; if (x > 0 && x <= row && y > 0 && y <= col && mine[x][y]!='1') { mine[x][y] = '1'; count--; } } }
如果有小伙伴看不懂rand()这个函数的用法可以看看我的这篇博客.
链接: link
这里我就直接用EASY表示简单模式了,只埋10个雷。