python扫雷(室友扫雷通关来炫耀)(1)

自动扫雷一般分为两种,一种是读取内存数据,而另一种是通过分析图片获得数据,并通过模拟鼠标操作,这里我用的是第二种方式。

代码已上传至GitHub:

https://github.com/chestnut-egg/GoMine

作者:chestnut_egg

源自:https://www.cnblogs.com/chestnut-egg/p/9302238.html

一、准备工作

1.扫雷游戏

我是win10,没有默认的扫雷,所以去扫雷网下载

http://www.saolei.net/BBS/

python扫雷(室友扫雷通关来炫耀)(2)

2.python 3

我的版本是 python 3.6.1

3.python的第三方库

python扫雷(室友扫雷通关来炫耀)(3)

win32api,win32gui,win32con,Pillow,numpy,opencv可通过 pip install --upgrade SomePackage 来进行安装注意:有的版本是下载pywin32,但是有的要把pywin32升级到最高并自动下载了pypiwin32,具体情况每个python版本可能都略有不同

我给出我的第三方库和版本仅供参考

python扫雷(室友扫雷通关来炫耀)(4)

二、关键代码组成

1.找到游戏窗口与坐标

#扫雷游戏窗口 class_name="TMain" title_name="MinesweeperArbiter" hwnd=win32gui.FindWindow(class_name,title_name) #窗口坐标 left=0 top=0 right=0 bottom=0 ifhwnd: print("找到窗口") left,top,right,bottom=win32gui.GetWindowrect(hwnd) #win32gui.SetForegroundWindow(hwnd) print("窗口坐标:") print(str(left) '' str(right) '' str(top) '' str(bottom)) else: print("未找到窗口")

2.锁定并抓取雷区图像

#锁定雷区坐标 #去除周围功能按钮以及多余的界面 #具体的像素值是通过QQ的截图来判断的 left =15 top =101 right-=15 bottom-=42 #抓取雷区图像 rect=(left,top,right,bottom) img=ImageGrab.grab().crop(rect)

3.各图像的RGBA值

#数字1-8周围雷数 #0未被打开 #ed被打开空白 #hongqi红旗 #boom普通雷 #boom_red踩中的雷 rgba_ed=[(225,(192,192,192)),(31,(128,128,128))] rgba_hongqi=[(54,(255,255,255)),(17,(255,0,0)),(109,(192,192,192)),(54,(128,128,128)),(22,(0,0,0))] rgba_0=[(54,(255,255,255)),(148,(192,192,192)),(54,(128,128,128))] rgba_1=[(185,(192,192,192)),(31,(128,128,128)),(40,(0,0,255))] rgba_2=[(160,(192,192,192)),(31,(128,128,128)),(65,(0,128,0))] rgba_3=[(62,(255,0,0)),(163,(192,192,192)),(31,(128,128,128))] rgba_4=[(169,(192,192,192)),(31,(128,128,128)),(56,(0,0,128))] rgba_5=[(70,(128,0,0)),(155,(192,192,192)),(31,(128,128,128))] rgba_6=[(153,(192,192,192)),(31,(128,128,128)),(72,(0,128,128))] rgba_8=[(149,(192,192,192)),(107,(128,128,128))] rgba_boom=[(4,(255,255,255)),(144,(192,192,192)),(31,(128,128,128)),(77,(0,0,0))] rgba_boom_red=[(4,(255,255,255)),(144,(255,0,0)),(31,(128,128,128)),(77,(0,0,0))]

(左右滑动可查看完整代码)

4.扫描雷区图像保存至一个二维数组map

#扫描雷区图像 defshowmap(): img=ImageGrab.grab().crop(rect) foryinrange(blocks_y): forxinrange(blocks_x): this_image=img.crop((x*block_width,y*block_height,(x 1)*block_width,(y 1)*block_height)) ifthis_image.getcolors()==rgba_0: map[y][x]=0 elifthis_image.getcolors()==rgba_1: map[y][x]=1 elifthis_image.getcolors()==rgba_2: map[y][x]=2 elifthis_image.getcolors()==rgba_3: map[y][x]=3 elifthis_image.getcolors()==rgba_4: map[y][x]=4 elifthis_image.getcolors()==rgba_5: map[y][x]=5 elifthis_image.getcolors()==rgba_6: map[y][x]=6 elifthis_image.getcolors()==rgba_8: map[y][x]=8 elifthis_image.getcolors()==rgba_ed: map[y][x]=-1 elifthis_image.getcolors()==rgba_hongqi: map[y][x]=-4 elifthis_image.getcolors()==rgba_boomorthis_image.getcolors()==rgba_boom_red: globalgameover gameover=1 break #sys.exit(0) else: print("无法识别图像") print("坐标") print((y,x)) print("颜色") print(this_image.getcolors()) sys.exit(0) #print(map)

(左右滑动可查看完整代码)

5.扫雷算法

这里我采用的最基础的算法

1.首先点出一个点

2.扫描所有数字,如果周围空白 插旗==数字,则空白均有雷,右键点击空白插旗

3.扫描所有数字,如果周围插旗==数字,则空白均没有雷,左键点击空白

4.循环2、3,如果没有符合条件的,则随机点击一个白块

#插旗 defbanner(): showmap() foryinrange(blocks_y): forxinrange(blocks_x): if1<=map[y][x]andmap[y][x]<=5: boom_number=map[y][x] block_white=0 block_qi=0 foryyinrange(y-1,y 2): forxxinrange(x-1,x 2): if0<=yyand0<=xxandyy<blocks_yandxx<blocks_x: ifnot(yy==yandxx==x):ifmap[yy][xx]==0: block_white =1 elifmap[yy][xx]==-4: block_qi =1ifboom_number==block_white block_qi:foryyinrange(y-1,y 2): forxxinrange(x-1,x 2): if0<=yyand0<=xxandyy<blocks_yandxx<blocks_x: ifnot(yy==yandxx==x): ifmap[yy][xx]==0: win32api.SetCursorPos([left xx*block_width,top yy*block_height]) win32api.mouse_event(win32con.MOUSEEVENTF_RIGHTDOWN,0,0,0,0) win32api.mouse_event(win32con.MOUSEEVENTF_RIGHTUP,0,0,0,0) showmap() #点击白块 defdig(): showmap() iscluck=0 foryinrange(blocks_y): forxinrange(blocks_x): if1<=map[y][x]andmap[y][x]<=5: boom_number=map[y][x] block_white=0 block_qi=0 foryyinrange(y-1,y 2): forxxinrange(x-1,x 2): if0<=yyand0<=xxandyy<blocks_yandxx<blocks_x: ifnot(yy==yandxx==x): ifmap[yy][xx]==0: block_white =1 elifmap[yy][xx]==-4: block_qi =1ifboom_number==block_qiandblock_white>0:foryyinrange(y-1,y 2): forxxinrange(x-1,x 2): if0<=yyand0<=xxandyy<blocks_yandxx<blocks_x: ifnot(yy==yandxx==x): ifmap[yy][xx]==0: win32api.SetCursorPos([left xx*block_width,top yy*block_height]) win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN,0,0,0,0) win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP,0,0,0,0) iscluck=1 ifiscluck==0: luck() #随机点击 defluck(): fl=1 while(fl): random_x=random.randint(0,blocks_x-1) random_y=random.randint(0,blocks_y-1) if(map[random_y][random_x]==0): win32api.SetCursorPos([left random_x*block_width,top random_y*block_height]) win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN,0,0,0,0) win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP,0,0,0,0) fl=0 defgogo(): win32api.SetCursorPos([left,top]) win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN,0,0,0,0) win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP,0,0,0,0) showmap() globalgameover while(1): if(gameover==0): banner() banner() dig() else: gameover=0 win32api.keybd_event(113,0,0,0) win32api.SetCursorPos([left,top]) win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN,0,0,0,0) win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP,0,0,0,0) showmap()

,