完整代码下载:「链接」
一、相关知识点
这一定是你需要的电子书资源,全!值得收藏! - 知乎
程序员书籍资源,值得收藏!_C语言与CPP编程的博客-CSDN博客
1、键盘监听
在扫雷游戏中,当用户输入是否开始游戏的 Y/N 时,程序能够自动监听,当用户输入完成后,不用回车,程序立即做出反应,这就用到了键盘监听。
所谓键盘监听,就是用户按下某个键时系统做出相应的处理,本章讲到的输入输出函数也是键盘监听函数的一种,例如 getchar()、getche()、getch() 等。下面的代码演示了 getche() 函数的使用:
#include <stdio.h>#include <conio.h>int main(){ char ch; int i = 0; //循环监听,直到按Esc键退出 while(ch = getch()){ if(ch == 27){ break; }else{ printf("Number: %d\n", ++i); } } return 0;}
这段代码虽然达到了监听键盘的目的,但是每次都必须按下一个键才能执行 getch() 后面的代码,也就是说,getch() 后面的代码被阻塞了。
阻塞式键盘监听用于用户输入时一般没有任何问题,用户输入完数据再执行后面的代码往往也符合逻辑。然而在很多小游戏中,阻塞式键盘监听会带来很大的麻烦,用户要不停按键游戏才能进行,这简直就是灾难,所以在小游戏中一般采用非阻塞式键盘监听:用户输入数据后程序可以捕获,用户不输入数据程序也可以继续执行。
在 Windows 系统中,conio.h头文件中的kbhit()函数就可以用来实现非阻塞式键盘监听。
conio.h 是 Windows 下特有的头文件,所以 kbhit() 也只适用于 Windows,不适用于 Linux 和 Mac OS。
用户每按下一个键,都会将对应的字符放到输入缓冲区中,kbhit() 函数会检测缓冲区中是否有数据,如果有的话就返回非 0 值,没有的话就返回 0 值。但是 kbhit() 不会读取数据,数据仍然留在缓冲区,所以一般情况下我们还要结合输入函数将缓冲区种的数据读出。请看下面的例子:
#include <stdio.h>#include <windows.h>#include <conio.h>int main(){ char ch; int i = 0; //循环监听,直到按Esc键退出 while(1){ if(kbhit()){ //检测缓冲区中是否有数据 ch = getch(); //将缓冲区中的数据以字符的形式读出 if(ch == 27){ break; } } printf("Number: %d\n", ++i); Sleep(1000); //暂停1秒 } return 0;}
每次循环,kbhit() 会检测用户是否按下某个键(也就是检测缓冲区中是否有数据),没有的话继续执行后面的语句,有的话就通过 getch() 读取,并判断是否是 Esc,是的话就退出循环,否则继续循环。
扫雷完整代码。点击下载
2、改变输出文本的颜色
在扫雷游戏中,当用户输入是否开始游戏的 Y/N 时,程序能够自动监听,当用户输入完成后,不用回车,程序立即做出反应,这就用到了键盘监听。
C语言不总是“黑底白字”,它也可以是彩色的,可以调用Windows.h头文件下的SetConsoleTextAttribute函数改变文字和背景颜色。
调用形式为:
SetConsoleTextAttribute( HANDLE hConsoleOutput, WORD wAttributes );
hConsoleOutput表示控制台缓冲区句柄,可以通过GetStdHandle(STD_OUTPUT_HANDLE)来获得;wAttributes表示文字颜色和背景颜色。
0~F 分别代表的颜色如下:
0 = 黑色 8 = 灰色 1 = 淡蓝 9 = 蓝色 2 = 淡绿 A = 绿色 3 = 湖蓝 B = 淡浅绿C = 红色 4 = 淡红 5 = 紫色 D = 淡紫6 = 黄色 E = 淡黄 7 = 白色 F = 亮白
例如,将背景设置为淡绿色,文字设置为红色:
#include <stdio.h>#include <windows.h>int main(){ HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); SetConsoleTextAttribute(hConsole, 0x2C ); puts("c语言与cpp编程"); return 0;}
如果只希望设置文字颜色,背景保持黑色,那么也可以只给出一位16进制数,例如:
SetConsoleTextAttribute(hConsole, 0xC ); //将文字颜色设置为红色SetConsoleTextAttribute(hConsole, 0xF ); //将文字颜色设置为白色
再来看一个例子:
#include <stdio.h>#include <windows.h>int main(){ HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); SetConsoleTextAttribute(hConsole, 0xC ); puts("红色文字"); SetConsoleTextAttribute(hConsole, 0xF ); puts("白色文字"); SetConsoleTextAttribute(hConsole, 2 ); puts("淡绿色文字"); return 0;}
3、获取随机数
扫雷游戏中,雷区会随机出现在整个区域的任意位置,没有任何规律,这就要求程序能够生成随机数值,由随机数设置雷区的位置。
在 C 语言中,我们一般使用<stdlib.h> 头文件中的 rand() 函数来生成随机数,它的用法为:
int rand (void);
void 表示不需要传递参数。C语言中还有一个 random() 函数可以获取随机数,但是 random() 不是标准函数,不能在 VC/VS 等编译器通过,所以比较少用。
rand() 会随机生成一个位于 0 ~ RAND_MAX 之间的整数。
RAND_MAX 是 <stdlib.h> 头文件中的一个宏,它用来指明 rand() 所能返回的随机数的最大值。C语言标准并没有规定 RAND_MAX 的具体数值,只是规定它的值至少为 32767。在实际编程中,我们也不需要知道 RAND_MAX 的具体值,把它当做一个很大的数来对待即可。
#include <stdio.h>#include <stdlib.h>int main(){ int a = rand(); printf("%d\n",a); return 0;}
生成一定范围内的随机数
在实际开发中,我们往往需要一定范围内的随机数,过大或者过小都不符合要求,那么,如何产生一定范围的随机数呢?我们可以利用取模的方法:
int a = rand() % 10; //产生0~9的随机数,注意10会被整除
如果要规定上下限:
int a = rand() % 51 + 13; //产生13~63的随机数
分析:取模即取余,rand()%51+13我们可以看成两部分:rand()%51是产生 0~50 的随机数,后面+13保证 a 最小只能是 13,最大就是 50+13=63。
最后给出产生 13~63 范围内随机数的完整代码:
#include <stdio.h>#include <stdlib.h>#include <time.h>int main(){ int a; srand((unsigned)time(NULL)); a = rand() % 51 + 13; printf("%d\n",a); return 0;}
二、扫雷游戏初始化
扫雷游戏初始化过程中,我们使用到了 3 个二维数组:mine、show、mineDow:
mine 数组用于初始化扫雷游戏。具体做法是:首先默认整个二维数组中没有雷区,全部设为安全区域(用 0 表示),然后在二维数组中随机安插一定数量的雷区;
show 数组用于每次将结果输出给用户。当用户输入完成后,show 数组会根据用户的输入对存储的数据做适当的更新,然后输出给用户;
mineDow 数组中每个数据表示的,该位置相邻的周围雷区的数量,此数组的建立为的是实现“点击一个位置,开出一片安全区域”的效果 提示:在源代码的 game 函数中,在 mine_sweep() 函数之前的所有工作,都是初始化工作。
三、扫雷功能的实现
扫雷功能的实现,整体思路是:
判断用户输入坐标处是否是雷区;
更新 show 数组:如果是雷区,将 show 数组中该坐标位置上由字符 ‘*’ 改为表示雷区的字符 ‘o’;如果不是雷区,借助 mineDow数组中存储的信息,使用递归的方式,找到其他符合条件的非雷区区域(show_deal 函数的作用),将找到的所有区域一并更新到 show 数组中;
将新的 show 数组以一定的格式输出,反馈给用户;
提示:show_deal 函数找的是该区域既不是雷区,其周围也没有雷区的区域,将其全部更新到 show 数组中。一旦遇到周围有雷区的区域(这部分区域也会被更新到 show 数组中),则递归结束。
扫雷功能的具体实现,可见源代码中的 mine_sweep 函数。
四 扫雷界面的优化
扫雷界面,实际上是将 show 数组中存储的数据换了一种方式输出出来。
例如,show 数组中存储有字符 ‘*’,在输出时,统一换为“■”;表示雷区的字符 ‘o’,统一换为 ‘●’,等等。
注意:用于替换的字符,并不是普通的字符,它们并不在 ASCII 码范围内,是宽字符,占用两个字节。
采用此种方式,再配以合适的颜色(采用Windows API),可以将二维数组以如下的这种形式反馈给用户:
扫雷界面的详细优化代码,可见原代码中的 display_board() 函数的实现。
完整扫雷代码下载,点击 下方链接:
「链接」
用户评论
这款扫雷游戏真的太简单了,玩起来就是满满的回忆啊。
有17位网友表示赞同!
小时候玩的游戏现在都能找到,感觉很温馨。
有13位网友表示赞同!
没想到扫雷还能做成这样子的简易版本,感觉好新鲜。
有20位网友表示赞同!
这种游戏玩起来轻松愉快,适合消磨时间。
有10位网友表示赞同!
扫雷小游戏的魅力不减当年,太经典了。
有16位网友表示赞同!
简单易懂,操作方便,适合所有年龄段的玩家。
有11位网友表示赞同!
小时候总是玩得不亦乐乎,现在还能回味那些日子。
有13位网友表示赞同!
扫雷游戏让人瞬间回到了那个无忧无虑的童年时期。
有12位网友表示赞同!
游戏的画面虽然简单,但乐趣不减。
有16位网友表示赞同!
玩这款小游戏让我想起了家里的那台老电视。
有13位网友表示赞同!
这样的游戏不仅消遣时间,还让人怀念。
有9位网友表示赞同!
玩了一次就上瘾了,真是越玩越想玩。
有13位网友表示赞同!
简单的操作,却带来了无尽的欢乐。
有18位网友表示赞同!
扫雷小游戏的互动性非常强,和朋友一起玩更有意思。
有7位网友表示赞同!
老少皆宜的游戏,无论何时何地都能玩。
有9位网友表示赞同!
这种游戏让人在繁忙的生活中找到了一丝宁静。
有5位网友表示赞同!
小时候妈妈总是提醒我注意危险,现在看来还真是如此。
有17位网友表示赞同!