c/c++语言用Easyx写出扫雷(保姆级教学),有源代码!!!!!!!!

2024-03-24 17:10

本文主要是介绍c/c++语言用Easyx写出扫雷(保姆级教学),有源代码!!!!!!!!,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

游戏截图:

看完之后有帮助记得点个赞和关注

目录

一.实现原理:

二.素材:

三.源代码

四.注意事项:

五.心得体会:


一.实现原理:

1.先通过https://easyx.cn/网址下载easyx方可开始使用(要有一点easxy的基础)

2.原理:

首先扫雷的布局其实就是二维数组,通过用不同的数字代替不同的效果来实现扫雷(如:-1代表雷,0代表空格,1就代表点开后的数字1,2代表数字2........),通过不同的数字来进行在对应的位置进行贴图。

当我们想好原理之后,就可以开始理一下思路、我们要先创造一个大一点的二维数组(初始值为0)这样可以方便我们后续进行难度的提升(如:可以创造一个102*102的二维数组这样我们可以通过利用不同大小的数组来进行扫雷难度的升级)。接着我们可以写一个函数随机出n个雷(n为你自己想设计的,最好设置成为一个未知数,方便后续不同难度的不同雷数的修改),这个函数的核心是用srand()函数布下一个种子,然后再二维数组中的不同位置随机附上n个不同位置的-1。这样的随机雷的效果就做出来了。

接下来我们要计算每个位置(除开炸弹的位置,就是-1的位置)附近九宫格的雷数,这样方便后续点开方块后的贴图。现在你所设置的游戏区域大小的数字都是-1到8的数字,接下用一个循环把你所有的游戏区域的数字都加上20(原因后面代码会体现出来),这样游戏区域的数字就是19到28之间。

现在万事大吉只差贴图,先将所有的图片loadimage函数加载好(图片后面up主^(* ̄(oo) ̄)^会附上),但是记得图片要放在代码文件的根目录下,这样写相对路径时候要方便一点。

最后一步就是我们要用一个while循环来不断地获取用户的鼠标输入(这里大家可以看一下getmousemsg函数),并且用一个函数来不断地打印地图。这样就可以实现扫雷的实现。

剩下就是一些细节的添加(如:时间的跳动和雷数的显示和笑脸点击后会重新开始游戏及返回界面按钮)

 

 

 

二.素材:

这里需要读者自己截出想要的部分(要是懒得话也可以私信up^(* ̄(oo) ̄)^主获取截好的图片)

三.源代码

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <graphics.h>
int grahight = 415;//实际画布高
int grawidth = 340;//实际画布宽
#define allhight 100//总数组大小
#define allwidth 100//总数组大小
//中级17*17:415*340,初级10*10:275*200,高级20*20:475*400
int hight = 17;//实际游戏区域大小
int width = 17;//实际游戏区域大小
int times = 0;//获取总时间
int time1 = 0, time2 = 0, time3 = 0;//记录时间的三位
int first = 1;//判断第一次点击
int bomb = 45;//炸弹数量
int runing = 1;//是否结束游戏
int smiles = 0;//笑脸图的变化
int ture = 1;//判断是否开始游戏
int a = 1;//不让它一直弹出胜利的框
int map[allhight + 2][allwidth + 2] = { 0 };//布局战场都出的两行和两个列用来辅助找出周围炸弹数
clock_t start_t, end_t;//开始实际时间,结束时间算时间差
IMAGE block[13];//1-8和空格和炸弹图片
IMAGE smile[4];//笑脸的各种状态
IMAGE numbomb[10];//时间图片
int numbombs = 0;//炸弹第一位数
int numbombss = 0;//炸弹第二位数
int win = 0;//判断是否赢
int choice = 0;//看用户是否选择
void printfmap();//打印地图
void updategame();//更新数据并且加密
int findbomb(int a, int b);//找正常方块附近的炸弹数量
void theloadimage();//加载图片
void playgame();//获取用户的点击
void newgame();//刷新游戏
void whitchtouch2();//选择 难度界面函数
void showbomb();//点击炸弹后显示所有炸弹
void openzero(int m, int n);//遇到空格打开,递归思想
void whitchtouth();//开始界面的选择函数
void printfmaps()
{for (int i = 1; i <= hight; i++){printf("第%d行:", i);for (int j = 1; j <= width; j++){int a = (j - 1) * 20;int b = (i - 1) * 20 + 72;printf("%3d", map[i][j]);}printf("\n");}
}
//输出后台数据看炸弹在哪,外挂!!!!!
void before();
int main()
{HWND hwnd = initgraph(grawidth, grahight);setbkcolor(RGB(189, 189, 189));cleardevice();//准备过程while (ture){settextcolor(BLACK);rectangle(80, 50, 250, 120);outtextxy(130, 80, L"开始游戏");rectangle(80, 150, 250, 220);outtextxy(130, 180, L"难度设置");outtextxy(30, 280, L"游戏说明:");outtextxy(105, 280, L"点击笑脸可以重新开始,开始");outtextxy(105, 305, L"游戏默认中级难度,可以选择");outtextxy(105, 330, L"难度直接开始游戏,点击返回");outtextxy(105, 355, L"回到界面");whitchtouth();}cleardevice();while (choice){settextcolor(BLACK);rectangle(80, 50, 250, 120);outtextxy(130, 80, L"初级");rectangle(80, 150, 250, 220);outtextxy(130, 180, L"中级");rectangle(80, 250, 250, 320);outtextxy(130, 280, L"高级");whitchtouch2();}initgraph(grawidth, grahight);setbkcolor(RGB(189, 189, 189));cleardevice();//开始numbombss = bomb % 10;numbombs = bomb / 10;theloadimage();updategame();printfmaps();while (1){printfmap();playgame();if (win == hight * width - bomb && a){a = 0;smiles = 3;printfmap();MessageBox(hwnd, L"you win the game!", L"", MB_OK);}if (smiles == 1)//点击笑脸就会重新开始游戏{first = 1;a = 1;win = 0;system("cls");newgame();printfmaps();}end_t = clock();int q = (end_t - start_t) / 1000;if (runing == 1 && first == 0 && win != hight * width - bomb){time1 = q / 100;time2 = q / 10 % 10;time3 = q % 10;}if (first == 1){time1 = time2 = time3 = 0;}}closegraph();return 0;
}
void printfmap()
{outtextxy(grawidth / 2 - 25, 0, L"返回");putimage(grawidth / 2 - 20, 30, &smile[smiles]);//中间笑脸图片putimage(10, 10, &numbomb[numbombs]);//这个和下个都是显示炸弹数量图片putimage(40, 10, &numbomb[numbombss]);putimage(grawidth - 90, 10, &numbomb[time1]);//下面三个都是时间图片putimage(grawidth - 60, 10, &numbomb[time2]);putimage(grawidth - 30, 10, &numbomb[time3]);for (int i = 1; i <= hight; i++){for (int j = 1; j <= width; j++){int a = (j - 1) * 20;int b = (i - 1) * 20 + 72;if (map[i][j] <= 28 && map[i][j] >= 19)//19-28表示没点开的所以都是方块图片。这就是为什么要加20的原因putimage(a, b, &block[0]);else if (map[i][j] <= 8 && map[i][j] >= -1){switch (map[i][j]){case -1:putimage(a, b, &block[9]);break;case 0:putimage(a, b, &block[10]);break;case 1:putimage(a, b, &block[1]);break;case 2:putimage(a, b, &block[2]);break;case 3:putimage(a, b, &block[3]);break;case 4:putimage(a, b, &block[4]);break;case 5:putimage(a, b, &block[5]);break;case 6:putimage(a, b, &block[6]);break;case 7:putimage(a, b, &block[7]);break;case 8:putimage(a, b, &block[8]);break;}}////上面这个if就是用来用户点击之后减去20就变成-1到8就显示出对应图片else if (map[i][j] <= 48 && map[i][j] >= 39)//右键加20然后,就在39到48之间,这些都是镖旗图标putimage(a, b, &block[11]);else if (map[i][j] == -100)//这是点到的炸弹要变红putimage(a, b, &block[12]);}}
}
void updategame()
{srand((unsigned int)time(NULL));int n = 0;while (n < bomb){int x = rand() % hight + 1;int y = rand() % width + 1;if (map[x][y] == 0 && x != 0 && y != 0){map[x][y] = -1;n++;}}//布置地雷for (int i = 1; i <= hight; i++){for (int j = 1; j <= width; j++){if (map[i][j] == 0){int sign = 0;sign = findbomb(i, j);map[i][j] = sign;}}}//查找不是雷的区域周围的雷数for (int i = 1; i <= hight; i++){for (int j = 1; j <= width; j++){map[i][j] += 20;}}//加密
}
int findbomb(int a, int b)
{int all = 0;for (int i = a - 1; i <= a + 1; i++){for (int j = b - 1; j <= b + 1; j++){if (map[i][j] == -1){all++;}}}return all;
}
void theloadimage()
{//加载图片loadimage(&block[0], L"img/方块.png", 20, 20);loadimage(&block[1], L"img/11.png", 20, 20);loadimage(&block[2], L"img/22.png", 20, 20);loadimage(&block[3], L"img/33.png", 20, 20);loadimage(&block[4], L"img/44.png", 20, 20);loadimage(&block[5], L"img/55.png", 20, 20);loadimage(&block[6], L"img/66.png", 20, 20);loadimage(&block[7], L"img/77.png", 20, 20);loadimage(&block[8], L"img/88.png", 20, 20);loadimage(&block[9], L"img/bom.png", 20, 20);loadimage(&block[10], L"img/方块2.png", 20, 20);loadimage(&block[11], L"img/flag.png", 20, 20);loadimage(&block[12], L"img/red-bom.png", 20, 20);loadimage(&smile[0], L"img/笑脸.png", 30, 30);loadimage(&smile[1], L"img/笑脸2.png", 30, 30);loadimage(&smile[2], L"img/dead.png", 30, 30);loadimage(&smile[3], L"img/cool.png", 30, 30);loadimage(&numbomb[0], L"img/0.png", 30, 50);loadimage(&numbomb[1], L"img/1.png", 30, 50);loadimage(&numbomb[2], L"img/2.png", 30, 50);loadimage(&numbomb[3], L"img/3.png", 30, 50);loadimage(&numbomb[4], L"img/4.png", 30, 50);loadimage(&numbomb[5], L"img/5.png", 30, 50);loadimage(&numbomb[6], L"img/6.png", 30, 50);loadimage(&numbomb[7], L"img/7.png", 30, 50);loadimage(&numbomb[8], L"img/8.png", 30, 50);loadimage(&numbomb[9], L"img/9.png", 30, 50);}
void playgame()
{//获取用户的鼠标输入if (MouseHit())//判读有误键盘输入,没有就跳过,免得影响时间的进行,如果没有这个if它会等一下,导致时间是跳动的,读者可以自己删去if来看一下会发生什么{MOUSEMSG msg = GetMouseMsg();int x = msg.x;int y = msg.y;switch (msg.uMsg){case  WM_LBUTTONDOWN:if (x >= 0 && x <= grawidth && y >= 72 && y <= grahight && runing && smiles != 3){if (first == 1)//判读第一次点击开始计时{start_t = clock();first = 0;}x = x / 20 + 1;y = (y - 72) / 20 + 1;if (map[y][x] <= 28 && map[y][x] >= 19){if (map[y][x] == 20)//如果点开的是0需要展开周围8个,8个中有0就还要展开,同时保证自己展开的不是炸弹{openzero(y, x);}else{map[y][x] -= 20;//正常的就直接展开win++;if (map[y][x] == -1)win--;//防止最后一个是雷变成又是赢,又有炸弹}}if (map[y][x] == -1){map[y][x] = -100;//点到的炸弹要标红,所以单独设置一个数字,来展示这张图片showbomb();//点到炸弹要把炸弹全部展开smiles = 2;//输了的话就变成哭脸printfmap();runing = 0;//输了就不能点击游戏区}}else if (x >= grawidth / 2 - 20 && x <= grawidth / 2 + 10 && y >= 20 && y <= 55){smiles = 1;runing = 1;}else if (x >= grawidth / 2 - 25 && x <= grawidth / 2 + 10 && y >= 0 && y <= 19){before();printf("1\n");}break;case WM_LBUTTONUP:if (runing == 1 && win != hight * width - bomb)smiles = 0;//除了输赢和点击否则都是笑脸break;case WM_RBUTTONDOWN:if (x >= 0 && x <= grawidth && y >= 72 && y <= grahight && runing == 1)//右键镖旗{if (first == 1){start_t = clock();first = 0;}x = x / 20 + 1;y = (y - 72) / 20 + 1;if (map[y][x] <= 28 && map[y][x] >= 19){map[y][x] += 20;}else if (map[y][x] <= 48 && map[y][x] >= 39){map[y][x] -= 20;}}break;}}}
void openzero(int m, int n)
{map[m][n] -= 20;//打开本身win++;for (int i = m - 1; i <= m + 1; i++){for (int j = n - 1; j <= n + 1; j++){if (i >= 1 && i <= width && j >= 1 && j <= hight)//保证在游戏区{if (map[i][j] <= 28 && map[i][j] >= 19)//保证没有翻开{if (map[i][j] != 20)//保证不是0{map[i][j] -= 20;win++;}elseopenzero(i, j);//递归}}}}
}
void newgame()
{for (int i = 1; i <= hight; i++){for (int j = 1; j <= width; j++){map[i][j] = 0;}}updategame();}
void whitchtouth()
{MOUSEMSG msg = GetMouseMsg();int x = msg.x;int y = msg.y;switch (msg.uMsg){case  WM_LBUTTONDOWN:if (x >= 80 && x <= 250 && y >= 50 && y <= 120){ture = 0;}else if (x >= 80 && x <= 250 && y >= 150 && y <= 220){ture = 0;choice = 1;}break;}}
void showbomb()
{int i, j;for (i = 1; i <= hight; i++){for (j = 1; j <= width; j++){if (map[i][j] == 19){map[i][j] -= 20;}}}
}
void whitchtouch2()
{MOUSEMSG msg = GetMouseMsg();int x = msg.x;int y = msg.y;switch (msg.uMsg){case  WM_LBUTTONDOWN:if (x >= 80 && x <= 250 && y >= 50 && y <= 120){choice = 0;cleardevice();hight = 10;width = 10;grahight = 275;grawidth = 200;bomb = 15;}else if (x >= 80 && x <= 250 && y >= 150 && y <= 220){cleardevice();choice = 0;hight = 17;width = 17;grahight = 415;grawidth = 340;bomb = 45;}else if (x >= 80 && x <= 250 && y >= 250 && y <= 320){cleardevice();choice = 0;hight = 20;width = 20;grahight = 475;grawidth = 400;bomb = 60;}break;}
}
void before()
{for (int i = 1; i <= hight; i++){for (int j = 1; j <= width; j++){map[i][j] = 0;}}ture = 1;//重置参数choice = 0;first = 1;smiles = 0;runing = 1;win = 0;a = 1;system("cls");initgraph(340,415);setbkcolor(RGB(189, 189, 189));cleardevice();//准备过程while (ture){settextcolor(BLACK);rectangle(80, 50, 250, 120);outtextxy(130, 80, L"开始游戏");rectangle(80, 150, 250, 220);outtextxy(130, 180, L"难度设置");outtextxy(30, 280, L"游戏说明:");outtextxy(105, 280, L"点击笑脸可以重新开始,开始");outtextxy(105, 305, L"游戏默认中级难度,可以选择");outtextxy(105, 330, L"难度直接开始游戏,点击返回");outtextxy(105, 355, L"回到界面");whitchtouth();}cleardevice();while (choice){settextcolor(BLACK);rectangle(80, 50, 250, 120);outtextxy(130, 80, L"初级");rectangle(80, 150, 250, 220);outtextxy(130, 180, L"中级");rectangle(80, 250, 250, 320);outtextxy(130, 280, L"高级");whitchtouch2();}initgraph(grawidth, grahight);setbkcolor(RGB(189, 189, 189));cleardevice();//开始numbombss = bomb % 10;numbombs = bomb / 10;updategame();printfmaps();
}

四.注意事项:

大家可以将我的代码运行玩一下(但是必须先截图,后保存在代码的根目录下面才可以运行,并且图片的名字要和我一样,因为我的代码加载图片使用的相对路径的名字就是我图片取得名字,如果不这样就加载不了图片,只有一片灰,还要就是要下载easyx!!!!!),这样可以帮助各位理解代码。up主用的是vs2019读者尽量用2019及以上的版本,以免导致有些函数无法运行。

要用代码图片位置和名字必须一样!!!!!!!!!!

五.心得体会:

这是up主第一次写的文章,且up主只是一个大一的学生,代码写的不是很好,并且这次代码是要交的作业,所以有点赶工,代码的可能有些地方没有优化,希望大家可以理解并且提出意见。有不会可以私信问!!!!!

爱你

 

这篇关于c/c++语言用Easyx写出扫雷(保姆级教学),有源代码!!!!!!!!的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/842234

相关文章

C语言中联合体union的使用

本文编辑整理自: http://bbs.chinaunix.net/forum.php?mod=viewthread&tid=179471 一、前言 “联合体”(union)与“结构体”(struct)有一些相似之处。但两者有本质上的不同。在结构体中,各成员有各自的内存空间, 一个结构变量的总长度是各成员长度之和。而在“联合”中,各成员共享一段内存空间, 一个联合变量

关于C++中的虚拟继承的一些总结(虚拟继承,覆盖,派生,隐藏)

1.为什么要引入虚拟继承 虚拟继承是多重继承中特有的概念。虚拟基类是为解决多重继承而出现的。如:类D继承自类B1、B2,而类B1、B2都继承自类A,因此在类D中两次出现类A中的变量和函数。为了节省内存空间,可以将B1、B2对A的继承定义为虚拟继承,而A就成了虚拟基类。实现的代码如下: class A class B1:public virtual A; class B2:pu

C++对象布局及多态实现探索之内存布局(整理的很多链接)

本文通过观察对象的内存布局,跟踪函数调用的汇编代码。分析了C++对象内存的布局情况,虚函数的执行方式,以及虚继承,等等 文章链接:http://dev.yesky.com/254/2191254.shtml      论C/C++函数间动态内存的传递 (2005-07-30)   当你涉及到C/C++的核心编程的时候,你会无止境地与内存管理打交道。 文章链接:http://dev.yesky

C++的模板(八):子系统

平常所见的大部分模板代码,模板所传的参数类型,到了模板里面,或实例化为对象,或嵌入模板内部结构中,或在模板内又派生了子类。不管怎样,最终他们在模板内,直接或间接,都实例化成对象了。 但这不是唯一的用法。试想一下。如果在模板内限制调用参数类型的构造函数会发生什么?参数类的对象在模板内无法构造。他们只能从模板的成员函数传入。模板不保存这些对象或者只保存他们的指针。因为构造函数被分离,这些指针在模板外

C++工程编译链接错误汇总VisualStudio

目录 一些小的知识点 make工具 可以使用windows下的事件查看器崩溃的地方 dumpbin工具查看dll是32位还是64位的 _MSC_VER .cc 和.cpp 【VC++目录中的包含目录】 vs 【C/C++常规中的附加包含目录】——头文件所在目录如何怎么添加,添加了以后搜索头文件就会到这些个路径下搜索了 include<> 和 include"" WinMain 和

C/C++的编译和链接过程

目录 从源文件生成可执行文件(书中第2章) 1.Preprocessing预处理——预处理器cpp 2.Compilation编译——编译器cll ps:vs中优化选项设置 3.Assembly汇编——汇编器as ps:vs中汇编输出文件设置 4.Linking链接——链接器ld 符号 模块,库 链接过程——链接器 链接过程 1.简单链接的例子 2.链接过程 3.地址和

C++必修:模版的入门到实践

✨✨ 欢迎大家来到贝蒂大讲堂✨✨ 🎈🎈养成好习惯,先赞后看哦~🎈🎈 所属专栏:C++学习 贝蒂的主页:Betty’s blog 1. 泛型编程 首先让我们来思考一个问题,如何实现一个交换函数? void swap(int& x, int& y){int tmp = x;x = y;y = tmp;} 相信大家很快就能写出上面这段代码,但是如果要求这个交换函数支持字符型

大语言模型(LLMs)能够进行推理和规划吗?

大语言模型(LLMs),基本上是经过强化训练的 n-gram 模型,它们在网络规模的语言语料库(实际上,可以说是我们文明的知识库)上进行了训练,展现出了一种超乎预期的语言行为,引发了我们的广泛关注。从训练和操作的角度来看,LLMs 可以被认为是一种巨大的、非真实的记忆库,相当于为我们所有人提供了一个外部的系统 1(见图 1)。然而,它们表面上的多功能性让许多研究者好奇,这些模型是否也能在通常需要系

C++入门01

1、.h和.cpp 源文件 (.cpp)源文件是C++程序的实际实现代码文件,其中包含了具体的函数和类的定义、实现以及其他相关的代码。主要特点如下:实现代码: 源文件中包含了函数、类的具体实现代码,用于实现程序的功能。编译单元: 源文件通常是一个编译单元,即单独编译的基本单位。每个源文件都会经过编译器的处理,生成对应的目标文件。包含头文件: 源文件可以通过#include指令引入头文件,以使

人工和AI大语言模型成本对比 ai语音模型

这里既有AI,又有生活大道理,无数渺小的思考填满了一生。 上一专题搭建了一套GMM-HMM系统,来识别连续0123456789的英文语音。 但若不是仅针对数字,而是所有普通词汇,可能达到十几万个词,解码过程将非常复杂,识别结果组合太多,识别结果不会理想。因此只有声学模型是完全不够的,需要引入语言模型来约束识别结果。让“今天天气很好”的概率高于“今天天汽很好”的概率,得到声学模型概率高,又符合表达