社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Python

利用Python实现自动扫雷小脚本

python • 4 年前 • 412 次点击  

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

代码已上传至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/

2.python 3

我的版本是 python 3.6.1

3.python的第三方库

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

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

二、关键代码组成

1.找到游戏窗口与坐标

#扫雷游戏窗口
class_name = "TMain"
title_name = "Minesweeper Arbiter "
hwnd = win32gui.FindWindow(class_name, title_name)

#窗口坐标
left = 0
top = 0
right = 0
bottom = 0

if hwnd:
    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, (192192192)), (31, (128128128))]
rgba_hongqi = [(54, (255255255)), (17, (25500)), (109, (192192192)), (54, (128128128)), (22, (000))]
rgba_0 = [(54, (255255255)), (148, (192192192)), (54, (128128128))]
rgba_1 = [(185, (192192 192)), (31, (128128128)), (40, (00255))]
rgba_2 = [(160, (192192192)), (31, (128128128)), (65, (01280))]
rgba_3 = [(62, (25500)), (163, (192192192)), (31, (128128128))]
rgba_4 = [(169, (192192192)), (31, (128128128)), (56, (00128))]
rgba_5 = [(70, (12800)), (155, (192192192 )), (31, (128128128))]
rgba_6 = [(153, (192192192)), (31, (128128128)), (72, (0128128))]
rgba_8 = [(149, (192192192)), (107, (128128128))]
rgba_boom = [(4, (255255255)), (144, (192192192)), (31, (128128128)), (77, (000))]
rgba_boom_red = [(4, (255255255)), (144, (25500)), (31, (128128128)), (77 , (000))]

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

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

#扫描雷区图像
def showmap():
    img = ImageGrab.grab().crop(rect)
    for y in range(blocks_y):
        for x in range(blocks_x):
            this_image = img.crop((x * block_width, y * block_height, (x + 1) * block_width, (y + 1) * block_height))
            if this_image.getcolors() == rgba_0:
                map[y][x] = 0
            elif this_image.getcolors() == rgba_1:
                map[y][x] = 1
            elif this_image.getcolors() == rgba_2:
                map[y][x] = 2
            elif this_image.getcolors() == rgba_3:
                map[y][x] = 3
            elif this_image.getcolors() == rgba_4:
                map[y][x] = 4
            elif this_image.getcolors() == rgba_5:
                map[y][x] = 5
            elif this_image.getcolors() == rgba_6:
                map[y][x] = 6
            elif this_image.getcolors() == rgba_8:
                map[y][x] = 8
            elif this_image.getcolors() == rgba_ ed:
                map[y][x] = -1
            elif this_image.getcolors() == rgba_hongqi:
                map[y][x] = -4
            elif this_image.getcolors() == rgba_boom or this_image.getcolors() == rgba_boom_red:
                global gameover
                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,如果没有符合条件的,则随机点击一个白块

#插旗
def banner():
    showmap()
    for y in range(blocks_y):
        for x in range(blocks_x):
            if 1 <= map[y][x] and map[y][x] <= 5:
                boom_number = map[y][x]
                block_white = 0
                block_qi = 0
                for yy in range(y-1,y+2):
                    for xx in range(x-1,x+2):
                        if 0 <= yy and 0 <= xx and yy and
 xx                             if not (yy == y and xx == x):if map[yy][xx] == 0:
                                    block_white += 1
                                elif map[yy][xx] == -4:
                                    block_qi += 1if boom_number == block_white + block_qi:for yy in range(y - 1, y + 2):
                        for xx in range(x - 1, x + 2):
                            if 0 <= yy and 0 <= xx and yy and xx                                 if not (yy == y and xx == x):
                                    if map[yy][xx] == 0:
                                        win32api.SetCursorPos([left+xx*block_width, top+yy*block_height])
                                        win32api.mouse_event(win32con.MOUSEEVENTF_RIGHTDOWN, 0000)
                                        win32api.mouse_event(win32con.MOUSEEVENTF_RIGHTUP, 00 00)
                                        showmap()

#点击白块
def dig():
    showmap()
    iscluck = 0
    for y in range(blocks_y):
        for x in range(blocks_x):
            if 1 <= map[y][x] and map[y][x] <= 5:
                boom_number = map[y][x]
                block_white = 0
                block_qi = 0
                for yy in range(y - 1, y + 2):
                    for xx in range(x - 1, x + 2):
                        if 0 <= yy and 0 <= xx and yy and xx                             if not (yy == y and xx == x):
                                if map[yy][xx] == 0:
                                    block_white += 1
                                elif map[yy][xx] == -4:
                                    block_qi += 1if boom_number == block_qi and block_white > 0:for yy in  range(y - 1, y + 2):
                        for xx in range(x - 1, x + 2):
                            if 0 <= yy and 0 <= xx and yy and xx                                 if not(yy == y and xx == x):
                                    if map[yy][xx] == 0:
                                        win32api.SetCursorPos([left + xx * block_width, top + yy * block_height])
                                        win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN, 0000)
                                        win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP, 0000)
                                        iscluck = 1
    if iscluck == 0:
        luck()

#随机点击
def luck():
    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, 0000 )
            win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP, 0000)
            fl = 0


def gogo():
    win32api.SetCursorPos([left, top])
    win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN, 0000)
    win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP, 0000)
    showmap()
    global gameover
    while(1):
        if(gameover == 0):
            banner()
            banner()
            dig()
        else:
            gameover = 0
            win32api.keybd_event(113000)
            win32api.SetCursorPos([left, top])
            win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN, 0000)
            win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP, 0000)
            showmap()

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


*声明:本文于网络整理,版权归原作者所有,如来源信息有误或侵犯权益,请联系我们删除或授权事宜。

觉得不错,点个“在看”然后转发出去


Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/99053
 
412 次点击