本文最后更新于 103 天前,其中的信息可能已经有所发展或是发生改变。
开发环境
VS2022 and EasyX(图形库)
这里使用VS2022作为IDE 此外需要安装图形库并使用GUI使程序告别漆黑的控制台
附件+可执行文件:扫雷
EasyX:EasyX_2023大暑版
Visual Studio的.sln项目文件:扫雷pro max
运行结果
使用IDA pro作个弊先
作为一名逆向工程爱好者,怎么能不开挂呢嘿嘿
我们用IDA打开之后能直接看见main函数,同时也能够很明显的看到判断胜负的地方
可以很明显看见有一个jnz指令,我们将其改为jz指令之后就可以实现踩到不是雷的地方就能胜利了,这大大提高了我们的胜率
随便踩一个就可以获胜了
此外还有更多的作弊方法,但是我懒得写了,就这样吧
代码实现
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include<graphics.h>
#include <windows.h>
#pragma comment( linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"" ) // 设置入口地址
#define ROW 30 //行
#define COL 20 //列
#define NUM 80 //雷
#define SIZE 20
//定义宏为了便于更改数据
int count = 0; //点开格子的个数
int map[ROW + 2][COL + 2]; //为了防止边界导致出错 外围多加一圈进行分区 分为游戏区和辅助区
//0 //其中只打印出游戏区
IMAGE img[12]; //存放图片
//初始化函数
void GameInit()
{
//随机数种子
srand(time(NULL));
//数组的赋初始值0
int i, j;
for (i = 0; i < ROW + 2; i++)
{
for (j = 0; j < COL + 2; j++)
{
map[i][j] = 0;
}
}
//布雷 1表示雷 NUM个雷
int n = 0;
while (n < NUM)
{
//随机行与列布雷
int r = rand() % ROW + 1; //1-ROW
int c = rand() % COL + 1; //1-COL
//随机数加1是为了防止布雷时布到辅助区
if (map[r][c] == 0)
{
map[r][c] = -1;
n++;
}
}
//根据雷的分布 填充其他不为雷的数据
int a, b, k, l;
for (a = 1; a <= ROW; a++)
{
for (b = 1; b <= COL; b++) //遍历二维数组 的游戏区
{
if (map[a][b] != -1) //找到不为雷的格子
{
//遍历该格的九宫格
for (k = a - 1; k <= a + 1; k++)
{
for (l = b - 1; l <= b + 1; l++)
{
if (map[k][l] == -1)
{
map[a][b]++;
}
}
}
}
}
}
//简单加密作为开局时的覆盖
for (i = 0; i < ROW + 2; i++)
{
for (j = 0; j < COL + 2; j++)
{
map[i][j] += 20;
}
}
}
//绘制函数 打印二维数组中所有元素
void Gamedraw()
{
//打印游戏区
int i, j;
for (i = 1; i <= ROW; i++)
{
for (j = 1; j <= COL; j++) //这里从1开始循环而不是从0开始循环 与i,j使用小于等于 都是为了仅打印出游戏区
{
printf("%2d ", map[i][j]);
/****************************************************
元素 图片
0-8 数字 +20 = 20-28
-1 img[9] +20 = 19
19-28 img[10]
>30 img[11]
*****************************************************/
if (map[i][j] == -1) //雷
{
putimage((i - 1) * SIZE, (j - 1) * SIZE, &img[9]);
}
else if (map[i][j] >= 0 && map[i][j] <= 8) //数字
{
putimage((i - 1) * SIZE, (j - 1) * SIZE, &img[map[i][j]]);
}
else if (map[i][j] >= 19 && map[i][j] <= 28) //方格
{
putimage((i - 1) * SIZE, (j - 1) * SIZE, &img[10]);
}
else if (map[i][j] > 30) //旗帜
{
putimage((i - 1) * SIZE, (j - 1) * SIZE, &img[11]);
}
}
printf("\n");
}
}
void OpenZero(int r, int c)
{
int m, n;
//先翻开格子
map[r][c] -= 20;
count++;
//辅助区为0
for (m = r - 1; m <= r + 1; m++)
{
for (n = c - 1; n <= c + 1; n++) //两个for循环遍历九宫格
{
if (m >= 1 && m <= ROW && n >= 1 && n <= COL) //保证遍历游戏区
{
if (map[m][n] >= 19 && map[m][n] <= 28) //限制条件来翻开空白格
{
if (map[m][n] != 20)
{
map[m][n] -= 20;
count++;
}
else
{
OpenZero(m, n);
}
}
}
}
}
}
int Gameplay()
{
MOUSEMSG msg = { 0 }; //定义一个鼠标
int r, c;
while (1)
{
msg = GetMouseMsg();
switch (msg.uMsg)
{
case WM_LBUTTONDOWN: //排雷
r = msg.x / SIZE + 1;
c = msg.y / SIZE + 1;
if (map[r][c] >= 19 && map[r][c] <= 28)
{
if (map[r][c] == 20)
{
OpenZero(r, c);
}
else
{
map[r][c] -= 20;
count++; //判断胜负
}
}
return map[r][c];
break;
case WM_RBUTTONDOWN: //插旗
r = msg.x / SIZE + 1;
c = msg.y / SIZE + 1;
if (map[r][c] >= 19 && map[r][c] <= 28)
{
map[r][c] += 50; //>30
}
else if (map[r][c] > 30)
{
map[r][c] -= 50;
}
return map[r][c];
break;
}
}
}
int main()
{
HWND hwnd = initgraph(ROW * SIZE, COL * SIZE); // 不传入 SHOWCONSOLE 参数,只显示图像窗口,不显示控制台窗口
loadimage(&img[0], L"0.jpg", SIZE, SIZE);
loadimage(&img[1], L"1.jpg", SIZE, SIZE);
loadimage(&img[2], L"2.jpg", SIZE, SIZE);
loadimage(&img[3], L"3.jpg", SIZE, SIZE);
loadimage(&img[4], L"4.jpg", SIZE, SIZE);
loadimage(&img[5], L"5.jpg", SIZE, SIZE);
loadimage(&img[6], L"6.jpg", SIZE, SIZE);
loadimage(&img[7], L"7.jpg", SIZE, SIZE);
loadimage(&img[8], L"8.jpg", SIZE, SIZE);
loadimage(&img[9], L"9.jpg", SIZE, SIZE); //雷
loadimage(&img[10], L"10.jpg", SIZE, SIZE); //旗帜
loadimage(&img[11], L"11.jpg", SIZE, SIZE); //方格
/****************************************************
元素 图片
0-8 数字 +20 = 20-28
-1 img[9] +20 = 19
19-28 img[10]
>30 img[11]
*****************************************************/
GameInit();
while (1)
{
Gamedraw();
if (Gameplay() == -1)
{
Gamedraw();
MessageBox(hwnd, L"cai", L"Try again", MB_OK);
break;
}
if (ROW * COL - NUM == count)
{
Gamedraw();
MessageBox(hwnd, L"WIN!!!", L"Ciallo", MB_OK);
break;
}
}
closegraph();
return 0;
}
代码解释
我们引入了<graphics.h>
头文件,使我们的程序能够使用图片
设置了函数入口点,避免程序单独运行时弹出控制台窗口
使用宏定义以便于修改格子与雷的数量
使用伪随机数使得程序每次运行时生成雷的格子都不同
二维数组布置地图
对数值进行简单的加密使其防止被逆向(没什么用就是了)
通过排雷总数计算胜负
使用递归进行游戏
总结
写着玩的,各位图一乐就行了