文章目录
用Python+OpenCV实现了自动扫雷,突破世界记录,我们先来看一下效果吧。
中级 - 0.74秒 3BV/S=60.81
相信许多人很早就知道有扫雷这么一款经典的游(显卡测试)戏(软件),更是有不少人曾听说过中国雷圣,也是中国扫雷第一、世界综合排名第二的郭蔚嘉的顶顶大名。扫雷作为一款在Windows9x时代就已经诞生的经典游戏,从过去到现在依然都有着它独特的魅力:快节奏高精准的鼠标操作要求、快速的反应能力、刷新纪录的快感,这些都是扫雷给雷友们带来的、只属于扫雷的独一无二的兴奋点。
准备
准备动手制作一套扫雷自动化软件之前,你需要准备如下一些工具/软件/环境
- 开发环境
- Python3 环境 - 推荐3.6或者以上 [更加推荐Anaconda3,以下很多依赖库无需安装]
- numpy依赖库 [如有Anaconda则无需安装]
- PIL依赖库 [如有Anaconda则无需安装]
- opencv-python
- win32gui、win32api依赖库
- 支持Python的IDE [可选,如果你能忍受用文本编辑器写程序也可以]
- 扫雷软件
· Minesweeper Arbiter(必须使用MS-Arbiter来进行扫雷!)
好啦,那么我们的准备工作已经全部完成了!让我们开始吧~
实现思路
在去做一件事情之前最重要的是什么? 是将要做的这件事情在心中搭建一个步骤框架。 只有这样,才能保证在去做这件事的过程中,尽可能的做到深思熟虑,使得最终有个好的结果。 我们写程序也要尽可能做到在正式开始开发之前,在心中有个大致的思路。
对于本项目而言,大致的开发过程是这样的:
- 完成窗体内容截取部分
- 完成雷块分割部分
- 完成雷块类型识别部分
- 完成扫雷算法
好啦,既然我们有了个思路,那就撸起袖子大力干!
窗体截取
其实对于本项目而言,窗体截取是一个逻辑上简单,实现起来却相当麻烦的部分,而且还是必不可少的部分。 我们通过Spy++得到了以下两点信息:
class\_name = "TMain"
title\_name = "Minesweeper Arbiter "
- ms_arbiter.exe的主窗体类别为"TMain"
- ms_arbiter.exe的主窗体名称为"Minesweeper Arbiter "
注意到了么?主窗体的名称后面有个空格。正是这个空格让笔者困扰了一会儿,只有加上这个空格,win32gui才能够正常的获取到窗体的句柄。
本项目采用了win32gui来获取窗体的位置信息,具体代码如下:
hwnd = win32gui.FindWindow(class\_name, title\_name)
if hwnd:
left, top, right, bottom = win32gui.GetWindowRect(hwnd)
通过以上代码,我们得到了窗体相对于整块屏幕的位置。之后我们需要通过PIL来进行扫雷界面的棋盘截取。
我们需要先导入PIL库
from PIL import ImageGrab
然后进行具体的操作。
left += 15
top += 101
right -= 15
bottom -= 43
rect = (left, top, right, bottom)
img = ImageGrab.grab().crop(rect)
聪明的你肯定一眼就发现了那些奇奇怪怪的Magic Numbers,没错,这的确是Magic Numbers,是我们通过一点点细微调节得到的整个棋盘相对于窗体的位置。
注意:这些数据仅在Windows10下测试通过,如果在别的Windows系统下,不保证相对位置的正确性,因为老版本的系统可能有不同宽度的窗体边框。
橙色的区域是我们所需要的
好啦,棋盘的图像我们有了,下一步就是对各个雷块进行图像分割了~
雷块分割
在进行雷块分割之前,我们事先需要了解雷块的尺寸以及它的边框大小。经过笔者的测量,在ms_arbiter下,每一个雷块的尺寸为16px*16px。
知道了雷块的尺寸,我们就可以进行每一个雷块的裁剪了。首先我们需要知道在横和竖两个方向上雷块的数量。
block\_width, block\_height = 16, 16
blocks\_