目录

怎么样?还不错吧,快去链接处下载吧!
EXE链接:下载点我
其他版本也可以,别太老就行。

本代码用到图形库,需要安装。
图形库简介:EasyX 是EasyX Graphics Library 是针对 Visual C++ 的免费绘图库,支持 VC6.0 ~VC2022,简单易用,学习成本极低,应用领域广泛。
安装网址:EasyX Graphics Library for C++
在游戏过程中,需要用到很多头文件,包括但不仅限于:时间函数,图形库,……
- #include
//C++头文件 - #include
//时间函数 - #include
//标准输出输入库 - #include
//图形库 - #include
//windows SDK 播放函数 - #include
//文件库 - #include
//windows api - #include
因为窗口大小是以像素计数的,我们得先提前设定好格子的长和宽像素个数,我们用50就够了。
而扫雷一般是有10x10一百个格子的所以我们定义N为每行格子数,M为每格像素边长。
- #define N 10 //格子数
- #define M 50 //一个格子的像素
那么窗口的边长就是:每格像素长×格子数=N×M。
initgraph(N * M, N * M);//初始化绘图窗口宽500高500像素
我们先把主函数写好,再去实现相应的功能。
根据扫雷的不同难度,游戏划分为“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("===天天扫雷=结束执行===");
- }
因为我们有图片,所有不需要有背景颜色,即把背景颜色设置为透明色。
setbkmode(TRANSPARENT); //设置背景 透明风格
字体推荐楷体,当然你也可以自行调整,比如“宋体”“仿宋”……
settextstyle(40, 18, L"楷体"); //设置开始界面字体大小 L设置字符集
音乐为天空之城,当然你也可以自己修改。
- 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);
放一张图片到窗口的函数是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
这个函数我试了好多个,目前我的版本GetMouseMsg( )是可以的。
- 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"退出");
- }
根据不同的坐标,执行不同的模式或者退出程序。
其中判断是否按下左键的函数是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);//退出游戏(终止)
- }
- }
- 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
- }
- }
- 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));
- }
- }
遍历整个数组,看八个方向,有一个雷就+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) + "】行结束执行===");
- }
这里用到了一个函数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;//输出提示框
- }
- }
- }
- }
用到函数SYSTEMTIME,可以调取年月日时秒分。
你想看到的后台调试信息都可以放进去。
- 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
//C++头文件 - #include
//时间函数 - #include
//标准输出输入库 - #include
//图形库 EasyX 是EasyX Graphics Library 是针对 Visual C++ 的免费绘图库,支持 VC6.0 ~VC2022,简单易用,学习成本极低,应用领域广泛 - #include
//windows SDK 播放函数 -
- #include
//文件库 - #include
//windows api - #include
// -
- #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 << "累计行数===>"<
-
- 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
- #include
- using namespace std;
- int main()
- {
- fstream f;
- //追加写入,在原来基础上加了ios::app
- f.open("data.txt",ios::out|ios::app);
- //输入你想写入的内容
- f<<"今天天气不错"<
- f.close();
- return 0;
- }
- */
-
- }
回顾编程过程
今天,我们一起探索了奇妙的扫雷游戏。运用到了很多知识点,有我们的老朋友递归,也有我们的新朋友日志。本篇文章制作不易,断更3周都在写这一篇。
本篇文章共20198字,真得不值得三连吗?