前言

EasyX 是针对 C++ 的图形库,可以帮助 C/C++ 初学者快速上手图形和游戏编程。

比如,可以基于 EasyX 图形库很快的用几何图形画一个房子,或者一辆移动的小车,可以编写俄罗斯方块、贪吃蛇、黑白棋等小游戏,可以练习图形学的各种算法,等等。

准备工作

🚪传送门:EasyX官网链接


EasyX下载

EasyX安装基础知识

  1. 进入EasyX官网后,点击下载即可。

图形化扫雷游戏_i++

  1. 下载完成后,找到该文件,点击打开。

图形化扫雷游戏_#include_02

  1. 点击下一步。

图形化扫雷游戏_#include_03

  1. 将前两个安装。

图形化扫雷游戏_数组_04

作者用的是VS2019,所以安装的是2019,如果您使用的是其他版本,软件会自己检测的。安装您所使用的版本即可。

🚪传送门:使用EasyX需要了解的基础函数


头文件的引用

EasyX为我们提供了一些库函数,我们只需要引用一下头文件就可以了。

#include <graphics.h>

图形化界面创建

图形化界面的创建需要用到库函数函数: initgraph

HWND initgraph(
		int width,
		int height,
		int flag = NULL
  );
	/*
	这个函数有三个参数
	第一个参数是界面水平方向的大小
	第二个参数是界面竖直方向的大小
	第三个参数是界面窗口样式,默认是NULL。
	*/

flag默认为NULL,也可以为以下几种:

图形化扫雷游戏_数组_05

示例:

以下代码片段创建一个尺寸为640*480的绘图窗口:

initgraph(640, 480);

以下代码片段创建一个尺寸为 640x480 的绘图窗口,同时显示控制台窗口:

initgraph(640, 480, EX_SHOWCONSOLE);

以下代码片段创建一个尺寸为 640x480 的绘图窗口,同时显示控制台窗口,并禁用关闭按钮:

initgraph(640, 480, EX_SHOWCONSOLE | EX_NOCLOSE);

图形化扫雷游戏_i++_06

当创建的文件后缀名是.c的时候,会发现程序报错。解决方法,将文件后缀名修改为.cpp。

图形化扫雷游戏_i++_07

但是当执行这段代码时,会出现界面一闪而过的情况,界面一闪而过是因为整个程序结束后,我们的界面也就结束了,所以我们对其进行修改,在此基础上增加一个死循环,让程序无法结束。

图形化扫雷游戏_#include_08

增加一个死循环让界面一直显示,并且增加一个函数closegraph,作用是关闭界面。

图形化扫雷游戏_i++_09

出现了界面后,我们要知道界面是有坐标的,因为需要根据坐标去放置图片。

图形化扫雷游戏_i++_10

图片加载与放置图片

引用<graphics.h>头文件后,我们就可以使用图片的数组或变量来存放图片。注意:图片存放位置最好和CPP文件在同一目录下。

图形化扫雷游戏_数组_11

图形化扫雷游戏_#include_12

loadimage()函数的功能是加载图片,也就是“告诉”程序我们有这个图片,我们可以理解为“此函数将图片的位置存入了变量中”,第一个参数为变量的地址,第二个变量是图片的地址,其中“./”表示与我们当前编辑的文件(cpp文件)同一目录下的文件路径(也可以省略,因为在同一路径下,可以直接写为"1.png"),如果这些基础知识还不知道的话推荐一篇博客:路径的表示与含义

putimage()函数的功能即为放置图片,第一个参数是图片开始位置的X坐标,第二个参数是Y坐标,第三个参数是变量的地址。

但是我们会发现loadimage()函数报错,这是因为该函数所需要的字符集与VS默认的字符集不同所导致的。修改字符集的方法如下:

图形化扫雷游戏_数组_13

图形化扫雷游戏_数组_14

修改完成后,再次执行,这次我把loadimageputimage函数的参数修改了。结果如图:

图形化扫雷游戏_#include_15

// 如果照片数量≥2张的话,可以采用数组方式。
IMAGE img[10]; // 有10张图片
// [ ]中的数字为数组大小,使用时下标从0开始。

鼠标操作

  1. MOUSEMSG结构体,以下是头文件中它的定义:

图形化扫雷游戏_数组_16

  1. MouseHit()函数,无参数,返回值为bool型,判断有无鼠标信息,如果有则返回true,没有则返回false,可以理解为有则返回1,否则返回0,鼠标信息包括的内容很多:

图形化扫雷游戏_数组_17

  1. GetMouseMsg()函数,无参数,返回类型为结构体类型。
  2. 先看一个代码片段。
while(1)
/*
为防止程序执行过快以致我们还没来得及操控鼠标
它就判断我们没有鼠标信息,定义一个死循环
*/
{
	if (MouseHit())//判断有没有鼠标消息,有的话进入循环
	{
		/*
		我们定义一个结构体变量来接收此函数的返回值
		也就是说msg会接收所有上图中的信息,如x,y,wheel等
		*/
		MOUSEMSG msg = GetMouseMsg();
		int r = msg.y / size;
		/*
		通过msg.y我们就可以使用前面得到的鼠标信息中鼠标所在位置的Y坐标
		msg.x同理
		*/
		int c = msg.x / size;
		switch (msg.uMsg)
		/*
		msg.uMSG代表我们获取的鼠标信息,上面有对鼠标信息的介绍
		各鼠标信息对应的值会在下面介绍
		*/
		{
		//看懂这里不懂了?往下看
		case WM_LBUTTONDOWN:
			break;
		case WM_RBUTTONDOWN:
			break;
		}
		break;//跳出循环
	}
}

这是头文件中的声明:

图形化扫雷游戏_#include_18

这些鼠标信息对应的都有整数值,msg.uMsg得到的也是这些信息对应的值,因此我们可以用switch语句对情况分类。

作个假设:

WM_LBUTTONDOWN代表左击,他的值假如为1,当我们左击时,msg.uMsg就是1。

提示框

int main()
{
	initgraph(400,400,SHOWCONSOLE);
	loadimage(&img, "1.png",100,100);
	putimage(100, 100,&img);
	MessageBox(GetHWnd(), "You win! Do you want to play again?", "notice", MB_OKCANCEL);
	while (1) 
	{
		;
	}
	closegraph();
	return 0;
}

执行后界面显示:

图形化扫雷游戏_#include_19


设计思路

这里需要补充一些知识。

  1. srand()函数和rand()函数的使用:srand()函数和rand()函数的使用
  2. 控制台扫雷游戏实现:扫雷游戏

扫雷游戏思路

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

图形化扫雷游戏_i++_20

自行截图或百度自行寻找。

  1. 可是这都是静态图片啊,我们怎么能实现鼠标点击后的转化呢,我们知道,在黑框框里我们用-1表示雷,数字表示该非雷位置九宫格内雷的个数,我们这里还在数组中存数字,根据数字的不同我们放置不同的图片,再利用鼠标操作得到鼠标操作的位置,转化为数组的下标,修改对应元素的值,就可以改变该位置的图片了。
  2. 接下来我们要计算每个位置(除开炸弹的位置,就是-1的位置)附近九宫格的雷数,这样方便后续点开方块后的贴图。现在你所设置的游戏区域大小的数字都是-1到8的数字,接下用一个循环把你所有的游戏区域的数字都加上20(原因后面代码会体现出来),这样游戏区域的数字就是19到28之间。

总结:

图形化扫雷游戏_#include_21

图片编号为(必须与下图中的图片名称一样,否则,就去修改代码中图片的相关名称):

图形化扫雷游戏_i++_22

扫雷游戏规则:

1. 左键点击未被打开的格子,可以打开格子
2. 右键点击未被打开的格子,可以标记格子
3. 被标记的格子不能被打开
4. 被标记的格子再右键时,可以解除标记
5. 如果打开后格子是空的,则自动打开周围的八个格子
6. 自动打开的格子也遵循规则4
7. 如果打开的格子里面是雷,则游戏失败
8. 如果所有非雷格子均被打开,则游戏获胜

完整代码

Mine.h

#pragma once

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <graphics.h>


extern int grahight;//实际画布高
extern int grawidth;//实际画布宽
#define allhight 100//总数组大小
#define allwidth 100//总数组大小
//中级17*17:415*340,初级10*10:275*200,高级20*20:475*400
extern int hight;//实际游戏区域大小
extern int width;//实际游戏区域大小
extern int times;//获取总时间
extern int time1, time2, time3;//记录时间的三位
extern int first;//判断第一次点击
extern int bomb;//炸弹数量
extern int runing;//是否结束游戏
extern int smiles;//笑脸图的变化
extern int ture;//判断是否开始游戏
extern int a;//不让它一直弹出胜利的框
extern int map[allhight + 2][allwidth + 2];//布局战场都出的两行和两个列用来辅助找出周围炸弹数
extern clock_t start_t, end_t;//开始实际时间,结束时间算时间差
extern IMAGE block[13];//1-8和空格和炸弹图片
extern IMAGE smile[4];//笑脸的各种状态
extern IMAGE numbomb[10];//时间图片
extern int numbombs;//炸弹第一位数
extern int numbombss;//炸弹第二位数
extern int win;//判断是否赢
extern int choice;//看用户是否选择

void printfmaps();

// 输出后台数据看炸弹在哪
void before();

// 打印地图
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();

Mine.cpp

#define _CRT_SECURE_NO_WARNINGS 1

#include "Mine.h"

int grahight = 415;//实际画布高
int grawidth = 340;//实际画布宽
int hight = 17;//实际游戏区域大小
int width = 17;//实际游戏区域大小
int times = 0;//获取总时间
int time1 = 0, time2 = 0, time3 = 0;//记录时间的三位
int first = 1;//判断第一次点击
int bomb = 30;//炸弹数量
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 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()
{
	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();
}

// 打印地图
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++;
					}
					else
						openzero(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 = 10;

		}
		else if (x >= 80 && x <= 250 && y >= 150 && y <= 220)
		{
			cleardevice();
			choice = 0;
			hight = 17;
			width = 17;
			grahight = 415;
			grawidth = 340;
			bomb = 30;
		}
		else if (x >= 80 && x <= 250 && y >= 250 && y <= 320)
		{
			cleardevice();
			choice = 0;
			hight = 20;
			width = 20;
			grahight = 475;
			grawidth = 400;
			bomb = 45;
		}
		break;
	}
}

Test.cpp

#define _CRT_SECURE_NO_WARNINGS 1

#include "Mine.h"


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;
}