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++ Primer Plus习题】13.4

大家好,这里是国中之林! ❥前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。有兴趣的可以点点进去看看← 问题: 解答: main.cpp #include <iostream>#include "port.h"int main() {Port p1;Port p2("Abc", "Bcc", 30);std::cout <<

C++包装器

包装器 在 C++ 中,“包装器”通常指的是一种设计模式或编程技巧,用于封装其他代码或对象,使其更易于使用、管理或扩展。包装器的概念在编程中非常普遍,可以用于函数、类、库等多个方面。下面是几个常见的 “包装器” 类型: 1. 函数包装器 函数包装器用于封装一个或多个函数,使其接口更统一或更便于调用。例如,std::function 是一个通用的函数包装器,它可以存储任意可调用对象(函数、函数

C++11第三弹:lambda表达式 | 新的类功能 | 模板的可变参数

🌈个人主页: 南桥几晴秋 🌈C++专栏: 南桥谈C++ 🌈C语言专栏: C语言学习系列 🌈Linux学习专栏: 南桥谈Linux 🌈数据结构学习专栏: 数据结构杂谈 🌈数据库学习专栏: 南桥谈MySQL 🌈Qt学习专栏: 南桥谈Qt 🌈菜鸡代码练习: 练习随想记录 🌈git学习: 南桥谈Git 🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈�

Centos7安装JDK1.8保姆版

工欲善其事,必先利其器。这句话同样适用于学习Java编程。在开始Java的学习旅程之前,我们必须首先配置好适合的开发环境。 通过事先准备好这些工具和配置,我们可以避免在学习过程中遇到因环境问题导致的代码异常或错误。一个稳定、高效的开发环境能够让我们更加专注于代码的学习和编写,提升学习效率,减少不必要的困扰和挫折感。因此,在学习Java之初,投入一些时间和精力来配置好开发环境是非常值得的。这将为我

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

06 C++Lambda表达式

lambda表达式的定义 没有显式模版形参的lambda表达式 [捕获] 前属性 (形参列表) 说明符 异常 后属性 尾随类型 约束 {函数体} 有显式模版形参的lambda表达式 [捕获] <模版形参> 模版约束 前属性 (形参列表) 说明符 异常 后属性 尾随类型 约束 {函数体} 含义 捕获:包含零个或者多个捕获符的逗号分隔列表 模板形参:用于泛型lambda提供个模板形参的名

科研绘图系列:R语言扩展物种堆积图(Extended Stacked Barplot)

介绍 R语言的扩展物种堆积图是一种数据可视化工具,它不仅展示了物种的堆积结果,还整合了不同样本分组之间的差异性分析结果。这种图形表示方法能够直观地比较不同物种在各个分组中的显著性差异,为研究者提供了一种有效的数据解读方式。 加载R包 knitr::opts_chunk$set(warning = F, message = F)library(tidyverse)library(phyl

透彻!驯服大型语言模型(LLMs)的五种方法,及具体方法选择思路

引言 随着时间的发展,大型语言模型不再停留在演示阶段而是逐步面向生产系统的应用,随着人们期望的不断增加,目标也发生了巨大的变化。在短短的几个月的时间里,人们对大模型的认识已经从对其zero-shot能力感到惊讶,转变为考虑改进模型质量、提高模型可用性。 「大语言模型(LLMs)其实就是利用高容量的模型架构(例如Transformer)对海量的、多种多样的数据分布进行建模得到,它包含了大量的先验

6.1.数据结构-c/c++堆详解下篇(堆排序,TopK问题)

上篇:6.1.数据结构-c/c++模拟实现堆上篇(向下,上调整算法,建堆,增删数据)-CSDN博客 本章重点 1.使用堆来完成堆排序 2.使用堆解决TopK问题 目录 一.堆排序 1.1 思路 1.2 代码 1.3 简单测试 二.TopK问题 2.1 思路(求最小): 2.2 C语言代码(手写堆) 2.3 C++代码(使用优先级队列 priority_queue)

SWAP作物生长模型安装教程、数据制备、敏感性分析、气候变化影响、R模型敏感性分析与贝叶斯优化、Fortran源代码分析、气候数据降尺度与变化影响分析

查看原文>>>全流程SWAP农业模型数据制备、敏感性分析及气候变化影响实践技术应用 SWAP模型是由荷兰瓦赫宁根大学开发的先进农作物模型,它综合考虑了土壤-水分-大气以及植被间的相互作用;是一种描述作物生长过程的一种机理性作物生长模型。它不但运用Richard方程,使其能够精确的模拟土壤中水分的运动,而且耦合了WOFOST作物模型使作物的生长描述更为科学。 本文让更多的科研人员和农业工作者