图形库实战丨C语言扫雷小游戏(超2w字,附图片素材)

目录

效果展示

游玩链接(无需安装图形库及VS)

开发环境及准备

1.VS2022版本

2.图形库

游戏初始化

1.头文件

2.创建窗口

3.主函数框架

开始界面函数

1.初始化

1-1.设置背景颜色及字体

1-2.处理背景音乐及图片素材 

1-3.处理背景图位置

2.选择模式 

2-1.获取鼠标信息

2-2.处理颜色变化

2-3.判断鼠标按下的键

普通模式

1.随机生成地雷

1-1.清空map数组,并播随机数种子。

1-2.随机布雷

2.确定数字

3.判断输赢

画图 

递归函数 

困难模式

生成日志 

1.获取时间

2.输出内容

完整源代码 

回顾编程过程


源代码三连博主+私信回复“扫雷”领取

效果展示

游玩链接(无需安装图形库及VS)

怎么样?还不错吧,快去链接处下载吧!

EXE链接:下载点我

开发环境及准备

1.VS2022版本

其他版本也可以,别太老就行。

2.图形库

本代码用到图形库,需要安装。

图形库简介:EasyX 是EasyX Graphics Library 是针对 Visual C++ 的免费绘图库,支持 VC6.0 ~VC2022,简单易用,学习成本极低,应用领域广泛。

安装网址:EasyX Graphics Library for C++

游戏初始化

1.头文件

在游戏过程中,需要用到很多头文件,包括但不仅限于:时间函数,图形库,……

#include <iostream>//C++头文件
#include <time.h>//时间函数
#include <stdio.h>//标准输出输入库
#include <graphics.h> //图形库 
#include <mmsystem.h>//windows SDK 播放函数
#include <fstream>  //文件库
#include <windows.h>//windows api
#include <string>

2.创建窗口

因为窗口大小是以像素计数的,我们得先提前设定好格子的长和宽像素个数,我们用50就够了。

而扫雷一般是有10x10一百个格子的所以我们定义N为每行格子数,M为每格像素边长。

#define N 10  //格子数
#define M 50  //一个格子的像素

那么窗口的边长就是:每格像素长×格子数=N×M。

initgraph(N * M, N * M);//初始化绘图窗口宽500高500像素

3.主函数框架

我们先把主函数写好,再去实现相应的功能。

根据扫雷的不同难度,游戏划分为“15雷模式”和“35雷模式”,增加了挑战性趣味性

注意:writeLogMsg是生成日志的函数,当初是方便我调试的,但对游戏体验没有影响。

int main() 
{
	writeLogMsg("===天天扫雷=开始执行===");
	writeLogMsg("===开始界面=开始执行===");
	//initgraph(N * M, N * M,EW_SHOWCONSOLE);//, EW_SHOWCONSOLE初始化绘图窗口宽500高500像素
	initgraph(N * M, N * M);//初始化绘图窗口宽500高500像素
	

	//测试日志
	//int log[4] = {0,1,2,3};
	//writeLog(log, 9);
	writeLogMsg("===开始界面=开始执行===");
	StartWindow();//调用开始界面函数。
	writeLogMsg("===开始界面=结束执行===");
	//1.设置开始页面:背景透明、字体、背景音乐、背景图片,2.加载待使用的图片列表。3.判定鼠标位置和点击事件确定,用户选择的是15雷模式还是35雷模式
	if (gamemodel == 0) {
		normalModel();//15雷模式
	}
	else {
		BTmodel();//35雷模式
	}
	closegraph();
	
	writeLogMsg("===天天扫雷=结束执行===");
}

开始界面函数

1.初始化

1-1.设置背景颜色及字体

因为我们有图片,所有不需要有背景颜色,即把背景颜色设置为透明色。

setbkmode(TRANSPARENT); //设置背景 透明风格

字体推荐楷体,当然你也可以自行调整,比如“宋体”“仿宋”……

settextstyle(40, 18, L"楷体"); //设置开始界面字体大小 L设置字符集

1-2.处理背景音乐及图片素材 

音乐为天空之城,当然你也可以自己修改。

mciSendString(L"open ./天空之城.mp3 alias bgm", 0, 0, 0); //L为设置字符集,./表示当前文件夹
mciSendString(L"play bgm repeat", 0, 0, 0);//重复播放bgm

图片素材名称不要打错了,加载图片的函数用法如下。

//加载图片
/* 
从图片文件获取图像(bmp / gif / jpg / png / tif / emf / wmf / ico)
void loadimage(
	IMAGE * pDstImg,			// 保存图像的 IMAGE 对象指针
	LPCTSTR pImgFile,		// 图片文件名
	int nWidth = 0,			// 图片的拉伸宽度
	int nHeight = 0,		// 图片的拉伸高度
	bool bResize = false	// 是否调整 IMAGE 的大小以适应图片
);
*/

 加载:

loadimage(&image[0], L"./image/blank.jpg", M, M);
loadimage(&image[1], L"./image/1.jpg", M, M);
loadimage(&image[2], L"./image/2.jpg", M, M);
loadimage(&image[3], L"./image/3.jpg", M, M);
loadimage(&image[4], L"./image/4.jpg", M, M);
loadimage(&image[5], L"./image/5.jpg", M, M);
loadimage(&image[6], L"./image/6.jpg", M, M);
loadimage(&image[7], L"./image/7.jpg", M, M);
loadimage(&image[8], L"./image/8.jpg", M, M);
loadimage(&image[9], L"./image/lei.jpg", M, M);
loadimage(&image[10], L"./image/tag.jpg", M, M);
loadimage(&image[11], L"./image/start.jpg", N * M, N * M);
loadimage(&image[12], L"./image/0.jpg", M, M);

1-3.处理背景图位置

放一张图片到窗口的函数是putimage,用法及参数如下:

/*
// 绘制图像
void putimage(
    int dstX,				// 绘制位置的 x 坐标
    int dstY,				// 绘制位置的 y 坐标
    IMAGE *pSrcImg,			// 要绘制的 IMAGE 对象指针
    DWORD dwRop = SRCCOPY	// 三元光栅操作码
);
*/

 把开始界面的背景图放到窗口正中间,也就是(0,0)的位置。

putimage(0, 0, &image[11]);//将image[11]显示在屏幕上,坐标0,0

2.选择模式 

2-1.获取鼠标信息

这个函数我试了好多个,目前我的版本GetMouseMsg( )是可以的。

MOUSEMSG msg = { 0 };//鼠标事件信息
while (1) 
{
	msg = GetMouseMsg();//获取鼠标位置,存到msg里面
}

2-2.处理颜色变化

当鼠标放到某一个模式上时,我们让那个模式的字体颜色变红,更加真实美观。

//判断鼠标位置是否在15雷模式上,如果在设置颜色为红色
if ((msg.x > 180 && msg.x < 320) &&( msg.y >250 && msg.y < 290))
{
	settextcolor(RGB(255, 0, 0));		//设置字体颜色红色
	outtextxy(180, 250, L"15雷模式");//输出 15雷模式 在x180,y250//outtextxyS
}
//判断鼠标位置是否在35雷模式上,如果在设置颜色为红色
else if ((msg.x > 180 && msg.x < 320) &&( msg.y >330 && msg.y < 370))
{
	settextcolor(RGB(255, 0, 0));		//设置字体颜色红色
	outtextxy(180, 330, L"35雷模式");//输出 35雷模式 在x180,y330
}
//判断鼠标位置是否在退出上,如果在设置颜色为红色
else if (msg.x > 180 && msg.x < 320 && msg.y >410 && msg.y < 450)
{
	settextcolor(RGB(255, 0, 0));		//设置字体颜色红色
	outtextxy(180, 410, L"退出");//输出 退出 在x180,y410
}
//判断鼠标位置是否在背景部分,如果在设置颜色为黑色
else
{
	settextcolor(RGB(0, 0, 0));		//设置字体颜色为黑色
	outtextxy(180, 250, L"15雷模式");
	outtextxy(180, 330, L"35雷模式");
	outtextxy(180, 410, L"退出");
}

2-3.判断鼠标按下的键

根据不同的坐标,执行不同的模式或者退出程序。

其中判断是否按下左键的函数是WM_LBUTTONDOWN,按下返回真,否则返回假。

switch (msg.uMsg)
{
    case WM_LBUTTONDOWN://当点击鼠标左键后,判定鼠标坐标位置。
	//如果以下坐标区域则设置为正常模式0
	if (msg.x > 180 && msg.x < 320 && msg.y >250 && msg.y < 290) {
		gamemodel = 0;//将游戏模式设为0(15雷模式)
		return;
	}//如果以下坐标区域则设置为风控模式1
	else if (msg.x > 180 && msg.x < 320 && msg.y >330 && msg.y < 370) {
		gamemodel = 1;//将游戏模式设为1(35雷模式)
		return;
	}//如果以下坐标区域则退出游戏
	else if (msg.x > 180 && msg.x < 320 && msg.y >410 && msg.y < 450) {
		exit(0);//退出游戏(终止)
	}
}

普通模式

1.随机生成地雷

1-1.清空map数组,并播随机数种子。

srand((unsigned)time(NULL));//播种随机数种子
for (int i = 0; i < N + 2; i++) 
{
	for (int j = 0; j < N + 2; j++)
	{
		map[i][j] = 0;//把该数组的位置归0
	}
}	

1-2.随机布雷

while (flag < 15)//控制总雷数不超过15个
{
	x = rand() % 10 + 1;//随机生成在第几行(1-10行)
	y = rand() % 10 + 1;//随机生成在第几列(1-10列)
	//随机方格坐标
	string msgXY = "may[" + to_string(x) + "][" + to_string(y )+ "]"+"当前数值value is "+to_string(map[x][y]);

	if (map[x][y] != -1) //随机获取坐标为map[x][y]的值,判定是否不等于-1(-1表示雷),如果等于-1则表示该位置已经是雷。
	{
		map[x][y] = -1;//如果不等于-1,则赋值该位置为-1(布雷)
		flag++;//总雷数增加1个
		writeLogMsg("may[" + to_string(x) + "][" + to_string(y) + "]" + "当前数值value is " + to_string(map[x][y]) + "埋雷成功!!!累计埋雷个数===>" + to_string(flag));
	}
}

2.确定数字

遍历整个数组,看八个方向,有一个雷就+1。

for (int i = 1; i <= N; i++) //扫描数组10X10显示部分
{
	//writeLogMsg("===扫描第【"+to_string(i)+"】行开始执行===");
	for (int j = 1; j <= N; j++)
	{
		squ_num++;
		if (map[i][j] != -1)//如果这个数组的位置不是-1即表示不是地雷
		{
			//writeLogMsg("==方格编号【"+ to_string(squ_num) +"】=扫描第map【" + to_string(i) + "】行第【" + to_string(j) + "】不是雷!!!开始扫描周围雷总数。当前map【】【】 valuse is==="+to_string(map[i][j]));
			for (int m = i - 1; m <= i + 1; m++) //扫描包含该数字周围的九个格子
			{
				for (int n = j - 1; n <= j + 1; n++)
				{
					if (map[m][n] == -1)
					{
						map[i][j]++;//确定除了雷每个格子中间数字,(也就是周围八个格子的总雷数)									
					}						
				}	
			}
			//writeLogMsg("==方格编号【" + to_string(squ_num) + "】=扫描第map【" + to_string(i) + "】行第【" + to_string(j) + "】不是雷,扫描周围雷总数共计map[i][j]值为==>" + to_string(map[i][j]) + "个");				
		}
        else
        {
			//writeLogMsg("==方格编号【" + to_string(squ_num) + "】=扫描第map【" + to_string(i) + "】行第【" + to_string(j) + "】是雷,不扫锚周围!map[i][j]值为==>" + to_string(map[i][j]) );
		}
	}
	//writeLogMsg("===扫描第【" + to_string(i) + "】行结束执行===");
}

3.判断输赢

这里用到了一个函数DrawGraph( )是用来画图显示的,下面会讲。

while (1)
{
	whileCount++;
	writeLogMsg("===根据map[i][j]存放数值设置对应图片开始执行===");
	DrawGraph();//更新雷的图片,数字对应的图片
	writeLogMsg("===根据map[i][j]存放数值设置对应图片结束执行===");
	type = MouseClick();
	if (type == -1) //判断用户是否点到雷了
	{
		DrawGraph();
		if (MessageBox(hWnd, L"按下确定重玩", L"很遗憾失败!", MB_ICONINFORMATION |MB_OK) == IDOK) break;//输出提示框
	}
	if (win == 0)//判断用户是否赢了,胜利条件为除了雷的所有方块点完即可
	{
		DrawGraph();
		if (MessageBox(hWnd, L"按下确定重玩", L"恭喜成功!", MB_ICONINFORMATION |MB_OK) == IDOK) break;//输出提示框
	}
	writeLogMsg("===type = MouseClick()当前type值===》" + to_string(type));
	writeLogMsg("===win当前win值===》" + to_string(win));
	writeLogMsg("===设置图片循环次数===>" + to_string(whileCount));
}

画图 

这个函数是程序的精髓,特别难理解,一定要多推敲推敲!

int count_num=0;//计数器方格数
for (int i = 1; i <= N; i++)
{
	for (int j = 1; j <= N; j++) {
		count_num++;
		//writeLogMsg("DrawGraph==>当前扫描第【"+ to_string(count_num) +"】map【" + to_string(i) + "】行第【" + to_string(j) + "】map[i][j]值为 ==> " + to_string(map[i][j]));
		switch (map[i][j])
		{
		case 9:putimage((i - 1) * M, (j - 1) * M, &image[9]); break;
		case 10:putimage((i - 1) * M, (j - 1) * M, &image[0]); break;
		case 11:putimage((i - 1) * M, (j - 1) * M, &image[1]); break;
		case 12:putimage((i - 1) * M, (j - 1) * M, &image[2]); break;
		case 13:putimage((i - 1) * M, (j - 1) * M, &image[3]); break;
		case 14:putimage((i - 1) * M, (j - 1) * M, &image[4]); break;
		case 15:putimage((i - 1) * M, (j - 1) * M, &image[5]); break;
		case 16:putimage((i - 1) * M, (j - 1) * M, &image[6]); break;
		case 17:putimage((i - 1) * M, (j - 1) * M, &image[7]); break;
		case 18:putimage((i - 1) * M, (j - 1) * M, &image[8]); break;
		case 29:putimage((i - 1) * M, (j - 1) * M, &image[10]); break;
		case 30:putimage((i - 1) * M, (j - 1) * M, &image[10]); break;
		case 31:putimage((i - 1) * M, (j - 1) * M, &image[10]); break;
		case 32:putimage((i - 1) * M, (j - 1) * M, &image[10]); break;
		case 33:putimage((i - 1) * M, (j - 1) * M, &image[10]); break;
		case 34:putimage((i - 1) * M, (j - 1) * M, &image[10]); break;
		case 35:putimage((i - 1) * M, (j - 1) * M, &image[10]); break;
		case 36:putimage((i - 1) * M, (j - 1) * M, &image[10]); break;
		case 37:putimage((i - 1) * M, (j - 1) * M, &image[10]); break;
		case 38:putimage((i - 1) * M, (j - 1) * M, &image[10]); break;
		default:putimage((i - 1) * M, (j - 1) * M, &image[12]); break;
		}
	}
}

递归函数 

通过不断地递归(调用自己),来实现点一大片的情况。

void loadingPlay(int x, int y) 
{
	map[x][y] += 10;
	win--;
	for (int i = x - 1; i <= x + 1; i++) {
		for (int j = y - 1; j <= y + 1; j++) {
			if (i <= 0 || i >= 11 || j <= 0 || j >= 11)  continue; //防止越界
			if (map[i][j] <= 8) {
				if (map[i][j] == 0) {
					loadingPlay(i, j);
				}
				else if (map[i][j] != -1) {
					map[i][j] += 10;
					win--;
				}
			}
		}
	}
}

困难模式

思路和普通模式一样,就不解析了,有注释。

{
	while (1)
	{
		cleardevice();//清屏
		win = N * N - 35;//设置胜利条件为把除了雷的所有方块点完即可
		int type = 0;
		HWND hWnd = GetHWnd();//这个函数用于获取绘图窗口句柄
		int x, y, flag = 0;
		srand((unsigned)time(NULL));//播种随机数种子
		//通过双重for循环把所有数组归零
		for (int i = 0; i < N + 2; i++) 
		{
			for (int j = 0; j < N + 2; j++) 
			{
				map[i][j] = 0;//把该数组的位置归0
			}
		}
		//布雷循环
		while (flag < 35)//控制总雷数不超过35个
		{
			x = rand() % 10 + 1;//随机生成在第几行
			y = rand() % 10 + 1;//随机生成在第几列
			if (map[x][y] != -1) //为了判断所生成的雷有没有重复
			{
				map[x][y] = -1;//将此数组设为-1(-1表示雷)
				flag++;//总雷数增加1个
			}
		}
		//布数字
		for (int i = 1; i <= N; i++) //扫描数组10X10显示部分
		{
			for (int j = 1; j <= N; j++)
			{
				if (map[i][j] != -1)//如果这个数组的位置不是-1(地雷)
				{
					for (int m = i - 1; m <= i + 1; m++) //扫描包含该数字周围的九个格子
					{
						for (int n = j - 1; n <= j + 1; n++)
						{
							if (map[m][n] == -1)
							{
								map[i][j]++;//确定除了雷每个格子中间数字,(也就是周围八个格子的总雷数)
							}
						}
					}
				}
			}
		}
		//判断输赢
		while (1)
		{
			DrawGraph();
			type = MouseClick();
			if (type == -1) //判断用户是否点到雷了
			{
				DrawGraph();
				if (MessageBox(hWnd, L"按下确定重玩", L"很遗憾失败", MB_ICONINFORMATION|MB_OK) == IDOK) break;//输出提示框
			}
			if (win == 0)//判断用户是否赢了 
			{
				DrawGraph();
				if (MessageBox(hWnd, L"按下确定重玩", L"恭喜成功", MB_ICONINFORMATION| MB_OK) == IDOK) break;//输出提示框
			}
		}
	}
}

生成日志 

1.获取时间

用到函数SYSTEMTIME,可以调取年月日时秒分。

2.输出内容

你想看到的后台调试信息都可以放进去。

for (int i = 0; i < count; i++) 
{
	cout << "log.txt  【Write】===>第" << i <<"行" << endl;
	myFile << "【" << sys.wYear <<"-"<< sys.wMonth << "-"<< sys.wDay << "    "<< sys.wHour << ":"<< sys.wMinute << ":"<< sys.wSecond << "."<< sys.wMilliseconds << "星期" << sys.wDayOfWeek << "】" << "\t" << squ[0] << "\t" << squ[1] << "\t" << squ[2] << "\t" << squ[3] << endl;
}

完整源代码 

#include<iostream>//C++头文件
#include<time.h>//时间函数
#include<stdio.h>//标准输出输入库
#include<graphics.h>			//图形库   EasyX 是EasyX Graphics Library 是针对 Visual C++ 的免费绘图库,支持 VC6.0 ~VC2022,简单易用,学习成本极低,应用领域广泛
#include<mmsystem.h>//windows SDK 播放函数

#include <fstream>  //文件库
#include <windows.h>//windows api
#include<string>//

#pragma comment(lib,"winmm.lib")	
#define N 10  //格子数
#define M 50  //一个格子的像素
using namespace std;//命名空间

IMAGE image[13];		//存放图片数量为13张
int map[N + 2][N + 2];	//定义整形12行12列二维数组
int gamemodel;//定义游戏模式
int win = N * N - 15;
void StartWindow();		//开始界面
void normalModel();     //15雷模式
void BTmodel();			//35雷模式
void DrawGraph();		//画扫雷地图
int MouseClick();	    //鼠标点击事件
void loadingPlay(int x, int y);	//定义loadingPlay函数,为了运用递归实现点击一大片

//void writeLog(int a [],int b);
void writeLogMsg(string msgStr);
int map_num;//map格子编号
int SquareInfo[4];//定义单个方格信息整型数组 用来存在单方格的基本信息。包括方格编号,方格数值,方格x,y坐标值。
int squ_num;//方格编号 从左往右,从第一行到最后一行计数编号。
int squ_value;//方格存放数值
int index_x;//定义格子坐标 X表示横,Y表示纵
int index_y;
int Square[100][4];//存放100个方格基本信息


int  main() {
	writeLogMsg("===天天扫雷=开始执行===");
	writeLogMsg("===开始界面=开始执行===");
	//initgraph(N * M, N * M,EW_SHOWCONSOLE);//, EW_SHOWCONSOLE初始化绘图窗口宽500高500像素
	initgraph(N * M, N * M);//初始化绘图窗口宽500高500像素
	

	//测试日志
	//int log[4] = {0,1,2,3};
	//writeLog(log, 9);
	writeLogMsg("===开始界面=开始执行===");
	StartWindow();//调用开始界面函数。
	writeLogMsg("===开始界面=结束执行===");
	//1.设置开始页面:背景透明、字体、背景音乐、背景图片,2.加载待使用的图片列表。3.判定鼠标位置和点击事件确定,用户选择的是15雷模式还是35雷模式
	if (gamemodel == 0) {
		normalModel();//15雷模式
	}
	else {
		BTmodel();//35雷模式
	}
	closegraph();
	
	writeLogMsg("===天天扫雷=结束执行===");
}
void StartWindow() {

	writeLogMsg("===设置界面背景、字体=开始执行===");
	setbkmode(TRANSPARENT);		 //设置背景 透明风格
	settextstyle(40, 18, L"楷体");//设置开始界面字体大小 L设置字符集
	//初始化页面
	//播放音乐
	writeLogMsg("===设置界面背景、字体=结束执行===");
	writeLogMsg("===设置播放背景音乐=开始执行===");
	mciSendString(L"open ./天空之城.mp3 alias bgm", 0, 0, 0); //L为设置字符集,./表示当前文件夹
	mciSendString(L"play bgm repeat", 0, 0, 0);//重复播放bgm
	writeLogMsg("===设置播放背景音乐=结束执行===");
	//加载图片
	/* 
	从图片文件获取图像(bmp / gif / jpg / png / tif / emf / wmf / ico)
	void loadimage(
		IMAGE * pDstImg,			// 保存图像的 IMAGE 对象指针
		LPCTSTR pImgFile,		// 图片文件名
		int nWidth = 0,			// 图片的拉伸宽度
		int nHeight = 0,		// 图片的拉伸高度
		bool bResize = false	// 是否调整 IMAGE 的大小以适应图片
	);
	*/
	writeLogMsg("===加载图片资源=开始执行===");
	loadimage(&image[0], L"./image/blank.jpg", M, M);
	loadimage(&image[1], L"./image/1.jpg", M, M);
	loadimage(&image[2], L"./image/2.jpg", M, M);
	loadimage(&image[3], L"./image/3.jpg", M, M);
	loadimage(&image[4], L"./image/4.jpg", M, M);
	loadimage(&image[5], L"./image/5.jpg", M, M);
	loadimage(&image[6], L"./image/6.jpg", M, M);
	loadimage(&image[7], L"./image/7.jpg", M, M);
	loadimage(&image[8], L"./image/8.jpg", M, M);
	loadimage(&image[9], L"./image/lei.jpg", M, M);
	loadimage(&image[10], L"./image/tag.jpg", M, M);
	loadimage(&image[11], L"./image/start.jpg", N * M, N * M);
	loadimage(&image[12], L"./image/0.jpg", M, M);
	writeLogMsg("===加载图片资源=开始执行===");
	/*
	// 绘制图像
void putimage(
	int dstX,				// 绘制位置的 x 坐标
	int dstY,				// 绘制位置的 y 坐标
	IMAGE *pSrcImg,			// 要绘制的 IMAGE 对象指针
	DWORD dwRop = SRCCOPY	// 三元光栅操作码
);

	*/
	writeLogMsg("===设置开始界面显示图片=开始执行===");
	putimage(0, 0, &image[11]);//将image[11]显示在屏幕上,坐标0,0
	writeLogMsg("===设置开始界面显示图片=结束执行===");

	writeLogMsg("===获取鼠标事件信息、设置15、35雷模式字体,坐标区域=开始执行===");
	MOUSEMSG msg = { 0 };//鼠标事件信息
	while (1) 
	{
		msg = GetMouseMsg();//获取鼠标位置,存到msg里面
		//判断鼠标位置是否在15雷模式上,如果在设置颜色为红色
		if ((msg.x > 180 && msg.x < 320) &&( msg.y >250 && msg.y < 290))
		{
			settextcolor(RGB(255, 0, 0));		//设置字体颜色红色
			outtextxy(180, 250, L"15雷模式");//输出 15雷模式 在x180,y250//outtextxyS
		}
		//判断鼠标位置是否在35雷模式上,如果在设置颜色为红色
		else if ((msg.x > 180 && msg.x < 320) &&( msg.y >330 && msg.y < 370))
		{
			settextcolor(RGB(255, 0, 0));		//设置字体颜色红色
			outtextxy(180, 330, L"35雷模式");//输出 35雷模式 在x180,y330
		}
		//判断鼠标位置是否在退出上,如果在设置颜色为红色
		else if (msg.x > 180 && msg.x < 320 && msg.y >410 && msg.y < 450)
		{
			settextcolor(RGB(255, 0, 0));		//设置字体颜色红色
			outtextxy(180, 410, L"退出");//输出 退出 在x180,y410
		}
		//判断鼠标位置是否在背景部分,如果在设置颜色为黑色
		else
		{
			settextcolor(RGB(0, 0, 0));		//设置字体颜色为黑色
			outtextxy(180, 250, L"15雷模式");
			outtextxy(180, 330, L"35雷模式");
			outtextxy(180, 410, L"退出");
		}
		switch (msg.uMsg)
		{
			case WM_LBUTTONDOWN://当点击鼠标左键后,判定鼠标坐标位置。
			//如果以下坐标区域则设置为正常模式0
			if (msg.x > 180 && msg.x < 320 && msg.y >250 && msg.y < 290) {
				gamemodel = 0;//将游戏模式设为0(15雷模式)
				return;
			}//如果以下坐标区域则设置为风控模式1
			else if (msg.x > 180 && msg.x < 320 && msg.y >330 && msg.y < 370) {
				gamemodel = 1;//将游戏模式设为1(35雷模式)
				return;
			}//如果以下坐标区域则退出游戏
			else if (msg.x > 180 && msg.x < 320 && msg.y >410 && msg.y < 450) {
				exit(0);//退出游戏(终止)
			}
		}
	}
	writeLogMsg("===获取鼠标事件信息、设置15、35雷模式字体,坐标区域=结束执行===");
}
void normalModel()//15雷模式(普通模式)
{

	writeLogMsg("===15雷模式=开始执行===");
	while (1)
	{
		cleardevice();//清屏
		win = N * N - 15;//设置胜利条件为把除了雷的所有方块点完即可
		int type = 0;
		HWND hWnd = GetHWnd();//GetHWnd()这个函数用于获取绘图窗口句柄
		int x, y, flag = 0;
		srand((unsigned)time(NULL));//播种随机数种子
		writeLogMsg("===初始化map[][]每个坐标的值开始执行===");
		//通过双重for循环把所有数组归零
		for (int i = 0; i < N + 2; i++) 
		{
			for (int j = 0; j < N + 2; j++)
			{
				map[i][j] = 0;//把该数组的位置归0
			}
			
		}
		
		writeLogMsg("===初始化map[][]每个坐标的值结束执行===");
		//随机布雷
		writeLogMsg("===随机布雷开始执行===");
		while (flag < 15)//控制总雷数不超过15个
		{
			x = rand() % 10 + 1;//随机生成在第几行(1-10行)
			y = rand() % 10 + 1;//随机生成在第几列(1-10列)

			//随机方格坐标
			string msgXY = "may[" + to_string(x) + "][" + to_string(y )+ "]"+"当前数值value is "+to_string(map[x][y]);
		
			if (map[x][y] != -1) //随机获取坐标为map[x][y]的值,判定是否不等于-1(-1表示雷),如果等于-1则表示该位置已经是雷。
			{
				map[x][y] = -1;//如果不等于-1,则赋值该位置为-1(布雷)
				
				flag++;//总雷数增加1个
				writeLogMsg("may[" + to_string(x) + "][" + to_string(y) + "]" + "当前数值value is " + to_string(map[x][y]) + "埋雷成功!!!累计埋雷个数===>" + to_string(flag));
				
			}
		

		}
		writeLogMsg("===随机布雷结束执行===");
		writeLogMsg("===计算每个方格周围雷数量开始执行===");
		//计算除了已布雷的格子之外,每个格子周围雷的数量并确定数字
		for (int i = 1; i <= N; i++) //扫描数组10X10显示部分
		{

			//writeLogMsg("===扫描第【"+to_string(i)+"】行开始执行===");
			for (int j = 1; j <= N; j++)
			{
				squ_num++;
				
				if (map[i][j] != -1)//如果这个数组的位置不是-1即表示不是地雷
				{
					
					//writeLogMsg("==方格编号【"+ to_string(squ_num) +"】=扫描第map【" + to_string(i) + "】行第【" + to_string(j) + "】不是雷!!!开始扫描周围雷总数。当前map【】【】 valuse is==="+to_string(map[i][j]));

					for (int m = i - 1; m <= i + 1; m++) //扫描包含该数字周围的九个格子
					{

						for (int n = j - 1; n <= j + 1; n++)
						{
							
							if (map[m][n] == -1)
							{
								map[i][j]++;//确定除了雷每个格子中间数字,(也就是周围八个格子的总雷数)
																	
							}
													
						}
						
					}
					//writeLogMsg("==方格编号【" + to_string(squ_num) + "】=扫描第map【" + to_string(i) + "】行第【" + to_string(j) + "】不是雷,扫描周围雷总数共计map[i][j]值为==>" + to_string(map[i][j]) + "个");
								
				}else{
					//writeLogMsg("==方格编号【" + to_string(squ_num) + "】=扫描第map【" + to_string(i) + "】行第【" + to_string(j) + "】是雷,不扫锚周围!map[i][j]值为==>" + to_string(map[i][j]) );
				}
				
			}
			//writeLogMsg("===扫描第【" + to_string(i) + "】行结束执行===");
		}
		writeLogMsg("===计算每个方格周围雷数量结束执行===");
		//判断输赢
		int whileCount = 0;
		
		while (1)
		{
			whileCount++;
			writeLogMsg("===根据map[i][j]存放数值设置对应图片开始执行===");
			DrawGraph();//更新雷的图片,数字对应的图片
			writeLogMsg("===根据map[i][j]存放数值设置对应图片结束执行===");
			
			type = MouseClick();
			
			
			if (type == -1) //判断用户是否点到雷了
			{
				DrawGraph();
				
				if (MessageBox(hWnd, L"按下确定重玩", L"很遗憾失败!", MB_ICONINFORMATION |MB_OK) == IDOK) break;//输出提示框
			}
			if (win == 0)//判断用户是否赢了,胜利条件为除了雷的所有方块点完即可
			{
				DrawGraph();
				if (MessageBox(hWnd, L"按下确定重玩", L"恭喜成功!", MB_ICONINFORMATION |MB_OK) == IDOK) break;//输出提示框
			}
			writeLogMsg("===type = MouseClick()当前type值===》" + to_string(type));
			writeLogMsg("===win当前win值===》" + to_string(win));
			writeLogMsg("===设置图片循环次数===>" + to_string(whileCount));
		}
	}
	writeLogMsg("===15雷模式=结束执行===");
}
void BTmodel() //35雷模式(疯狂模式)
{
	while (1)
	{
		cleardevice();//清屏
		win = N * N - 35;//设置胜利条件为把除了雷的所有方块点完即可
		int type = 0;
		HWND hWnd = GetHWnd();//这个函数用于获取绘图窗口句柄
		int x, y, flag = 0;
		srand((unsigned)time(NULL));//播种随机数种子
		//通过双重for循环把所有数组归零
		for (int i = 0; i < N + 2; i++) 
		{
			for (int j = 0; j < N + 2; j++) 
			{
				map[i][j] = 0;//把该数组的位置归0
			}
		}
		//布雷循环
		while (flag < 35)//控制总雷数不超过35个
		{
			x = rand() % 10 + 1;//随机生成在第几行
			y = rand() % 10 + 1;//随机生成在第几列
			if (map[x][y] != -1) //为了判断所生成的雷有没有重复
			{
				map[x][y] = -1;//将此数组设为-1(-1表示雷)
				flag++;//总雷数增加1个
			}
		}
		//布数字
		for (int i = 1; i <= N; i++) //扫描数组10X10显示部分
		{
			for (int j = 1; j <= N; j++)
			{
				if (map[i][j] != -1)//如果这个数组的位置不是-1(地雷)
				{
					for (int m = i - 1; m <= i + 1; m++) //扫描包含该数字周围的九个格子
					{
						for (int n = j - 1; n <= j + 1; n++)
						{
							if (map[m][n] == -1)
							{
								map[i][j]++;//确定除了雷每个格子中间数字,(也就是周围八个格子的总雷数)
							}
						}
					}
				}
			}
		}
		//判断输赢
		while (1)
		{
			DrawGraph();
			type = MouseClick();
			if (type == -1) //判断用户是否点到雷了
			{
				DrawGraph();
				if (MessageBox(hWnd, L"按下确定重玩", L"很遗憾失败", MB_ICONINFORMATION|MB_OK) == IDOK) break;//输出提示框
			}
			if (win == 0)//判断用户是否赢了 
			{
				DrawGraph();
				if (MessageBox(hWnd, L"按下确定重玩", L"恭喜成功", MB_ICONINFORMATION| MB_OK) == IDOK) break;//输出提示框
			}
		}
	}
}
void DrawGraph()
{
	int count_num=0;//计数器方格数

	for (int i = 1; i <= N; i++)
	{
		for (int j = 1; j <= N; j++) {
			count_num++;
			//writeLogMsg("DrawGraph==>当前扫描第【"+ to_string(count_num) +"】map【" + to_string(i) + "】行第【" + to_string(j) + "】map[i][j]值为 ==> " + to_string(map[i][j]));
			switch (map[i][j])
			{

			case 9:putimage((i - 1) * M, (j - 1) * M, &image[9]); break;
			case 10:putimage((i - 1) * M, (j - 1) * M, &image[0]); break;
			case 11:putimage((i - 1) * M, (j - 1) * M, &image[1]); break;
			case 12:putimage((i - 1) * M, (j - 1) * M, &image[2]); break;
			case 13:putimage((i - 1) * M, (j - 1) * M, &image[3]); break;
			case 14:putimage((i - 1) * M, (j - 1) * M, &image[4]); break;
			case 15:putimage((i - 1) * M, (j - 1) * M, &image[5]); break;
			case 16:putimage((i - 1) * M, (j - 1) * M, &image[6]); break;
			case 17:putimage((i - 1) * M, (j - 1) * M, &image[7]); break;
			case 18:putimage((i - 1) * M, (j - 1) * M, &image[8]); break;
			case 29:putimage((i - 1) * M, (j - 1) * M, &image[10]); break;
			case 30:putimage((i - 1) * M, (j - 1) * M, &image[10]); break;
			case 31:putimage((i - 1) * M, (j - 1) * M, &image[10]); break;
			case 32:putimage((i - 1) * M, (j - 1) * M, &image[10]); break;
			case 33:putimage((i - 1) * M, (j - 1) * M, &image[10]); break;
			case 34:putimage((i - 1) * M, (j - 1) * M, &image[10]); break;
			case 35:putimage((i - 1) * M, (j - 1) * M, &image[10]); break;
			case 36:putimage((i - 1) * M, (j - 1) * M, &image[10]); break;
			case 37:putimage((i - 1) * M, (j - 1) * M, &image[10]); break;
			case 38:putimage((i - 1) * M, (j - 1) * M, &image[10]); break;
			default:putimage((i - 1) * M, (j - 1) * M, &image[12]); break;
			}
		}
	}
}
int MouseClick()
{
	

	MOUSEMSG msg = { 0 };
	int loadingPlayCout = 0;
	while (1) {
		
		msg = GetMouseMsg();
		
		writeLogMsg("===MouseClick循环while开始执行===msg.x==》【" +to_string( msg.x)+"】msg.y==》【"+ to_string(msg.y)+"】");
		switch (msg.uMsg)
		{
		case WM_LBUTTONDOWN:
			writeLogMsg("===msg.uMsg.WM_LBUTTONDOWN===正在点击左键");
			if (map[msg.x / M + 1][msg.y / M + 1] == 0) {
				writeLogMsg("===map【"+to_string( msg.x / M) +"】【"+ to_string(msg.y / M) +"】的值是===>"+to_string(map[msg.x / M][msg.x / M]));
				writeLogMsg("当前方格周围没有雷!!!");
				writeLogMsg("开始加载loadingPlay  没有雷更换为无雷的图片递归循环判断!");
				loadingPlay(msg.x / M + 1, msg.y / M + 1);
				loadingPlayCout++;
				writeLogMsg("当前loadingPlayCout的值得是===>" + to_string(loadingPlayCout));
				writeLogMsg("结束加载loadingPlay");
			}
			else if (map[msg.x / M + 1][msg.y / M + 1] <= 8) {
				writeLogMsg("当前方格周围有雷!!!");
				writeLogMsg("map[][]<=8开始执行");
				writeLogMsg("===map【" + to_string(msg.x / M) + "】【" + to_string(msg.y / M) + "】的值是===>" + to_string(map[msg.x / M][msg.x / M]));
				map[msg.x / M + 1][msg.y / M + 1] += 10;
				win--;
				writeLogMsg("当前win的值是==>"+to_string(win));
				writeLogMsg("map[][]<=8结束执行");
			}
			if (map[msg.x / M + 1][msg.y / M + 1] == 9) {
				writeLogMsg("map[][]等于9");
				return -1;
			}
			break;
		case WM_RBUTTONDOWN:
			writeLogMsg("===msg.uMsg.WM_LBUTTONDOWN===正在点击右键");
			if (map[msg.x / M + 1][msg.y / M + 1] <= 8) {
				writeLogMsg("map[][]<=8开始执行");
				map[msg.x / M + 1][msg.y / M + 1] += 30;
			}
			else if (map[msg.x / M + 1][msg.y / M + 1] >= 29) {
				writeLogMsg("map[][]>=29开始执行");
				map[msg.x / M + 1][msg.y / M + 1] -= 30;
			}
			break;
		}
		writeLogMsg("===MouseClick循环while结束执行===" );

		return 0;
	}
	
}
void loadingPlay(int x, int y) {
	
	
	
	map[x][y] += 10;
	win--;
	for (int i = x - 1; i <= x + 1; i++) {
		for (int j = y - 1; j <= y + 1; j++) {
			if (i <= 0 || i >= 11 || j <= 0 || j >= 11)  continue; //防止越界
			if (map[i][j] <= 8) {
				if (map[i][j] == 0) {
					loadingPlay(i, j);
				}
				else if (map[i][j] != -1) {
					map[i][j] += 10;
					win--;
				}
			}
		}
	}
	
}
 void writeLog(int squ[], int n){
	 //获取当前系统时间
	 SYSTEMTIME sys;
	 GetLocalTime(&sys);
	fstream myFile;
	myFile.open("log.txt", ios::out | ios::binary);
	if (!myFile) {
		cout << "log.txt can't open!" << endl;
		abort();
	}
	int count = n;
	myFile << "累计行数===>"<<count << endl;
	
	for (int i = 0; i < count; i++) {
		cout << "log.txt  【Write】===>第" << i <<"行" << endl;

		myFile << "【" << sys.wYear <<"-"<< sys.wMonth << "-"<< sys.wDay << "    "<< sys.wHour << ":"<< sys.wMinute << ":"<< sys.wSecond << "."<< sys.wMilliseconds << "星期" << sys.wDayOfWeek << "】" << "\t" << squ[0] << "\t" << squ[1] << "\t" << squ[2] << "\t" << squ[3] << endl;

		
	}
	myFile.close();
}

 void writeLogMsg(string msg) {
	 //获取当前系统时间
	 SYSTEMTIME sys;
	 GetLocalTime(&sys);
	 fstream myFile;
	 myFile.open("log.txt", ios::out | ios::app);
	 if (!myFile) {
		 cout << "log.txt can't open!" << endl;
		 abort();
	 }
	 
		 myFile << "【" << sys.wYear << "-" << sys.wMonth << "-" << sys.wDay << "    " << sys.wHour << ":" << sys.wMinute << ":" << sys.wSecond << "." << sys.wMilliseconds << "   星期" << sys.wDayOfWeek << "】" << "\t" << msg << endl;
	     myFile.close();


	 /*
 #include<fstream>
#include<iostream>
using namespace std;
int main()
{
	fstream f;
	//追加写入,在原来基础上加了ios::app 
	f.open("data.txt",ios::out|ios::app);
	//输入你想写入的内容 
	f<<"今天天气不错"<<endl;
	f.close();
	return 0;
}

	 */

 }

回顾编程过程

今天,我们一起探索了奇妙的扫雷游戏。运用到了很多知识点,有我们的老朋友递归,也有我们的新朋友日志。本篇文章制作不易,断更3周都在写这一篇。

本篇文章共20198字,真得不值得三连吗?

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/443296.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

代码随想录算法训练营第四天|24.两两交换链表中的节点、19.删除链表的倒数第N的节点、07.链表相交、142.环形链表II

代码随想录算法训练营第四天|24.两两交换链表中的节点、19.删除链表的倒数第N的节点、07.链表相交、142.环形链表II 24.两两交换链表中的节点 给你一个链表&#xff0c;两两交换其中相邻的节点&#xff0c;并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成…

【UE5】创建蓝图

创建GamePlay需要的相关蓝图 在内容游览器文件夹中创建文件夹&#xff0c;命名为Blueprints&#xff0c;用来放这个项目的所有蓝图(Blueprint) 在Blueprints文件夹下新建文件夹GamePlay,用存放GamePlay相关蓝图 在Blueprints文件夹下创建文件夹Character,存放角色相关蓝图 在Ga…

idea连接远程服务器

1. 双击shift&#xff0c;出现如下界面 2. 远程连接 原文来自这个up主的&#xff0c;点击蓝色字体就可以跳转啦&#xff01; 输入主机ip、用户名、密码&#xff0c;点击Test Connection验证&#xff0c;最后点击ok添加成功 有用的话记得给俺点个赞&#xff0c;靴靴~

学会与自己和解

最近半年来&#xff0c;在学习智能驾驶方面的技术&#xff0c;但有些文档和资料不方便分享&#xff0c;有一段时间没有写 写文档啦&#xff01;那就写一些技术之外的东西吧&#xff0c;最近也一直在学心理建设&#xff0c;学会与自己和解 行动 唯有自己先行动起来&#xff0c;…

vue组件之间通信方式汇总

方式1&#xff1a;props和$emit props和$emit仅仅限制在父子组件中使用 1.props&#xff1a;父组件向子组件传递数据 1.1 代码展示 <template><div><!-- 这是父组件 --><div>父组件中的基本数据类型age的值是:{{this.age}}</div><div>…

Web Servlet

目录 1 简介2 创建Servlet项目并成功发布运行3 新加Servlet步骤4 Servlet项目练习5 Servlet运行原理6 操作 HTTP Request头的方法(部分方法示例)7 操作 HTTP Response头的方法(部分方法示例)8 两种重定向(页面跳转)方法9 Cookie9.1 Cookie工作原理9.2 cookie构成9.3 Servlet 操…

LeetCode 1976.到达目的地的方案数:单源最短路的Dijkstra算法

【LetMeFly】1976.到达目的地的方案数&#xff1a;单源最短路的Dijkstra算法 力扣题目链接&#xff1a;https://leetcode.cn/problems/number-of-ways-to-arrive-at-destination/ 你在一个城市里&#xff0c;城市由 n 个路口组成&#xff0c;路口编号为 0 到 n - 1 &#xff…

202441读书笔记|《笠翁对韵》—— 金菡萏,玉芙蓉,酒晕微酡琼杏颊,香尘浅印玉莲双

202441读书笔记|《笠翁对韵》——金菡萏&#xff0c;玉芙蓉&#xff0c;酒晕微酡琼杏颊&#xff0c;香尘浅印玉莲双 《作家榜名著&#xff1a;笠翁对韵》作者李渔&#xff0c;霍俊明。是所有词句都有注音的一本书&#xff0c;轻松学不认识的字&#xff0c;非常朗朗上口的对偶词…

2024年如何批量下载知乎回答和知乎文章导出pdf?

如何批量下载知乎回答和知乎文章导出pdf&#xff1f;用scraper浏览器扩展 2024 年开发的第一个脚本神器 下载的所有回答html内容&#xff0c;文件名为回答日期加标题。 接着批量将html转换pdf&#xff0c;效果如图&#xff1a; 再将所有pdf合成一个pdf文件&#xff1a; 每个回…

VUE Element例子学习

参考:【前端】VueElement UI案例&#xff1a;通用后台管理系统-项目总结_vue elementui 管理系统-CSDN博客 之前参考的el-admin-web太复杂了&#xff0c;不是纯净的demo. 所以找了一圈资料&#xff0c;找到了这个博客&#xff0c;很合适&#xff0c;有例子的代码&#xff0c;…

vue中性能优化

目录 1. 编码优化 2. 源码优化 3. 打包优化 4. 利用 Vue Devtools 总结 Vue.js 作为一个强大的前端框架&#xff0c;提供了丰富的功能和工具来帮助开发者构建高效的 Web 应用。然而&#xff0c;在开发过程中&#xff0c;性能优化仍然是一个需要关注的问题。以下是对 Vue.j…

Solidity攻击合约:重入攻击与危害分析

以太坊智能合约开发中&#xff0c;重入攻击是一种常见的安全漏洞。这种攻击通常发生在合约的递归调用中&#xff0c;攻击者通过构造恶意交易&#xff0c;使得原本合约在执行过程中不断调用自身或其他合约&#xff0c;从而耗尽合约的Gas&#xff08;交易费用&#xff09;&#x…

数据结构与算法----复习Part 13 (单模式串匹配算法)

本系列是算法通关手册LeeCode的学习笔记 算法通关手册&#xff08;LeetCode&#xff09; | 算法通关手册&#xff08;LeetCode&#xff09; (itcharge.cn) 目录 一&#xff0c;朴素匹配算法&#xff08;Brute Force&#xff09; 二&#xff0c;Rabin Karp算法 三&#xff…

【NR 定位】3GPP NR Positioning 5G定位标准解读(十二)-Multi-RTT定位

前言 3GPP NR Positioning 5G定位标准&#xff1a;3GPP TS 38.305 V18 3GPP 标准网址&#xff1a;Directory Listing /ftp/ 【NR 定位】3GPP NR Positioning 5G定位标准解读&#xff08;一&#xff09;-CSDN博客 【NR 定位】3GPP NR Positioning 5G定位标准解读&#xff08;…

C语言字符串型常量

在C语言中&#xff0c;字符串型常量是由一系列字符组成的常量。字符串常量在C中以双引号&#xff08;"&#xff09;括起来&#xff0c;例如&#xff1a;“Hello, World!”。字符串常量在C中是不可变的&#xff0c;也就是说&#xff0c;一旦定义&#xff0c;就不能修改其内…

Python 一步一步教你用pyglet仿制鸿蒙系统里的时钟

目录 鸿蒙时钟 1. 绘制圆盘 2. 创建表类 3. 绘制刻度 4. 刻度数值 5. 添加指针 6. 转动指针 7. 联动时间 8. 时钟走动 鸿蒙时钟 本篇将用python pyglet库复刻华为手机鸿蒙系统闹钟程序的时钟&#xff0c;先在上图中抓取出时分秒针及刻度、表盘的颜色RGB值&#xff1a…

读书笔记之《理解和改变世界》:从信息知识智能的本质看AI

《理解和改变世界: 从信息到知识与智能》作者:是(法) 约瑟夫希发基思&#xff0c; 原作名: Understanding and Changing the World: From Information to Knowledge and Intelligence&#xff0c;2023年出版。 约瑟夫希发基思&#xff08;Joseph Sifakis&#xff09;&#xff…

力扣199. 二叉树的右视图(DFS,BFS)

Problem: 199. 二叉树的右视图 文章目录 题目描述思路解题方法复杂度Code 题目描述 思路 无论是DFS还是BFS我们都要思考到达二叉树的每一层&#xff08;或者每一层中的每一个节点&#xff09;时&#xff0c;我们都该如何按题目要求做出对应得处理!!!在本体中我们主要是&#x…

leetcode 热题 100_缺失的第一个正数

题解一&#xff1a; 正负模拟哈希&#xff1a;偏技巧类的题目&#xff0c;在无法使用额外空间的情况下&#xff0c;只能在原数组中做出类似哈希表的模拟。除去数值&#xff0c;我们还可以用正负来表示下标值的出现情况。首先&#xff0c;数组中存在正负数和0&#xff0c;而负数…

Ubuntu下使用DAPLink(OpenOCD)

目录 1. 下载OpenOCD源代码 2. 编译代码 2.1 运行bootstrap 2.2 安装关联库 2.3 运行./configure 2.4 运行make 2.5 运行sudo make install 3. 烧录程序 3.1 挂起MCU 3.2 写入镜像 3.3 校验镜像 通过OpenOCD实现&#xff0c;在Ubuntu18 64bit下验证。 1. 下载OpenOC…
最新文章