林小林 发表于 2021-5-23 03:50:14

扫雷辅助

本帖最后由 林小林 于 2021-5-23 03:51 编辑

自己写了一个扫雷的辅助程序。对初级和中级扫雷,基本上程序就可以完成,成功率极高。
高级扫雷,成功率很低
(基本上很难拷过去直接用,我里面很多参数是针对我的电脑和我装的扫雷设置的……)
(实在是没有力气去完成所有参数的自动化了)

# -*- coding: utf-8 -*-
# What the code does: Convert pictures to text
# Author: Kkkkix
# Last Modified: 21/05/20

import win32gui, win32api, win32con
import matplotlib.pyplot as plt
import colorsys
import random
import numpy as np
from PIL import ImageGrab


def initiate_para():
    block_x = 16
    block_y = 16
    # block_x = 8   # Beginner
    # block_y = 8
    block_width = 16
    block_height = 16
    return block_x,block_y,block_width,block_height


# Find the minesweeper window and get the mine area
def findMinesweeper():
    title_name = 'Minesweeper Clone 2007'
    ms_win = win32gui.FindWindow(None, title_name)

    # window coordinates
    left,top,right,bottom = 0,0,0,0

    if ms_win:
      print("找到窗口:%s" % title_name)
      left, top, right, bottom = win32gui.GetWindowRect(ms_win)
      win32gui.SetForegroundWindow(ms_win)
      print("窗口的坐标是:left:%d; top:%d; right:%d; bottom:%d" % (left,top,right,bottom))
    else:
      print("未找到窗口")

    return (left,top,right,bottom)


# Take a screenshot and select the mine area
def getMineArea(win_pos):
    win_pos_temp = list(win_pos[:])
    win_pos_temp += 15
    win_pos_temp += 104
    win_pos_temp -= 15
    win_pos_temp -= 40
    img = ImageGrab.grab().crop(win_pos_temp)
    # plt.figure('a')
    # plt.imshow(img)
    # plt.show()
    return img


# The color info
def init_colorInfo():
    rgb_0 = [(22, (255, 255, 255)), (110, (192, 192, 192))]
    rgb_1 = [(88, (192, 192, 192)), (11, (128, 128, 128)), (33, (0, 0, 255))]
    rgb_2 = [(66, (192, 192, 192)), (11, (128, 128, 128)), (55, (0, 128, 0))]
    rgb_3 = [(53, (255, 0, 0)), (68, (192, 192, 192)), (11, (128, 128, 128))]
    rgb_4 = [(68, (192, 192, 192)), (11, (128, 128, 128)), (53, (0, 0, 128))]
    rgb_5 = [(61, (128, 0, 0)), (60, (192, 192, 192)), (11, (128, 128, 128))]

    rgb_50 = [(22, (255, 255, 255)), (17, (255, 0, 0)), (79, (192, 192, 192)), (14, (0, 0, 0))] # number 50: red flag
    rgb_100 = [(121, (192, 192, 192)), (11, (128, 128, 128))]                   # number 100: opened and empty
    rgb_101 = [(4, (255, 255, 255)), (51, (192, 192, 192)), (11, (128, 128, 128)), (66, (0, 0, 0))] #101: opened and mine
    rgb_102 = [(4, (255, 255, 255)), (51, (255, 0, 0)), (11, (128, 128, 128)), (66, (0, 0, 0))]   #102: clicked mine

    rgb_game_finish = [(61, (255, 255, 0)), (3, (16, 16, 0)), (12, (247, 247, 0)), (11, (239, 239, 0)), (6, (231, 231, 0)), (151, (225, 225, 225)), (2, (49, 49, 24)), (2, (16, 16, 16)), (2, (189, 189, 0)), (1, (181, 181, 0)), (4, (173, 173, 0)), (1, (165, 165, 0)), (5, (123, 123, 132)), (1, (115, 115, 115)), (1, (49, 49, 16)), (6, (107, 107, 115)), (1, (123, 123, 115)), (2, (107, 107, 0)), (4, (99, 99, 99)), (1, (74, 74, 16)), (2, (123, 123, 0)), (2, (57, 57, 57)), (1, (49, 49, 41)), (1, (74, 74, 24)), (1, (41, 41, 41)), (3, (33, 33, 0)), (6, (41, 41, 0)), (2, (57, 57, 16)), (2, (41, 41, 16)), (2, (24, 24, 16)), (1, (74, 74, 57)), (2, (57, 57, 0)), (8, (222, 222, 0)), (4, (24, 24, 0)), (9, (206, 206, 0)), (7, (214, 214, 0)), (8, (198, 198, 198)), (2, (198, 198, 0)), (2, (156, 156, 0)), (1, (140, 140, 0)), (3, (132, 132, 132)), (1, (132, 132, 0)), (4, (90, 90, 0)), (2, (115, 115, 0)), (1, (99, 99, 0)), (1, (82, 82, 0)), (6, (74, 74, 0)), (3, (66, 66, 57)), (1, (66, 66, 0)), (1, (66, 66, 24)), (2, (33, 33, 16)), (5, (49, 49, 0)), (2, (24, 24, 8)), (1, (16, 16, 8)), (2, (8, 8, 0)), (22, (0, 0, 0))]
    rgb_game_running = [(116, (255, 255, 0)), (2, (16, 16, 0)), (7, (247, 247, 0)), (9, (239, 239, 0)), (4, (231, 231, 0)), (151, (225, 225, 225)), (1, (49, 49, 8)), (1, (16, 16, 16)), (3, (189, 189, 0)), (1, (181, 181, 0)), (2, (173, 173, 0)), (2, (165, 165, 0)), (6, (123, 123, 132)), (2, (115, 115, 0)), (2, (49, 49, 16)), (8, (107, 107, 115)), (2, (123, 123, 0)), (4, (99, 99, 99)), (1, (74, 74, 16)), (10, (57, 57, 0)), (1, (49, 49, 41)), (1, (74, 74, 24)), (1, (41, 41, 41)), (1, (33, 33, 16)), (4, (41, 41, 0)), (1, (57, 57, 16)), (3, (41, 41, 16)), (2, (24, 24, 16)), (1, (74, 74, 57)), (6, (222, 222, 0)), (3, (24, 24, 0)), (5, (206, 206, 0)), (1, (214, 214, 0)), (8, (198, 198, 198)), (1, (198, 198, 0)), (2, (49, 49, 0)), (1, (156, 156, 0)), (2, (132, 132, 132)), (1, (132, 132, 0)), (2, (90, 90, 0)), (2, (99, 99, 0)), (2, (82, 82, 0)), (5, (74, 74, 0)), (3, (66, 66, 57)), (1, (66, 66, 24)), (2, (49, 49, 49)), (3, (24, 24, 8)), (1, (16, 16, 8))]
    rgb_game_over = [(95, (255, 255, 0)), (11, (16, 16, 0)), (5, (247, 247, 0)), (3, (239, 239, 0)), (3, (231, 231, 0)), (151, (225, 225, 225)), (2, (49, 49, 16)), (1, (16, 16, 16)), (7, (189, 189, 0)), (10, (181, 181, 0)), (7, (173, 173, 0)), (1, (165, 165, 0)), (6, (123, 123, 132)), (2, (49, 49, 0)), (8, (107, 107, 115)), (2, (123, 123, 0)), (4, (99, 99, 99)), (1, (74, 74, 16)), (2, (57, 57, 57)), (1, (49, 49, 41)), (1, (74, 74, 24)), (1, (41, 41, 41)), (3, (33, 33, 16)), (4, (41, 41, 0)), (2, (57, 57, 0)), (3, (41, 41, 16)), (2, (24, 24, 16)), (1, (74, 74, 57)), (1, (57, 57, 16)), (6, (222, 222, 0)), (2, (24, 24, 0)), (3, (206, 206, 0)), (2, (214, 214, 0)), (8, (198, 198, 198)), (7, (198, 198, 0)), (2, (156, 156, 0)), (3, (148, 148, 0)), (6, (140, 140, 0)), (2, (132, 132, 132)), (3, (132, 132, 0)), (1, (90, 90, 0)), (2, (99, 99, 0)), (1, (82, 82, 0)), (4, (74, 74, 0)), (3, (66, 66, 57)), (1, (66, 66, 24)), (1, (49, 49, 8)), (2, (24, 24, 8)), (1, (16, 16, 8))]


    color_info = {'1':rgb_1, '2':rgb_2, '3':rgb_3, '4':rgb_4, '5':rgb_5,
                  '50':rgb_50, '0':rgb_0,
                  '100':rgb_100, '101':rgb_101, '102':rgb_102,
                  'finish':rgb_game_finish,'running':rgb_game_running,'over':rgb_game_over}
    return color_info


# Convert the mine area image to map
def convertImg2map(img):
    # number 1-8: number of mines around
    # number 0: not opened
    # number 50: red flag
    # number 100: opened and empty
    # number 101: opened and mine
    # number 102: clicked mine
    block_x,block_y,block_width,block_height = initiate_para()
    color_info = init_colorInfo()
    DictLab = color_info.copy()
    mine_map = [ for j in range(block_y)]
    for y in range(block_y):
      for x in range(block_x):
            this_image = img.crop((x*block_width, y*block_height, (x+1)*block_width,(y+1)*block_height))
            this_image = this_image.crop((2,1,13,13))
            # plt.figure('a')
            # plt.imshow(this_image)
            # plt.ion()
            # plt.pause(0.1)
            # plt.close()
            print(this_image.getcolors())

            if this_image.getcolors() == color_info['1']:
                mine_map = 1
            elif this_image.getcolors() == color_info['2']:
                mine_map = 2
            elif this_image.getcolors() == color_info['3']:
                mine_map = 3
            elif this_image.getcolors() == color_info['4']:
                mine_map = 4
            elif this_image.getcolors() == color_info['5']:
                mine_map = 5

            elif this_image.getcolors() == color_info['50']:
                mine_map = 50
            elif this_image.getcolors() == color_info['100']:
                mine_map = 100
            elif this_image.getcolors() == color_info['101']:
                mine_map = 101
            elif this_image.getcolors() == color_info['102']:
                mine_map = 102
            elif this_image.getcolors() == color_info['0']:
                mine_map = 0

            else:
                print('There is one figure which can not be recognized')
                print('x = %d; y = %d' % (x,y))
                input('press Enter button to continue --->>>')

            if this_image.getcolors() not in DictLab.values():
                DictLab["%d;%d" % (x,y)] = this_image.getcolors()
    print('The DictLab is: ',end='')
    print(DictLab)
    # input('press Enter button to continue --->>>')
    returnmine_map


def mouse_click(x, y):
    win32api.SetCursorPos()
    win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0)
    win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP, 0, 0, 0, 0)


def mouse_right_click(x, y):
    win32api.SetCursorPos()
    win32api.mouse_event(win32con.MOUSEEVENTF_RIGHTDOWN, 0, 0, 0, 0)
    win32api.mouse_event(win32con.MOUSEEVENTF_RIGHTUP, 0, 0, 0, 0)


def luck(mine_map,win_pos):
    block_width,block_height = initiate_para()
    mine_map = np.array(mine_map)
    enpty_index = np.where(mine_map == 0)
    empty_index_matrix = np.dstack((enpty_index,enpty_index))

    num_empty = empty_index_matrix.shape   # (1, 176, 2)
    ran_int = random.randint(0,num_empty-1)
    click_x, click_y = empty_index_matrix,empty_index_matrix

    win_pos_temp = list(win_pos[:])
    win_pos_temp += 15
    win_pos_temp += 104
    win_pos_temp -= 15
    win_pos_temp -= 40
    mouse_click(win_pos_temp+(click_x+1)*block_width-int(block_width/2), win_pos_temp+(click_y+1)*block_height-int(block_height/2))
    print('click %d %d' % (click_x,click_y))


def num_around(mine_map,posi):
    # This function is used to count the surround situation
    # posi format is (row = y,column = x)
    block_x,block_y = initiate_para()
    num_num = -1
    num_empty = 0
    num_closed = 0
    num_flag = 0
    closed_posi = []
    if posi == 0:    # the first row
      start_y = 0
      end_y = 2
    elif posi == block_y-1: # the last row
      start_y = block_y-2
      end_y = block_y
    else:   # the other row
      start_y = posi -1
      end_y = posi +2

    if posi == 0:    # the first column
      start_x = 0
      end_x = 2
    elif posi == block_x-1:# the last column
      start_x = block_x-2
      end_x = block_x
    else:# the other column
      start_x = posi - 1
      end_x = posi + 2

    for x in range(start_x,end_x):
      for y in range(start_y,end_y):
            if (mine_map <= 8) & (mine_map != 0):
                num_num += 1
            elif (mine_map == 0):
                num_closed += 1
                closed_posi.append((y,x))
            elif (mine_map == 50):
                num_flag += 1
            elif (mine_map == 100):
                num_empty += 1

    return


def flagandclick(mine_map,win_pos):
    win_pos_temp = list(win_pos[:])
    win_pos_temp += 15
    win_pos_temp += 104
    win_pos_temp -= 15
    win_pos_temp -= 40
    block_width, block_height = initiate_para()
    mine_map = np.array(mine_map)
    print(mine_map)
    clicked_num_index = np.where((mine_map <=8) & (mine_map != 0))
    clicked_num_index_matrix = np.dstack((clicked_num_index, clicked_num_index))

    print(clicked_num_index_matrix)

    for each_num in clicked_num_index_matrix:
      print(each_num)
      ar_det = num_around(mine_map,each_num)   # around details of this position
      print('around details: ', end='')
      print(ar_det)
      if ar_det == 0:
            continue
      elif mine_map]] - ar_det == ar_det:   # number of mines - flags = closed
            print('each_num: ',end='')
            print(each_num)
            for each in ar_det:
                print(each)
                y = win_pos_temp + (each + 1) * block_height - int(block_height / 2)
                x = win_pos_temp + (each + 1) * block_width - int(block_width / 2)
                print('click',end='')
                print(x,y)
                mouse_right_click(x,y)
            break
      elif mine_map]] - ar_det == 0:   # number of mines = flags
            for each in ar_det:
                y = win_pos_temp + (each + 1) * block_height - int(block_height / 2)
                x = win_pos_temp + (each + 1) * block_width - int(block_width / 2)
                print('click',end='')
                print(x,y)
                mouse_click(x,y)
            break




def checkGameStatus(win_pos):
    color_info = init_colorInfo()
    win_pos_temp = list(win_pos[:])
    win_pos_temp += 132
    win_pos_temp += 67
    win_pos_temp = win_pos_temp + 20
    win_pos_temp = win_pos_temp + 20
    img = ImageGrab.grab().crop(win_pos_temp)
    if img.getcolors() == color_info['running']:
      return True
    elif img.getcolors() == color_info['over']:
      print('Game Over. Too Sad...')
      return False
    elif img.getcolors() == color_info['finish']:
      print('Game is finish!!!')
      return False
    else:
      print('nothin detected')
      return True




def Solver():
    game_status = True
    times = 0
    while game_status:
      win_pos = findMinesweeper()
      mine_area_img = getMineArea(win_pos)
      mine_map = convertImg2map(img=mine_area_img)

      # luck(mine_map, win_pos)
      flagandclick(mine_map,win_pos)
      game_status = checkGameStatus(win_pos)

      times += 1
      if times == 1000:
            break
      # break
      # if


if __name__ == '__main__':
    # win_pos = findMinesweeper()
    # mine_area_img = getMineArea(win_pos)
    # mine_map = convertImg2map(img=mine_area_img,block_x=16,block_y=16,block_width=16,block_height=16)
    # print(mine_map)
    Solver()



hrp 发表于 2021-5-23 06:50:57

支持

fumun 发表于 2021-5-23 10:40:54

确实,我装上了Minesweeper Clone 2007用不了
页: [1]
查看完整版本: 扫雷辅助