扫雷最原始的版本可以追溯到1973年一款名为“方块”的游戏。
不久,“方块”被改写成了游戏“Rlogic”。在“Rlogic”里,玩家的任务是作为美国海军陆战队队员,为指挥中心探出一条没有地雷的安全路线,如果路全被地雷堵死就算输。两年后,汤姆·安德森在“Rlogic”的基础上又编写出了游戏“地雷”,由此奠定了现代扫雷游戏的雏形。
1981年,微软公司的罗伯特·杜尔和卡特·约翰逊两位工程师在Windows3.1系统上加载了该游戏,扫雷游戏才正式在全世界推广开来。
这款游戏的玩法是在一个9*9(初级),16*16(中级),16*30(高级),或自定义大小的方块矩阵中随机布置一定量的地雷(初级为10个,中级为40个,高级为99个)。由玩家逐个翻开方块,以找出所有地雷为最终游戏目标。如果玩家翻开的方块有地雷,则游戏结束。
我们今天就来自己写《扫雷》
这个项目并不是很难,今天就和大家从头到尾详细的讲一遍,大家一定要好好看好好学!
行吧,开始了
我们今天用的是Cpp来写,但不是用Windows来创建窗口,而是用他的远房表亲EasyX图形库来创建窗口,因为用图形库会简单很多,刚学C的也可以听懂,而且C/C++不分家,没有什么问题,OK,我们现在开始写代码,今天我就把头文件也分享出来了,主要是教大家如何去调用图形库。(注:没有EasyX图形库的可以去官网下载,也可以进群直接下载)
首先是我们的头文件以及一些宏定义
`
1. #include<stdio.h>
2. #include<graphics.h>//包含图形库头文件
3. #define ROW 9 //行
4. #define COL 9 //列 共81个格子
5. #define MINE_NUM 18//雷的数量
6. #define IMG_SIZE 40
`
初始化函数,也是我们的老朋友了
`
1. void GameInit()
2. {
3. //1,创建窗口 一行有九张图片每张图片40px,
4. initgraph(IMG_SIZE*ROW, IMG_SIZE*COL,SHOWCONSOLE);
5. //加载图片(赋值) load加载 第一个参数,存储图片的变量 错误:字符集问题
6. for (int i = 0; i < 12; i++)
7. {
8. char file[20] = "";
9. sprintf(file, "./image/%d.jpg", i);
10. loadimage(&img[i], file, IMG_SIZE, IMG_SIZE);
11. }
12. //布雷
13. for (int i = 0; i < MINE_NUM; )
14. {
15. //排除辅助区
16. int row = rand() % ROW+1;//0-8 1-9
17. int col = rand() % COL+1;
18. if (mine[row][col] == 0)
19. {
20. mine[row][col] = 9;
21. i++;
22. }
23. }
24. //雷所在的九宫格,要加1(雷除外)
25. for (int i = 1; i < ROW+1; i++)
26. {
27. for (int k = 1; k < COL+1; k++)
28. {
29. if (mine[i][k] == 9)
30. {
31. //遍历雷的九宫格 细心
32. for (int a = i - 1; a <= i + 1; a++)
33. {
34. for (int b = k - 1; b <= k + 1; b++)
35. {
36. //非雷的格子加1
37. if (mine[a][b] != 9)
38. {
39. mine[a][b]++;
40. }
41. }
42. }
43. }
44. }
45. }
46. //加密 开始时全部为掩码图
47. for (int i = 1; i < ROW + 1; i++)
48. {
49. for (int k = 1; k < COL + 1; k++)
50. {
51. mine[i][k] += 20;
52. }
53. }
55. }
`
鼠标信息处理函数
`
1. void MouseEvent()
2. {
3. //检测是否有鼠标消息
4. if (MouseHit())
5. {
6. //获取鼠标消息,坐标,左键还是右键
7. MOUSEMSG msg = GetMouseMsg();
8. //把坐标转化成数组下标
9. openr = msg.y / IMG_SIZE+1;
10. openc = msg.x / IMG_SIZE+1;
11. //判断是左键还是右键
12. switch (msg.uMsg)
13. {
14. case WM_LBUTTONDOWN:
15. //如果格子没有打开,就打开格子,否则不做处理
16. if (mine[openr][openc] > 9)
17. {
18. mine[openr][openc] -= 20;
19. OpenNull(openr,openc);
20. num++;
21. }
22. break;
23. case WM_RBUTTONDOWN:
24. //标记
25. if (mine[openr][openc] > 9 && mine[openr][openc] <= 29)
26. {
27. mine[openr][openc] += 20;
28. }
29. else
30. {
31. mine[openr][openc] -= 20;
32. }
33. break;
34. }
35. }
36. }
`
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
进行递归操作,判断鼠标点击的地方
`
1. //递归打开所有空白,以及空白周围的数字
2. void OpenNull(int row,int col)
3. {
4. //点击的是空白才能打开
5. if (mine[row][col] == 0)
6. {
7. for (int i = row - 1; i <= row + 1; i++)
8. {
9. for (size_t k = col-1; k <= col+1; k++)
10. {
11. //如果为空或者不是雷就打开
12. if ((mine[i][k] == 20 || mine[i][k] != 29)&& mine[i][k]>9)
13. {
14. mine[i][k] -= 20;
15. num++;
16. OpenNull(i, k);
17. }
18. }
19. }
20. }
21. }
`
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
游戏的输赢判断函数,注意理清逻辑
`
1. void Jude()
2. {
3. //判断输
4. if (mine[openr][openc] == 9)
5. {
6. int isok = MessageBox(GetHWnd(), "是否继续!", "点到雷了", MB_OKCANCEL);
7. if (isok == IDOK)
8. {
9. mine[openr][openc] += 20;
10. }
11. else
12. {
13. exit(666);
14. }
15. }
16. //判断赢
17. if (num == ROW*COL - MINE_NUM)
18. {
19. int isok = MessageBox(GetHWnd(), "是否继续!", "点到雷了", MB_OKCANCEL);
20. if (isok == IDOK)
21. {
22. num = 0;
23. GameInit();
24. }
25. else
26. {
27. exit(666);
28. }
29. }
30. }
`
最后就是我们的主函数了
`
1. int main()
2. {
3. GameInit();
4. show();
5. //循环处理游戏逻辑
6. while (1)
7. {
8. MouseEvent();
9. GameDraw();
10. Jude();
11. }
13. getchar();
14. return 0;
15. }
`