打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
简单的撸了一个扫雷小游戏

一、相关知识点

程序员必备资源,值得收藏!点击下载

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() 函数的实现。

 扫雷完整代码。点击下载

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
转贴:EXCEL表中RAND函数的妙用
Excel生成随机数的几种方法及实例
Excel工作表中产生不重复随机整数的两种方法
Excel产生随机数Rand函数巧妙应用
随机,一场随机的遇见,RAND()和RANK()的故事里多了个INDEX()-【Excel问伊答187】
用RAND RANK函数组合,实现“随机安排面试顺序”的功能
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服