在B站发布了以前自己写的不完善的消消乐脚本,有小伙伴找我要,想要亲自体验并学习,效果https://www.bilibili.com/video/BV1hE41147VT
OK!这个可以秒消了,首先你们得装python并运行脚本,开始游戏按F5运行,程序能自动找到消消乐游戏房间的窗口pid,并秒杀,你还能调数值,比如几秒消完。
注释我都写好了,便于理解,代码如下:
import PIL.ImageGrab
import pyautogui
import win32api
import win32gui
import win32con
import time
import random
def color_hash(color):
value = ""
for i in range(5):
value += "%d,%d,%d," % (color[0], color[1], color[2])
return hash(value)
def image_hash(img):
value = ""
for i in range(5):
c = img.getpixel((i * 3, i * 3))
value += "%d,%d,%d," % (c[0], c[1], c[2])
return hash(value)
def game_area_image_to_matrix():
pos_to_image = {}
#遍历图片,并切成19*11的二维数组
for row in range(ROW_NUM):
pos_to_image[row] = {}
for col in range(COL_NUM):
grid_left = col * grid_width
grid_top = row * grid_height
grid_right = grid_left + grid_width
grid_bottom = grid_top + grid_height
grid_image = game_area_image.crop((grid_left, grid_top, grid_right, grid_bottom))
pos_to_image[row][col] = grid_image
pos_to_type_id = {}
image_map = {}
empty_hash = color_hash((48, 76, 112)) #地板的颜色
#一张图片对应一个hash值,如果是地板颜色值为0
for row in range(ROW_NUM):
pos_to_type_id[row] = {}
for col in range(COL_NUM):
this_image = pos_to_image[row][col]
this_image_hash = image_hash(this_image)
if this_image_hash == empty_hash:
pos_to_type_id[row][col] = 0
continue
image_map.setdefault(this_image_hash, len(image_map) + 1) #除了地板每个图片唯一编号
pos_to_type_id[row][col] = image_map.get(this_image_hash) #改hash值变唯一编号
return pos_to_type_id
#找到每张图片所在的位置列表之间,判断两两是否可消
def solve_matrix_one_step():
for key in map:
arr = map[key]
arr_len = len(arr)
for index1 in range(arr_len - 1):
point1 = arr[index1]
x1 = point1[0]
y1 = point1[1]
for index2 in range(index1 + 1, arr_len):
point2 = arr[index2]
x2 = point2[0]
y2 = point2[1]
if verifying_connectivity(x1, y1, x2, y2):
arr.remove(point1)
arr.remove(point2)
matrix[y1][x1] = 0
matrix[y2][x2] = 0
if arr_len == 2:
map.pop(key)
return y1, x1, y2, x2
#判断两个格子是否可连接并消除(重点)
def verifying_connectivity(x1, y1, x2, y2):
max_y1 = y1
while max_y1 + 1 < ROW_NUM and matrix[max_y1 + 1][x1] == 0: #如果第一格子不在最后一行而且他下面一个格子为空,继续往下搜
max_y1 += 1
min_y1 = y1
while min_y1 - 1 >= 0 and matrix[min_y1 - 1][x1] == 0: #如果第一格子不在最上一行而且他上面一个格子为空,继续往下搜
min_y1 -= 1
max_y2 = y2
while max_y2 + 1 < ROW_NUM and matrix[max_y2 + 1][x2] == 0: #如果第二格子不在最后一行而且他下面一个格子为空,继续往下搜
max_y2 += 1
min_y2 = y2
while min_y2 - 1 >= 0 and matrix[min_y2 - 1][x2] == 0: #如果第二格子不在最上一行而且他上面一个格子为空,继续往下搜
min_y2 -= 1
rg_min_y = max(min_y1, min_y2)
rg_max_y = min(max_y1, max_y2)
if rg_max_y >= rg_min_y:
for index_y in range(rg_min_y, rg_max_y + 1): #说明竖向有可能有连接区域
min_x = min(x1, x2)
max_x = max(x1, x2)
flag = True
for index_x in range(min_x + 1, max_x): #每一行看竖向可能连接区域是否没有格子阻挡
if matrix[index_y][index_x] != 0:
flag = False
break
if flag:
return True
#横向逻辑类似。。。
max_x1 = x1
while max_x1 + 1 < COL_NUM and matrix[y1][max_x1 + 1] == 0:
max_x1 += 1
min_x1 = x1
while min_x1 - 1 >= 0 and matrix[y1][min_x1 - 1] == 0:
min_x1 -= 1
max_x2 = x2
while max_x2 + 1 < COL_NUM and matrix[y2][max_x2 + 1] == 0:
max_x2 += 1
min_x2 = x2
while min_x2 - 1 >= 0 and matrix[y2][min_x2 - 1] == 0:
min_x2 -= 1
rg_min_x = max(min_x1, min_x2)
rg_max_x = min(max_x1, max_x2)
if rg_max_x >= rg_min_x:
for index_x in range(rg_min_x, rg_max_x + 1):
min_y = min(y1, y2)
max_y = max(y1, y2)
flag = True
for index_y in range(min_y + 1, max_y):
if matrix[index_y][index_x] != 0:
flag = False
break
if flag:
return True
return False
#判断可消就点击两个格子
def execute_one_step(one_step):
from_row, from_col, to_row, to_col = one_step
from_x = game_area_left + (from_col + 0.5) * grid_width
from_y = game_area_top + (from_row + 0.5) * grid_height
to_x = game_area_left + (to_col + 0.5) * grid_width
to_y = game_area_top + (to_row + 0.5) * grid_height
pyautogui.moveTo(from_x, from_y)
pyautogui.click()
pyautogui.moveTo(to_x, to_y)
pyautogui.click()
if __name__ == '__main__':
COL_NUM = 19 #列数
ROW_NUM = 11 #行数
screen_width = win32api.GetSystemMetrics(0) #获取屏幕宽
screen_height = win32api.GetSystemMetrics(1) #获取屏幕高
hwnd = win32gui.FindWindow(win32con.NULL, 'QQ游戏 - 连连看角色版') #获取游戏窗口
if hwnd == 0:
exit(-1) #没找到,退出
win32gui.ShowWindow(hwnd, win32con.SW_RESTORE)
win32gui.SetForegroundWindow(hwnd) #设置游戏窗口为前台窗口
window_left, window_top, window_right, window_bottom = win32gui.GetWindowRect(hwnd) #找到游戏窗口上下左右屏幕坐标
if min(window_left, window_top) < 0 or window_right > screen_width or window_bottom > screen_height:
exit(-1)
window_width = window_right - window_left #游戏窗口宽度
window_height = window_bottom - window_top #游戏窗口高度
game_area_left = window_left + 14.0 / 800.0 * window_width #游戏连连看可消区域上下左右坐标
game_area_top = window_top + 181.0 / 600.0 * window_height
game_area_right = window_left + 603 / 800.0 * window_width
game_area_bottom = window_top + 566 / 600.0 * window_height
#可消区域宽高
game_area_width = game_area_right - game_area_left
game_area_height = game_area_bottom - game_area_top
#一个格子宽高
grid_width = game_area_width / COL_NUM
grid_height = game_area_height / ROW_NUM
#获取所有格子图片
game_area_image = PIL.ImageGrab.grab((game_area_left, game_area_top, game_area_right, game_area_bottom))
#图片根据每个格子中心点rgb值转成二位数组
matrix = game_area_image_to_matrix()
map = {}
for y in range(ROW_NUM):
for x in range(COL_NUM):
grid_id = matrix[y][x]
if grid_id == 0: #0表示为那个坐标没格子
continue
map.setdefault(grid_id, []) #如果键不存在于字典中,将会添加键并将值设为默认值。
arr = map[grid_id]
arr.append([x, y]) #把key:格子图片 value:所有格子图片的坐标
pyautogui.PAUSE = 0 #开启自动化鼠标点击
while True:
one_step = solve_matrix_one_step()
if not one_step:
exit(0)
execute_one_step(one_step)
time.sleep(random.randint(0,10)/1000)