ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

QQ游戏 - 连连看角色版代码加组合和快捷键+提速-QZQ-2026-9-18

2026/10/3 17:03:21 拓冰建站 浏览量
QQ游戏 - 连连看角色版代码加组合和快捷键+提速-QZQ-2026-9-18 import time import threading import win32api import win32gui import pandas as pd import numpy as np import win32con import random import keyboard # 全局热键 # 运行控制 running False # 是否正在自动消除 stop_flag False # F2 停止标志 worker_thread None # 工作线程 def scan_game_board(hwnd, hdc): 扫描游戏棋盘返回 11x19 的颜色矩阵 try: win32gui.SetForegroundWindow(hwnd) win32gui.SetActiveWindow(hwnd) except win32gui.error as e: print(Havent open the game!, e) board_width, board_height 19, 11 array pd.DataFrame(np.zeros((board_height, board_width))) print(win32gui.GetClientRect(hwnd)) for j in range(board_width): for i in range(board_height): card_mid_width 9 j * 31 13 card_mid_height 180 i * 35 13 mid_color win32gui.GetPixel(hdc, card_mid_width, card_mid_height) if mid_color ! 7359536: array.iloc[i, j] mid_color return array # 常见组合判定相关函数 def is_empty(arr, x, y): 判断某个格子是否为空 if x 0 or y 0 or x arr.shape[1] or y arr.shape[0]: return True return arr.iloc[y, x] 0 def line_clear_h(arr, y, x1, x2): 水平方向两点之间是否全为空 if x1 x2: x1, x2 x2, x1 for x in range(x1 1, x2): if not is_empty(arr, x, y): return False return True def line_clear_v(arr, x, y1, y2): 垂直方向两点之间是否全为空 if y1 y2: y1, y2 y2, y1 for y in range(y1 1, y2): if not is_empty(arr, x, y): return False return True def can_link_direct(arr, p1, p2): 判断两点是否可以直接直线连通 y1, x1 p1 y2, x2 p2 if y1 y2: return line_clear_h(arr, y1, x1, x2) if x1 x2: return line_clear_v(arr, x1, y1, y2) return False def can_link_one_corner(arr, p1, p2): 判断两点是否可以通过一个拐点连通 y1, x1 p1 y2, x2 p2 if is_empty(arr, x2, y1): if line_clear_h(arr, y1, x1, x2) and line_clear_v(arr, x2, y1, y2): return True if is_empty(arr, x1, y2): if line_clear_v(arr, x1, y1, y2) and line_clear_h(arr, y2, x1, x2): return True return False def can_link_two_corner(arr, p1, p2): 判断两点是否可以通过两个拐点连通 y1, x1 p1 y2, x2 p2 # 水平扫描 for x in range(arr.shape[1]): if x x1 or x x2: continue if is_empty(arr, x, y1) and is_empty(arr, x, y2): if line_clear_h(arr, y1, x1, x) and line_clear_v(arr, x, y1, y2) and line_clear_h(arr, y2, x, x2): return True # 垂直扫描 for y in range(arr.shape[0]): if y y1 or y y2: continue if is_empty(arr, x1, y) and is_empty(arr, x2, y): if line_clear_v(arr, x1, y1, y) and line_clear_h(arr, y, x1, x2) and line_clear_v(arr, x2, y, y2): return True return False def can_link(arr, p1, p2): 综合判断两个格子是否可以消除 if p1 p2: return False if arr.iloc[p1[0], p1[1]] 0 or arr.iloc[p2[0], p2[1]] 0: return False if arr.iloc[p1[0], p1[1]] ! arr.iloc[p2[0], p2[1]]: return False return ( can_link_direct(arr, p1, p2) or can_link_one_corner(arr, p1, p2) or can_link_two_corner(arr, p1, p2) ) def find_common_combinations(arr, new_arrs): 找出常见组合 1. 相邻 2. 同行同列 3. 一个拐点 4. 两个拐点 返回可直接点击的组合列表 [(p1, p2), ...] common_pairs [] for new_arr in new_arrs: for i in range(len(new_arr)): for j in range(i 1, len(new_arr)): p1 tuple(new_arr[i]) p2 tuple(new_arr[j]) if can_link(arr, p1, p2): common_pairs.append((p1, p2)) return common_pairs # 主逻辑封装 def auto_play(): global stop_flag hd win32gui.FindWindow(None, QQ游戏 - 连连看角色版) if hd 0: print(找不到游戏窗口请先打开 QQ 连连看。) return # 把窗口置前 try: win32gui.SetForegroundWindow(hd) win32gui.SetActiveWindow(hd) except win32gui.error as e: print(窗口置前失败, e) hdc win32gui.GetWindowDC(hd) try: arr scan_game_board(hd, hdc) print(初始数组\n, arr) # 找出重复出现的元素 unique_nums np.unique(arr) unique_nums unique_nums[unique_nums ! 0] same_nums [] for num in unique_nums: if np.count_nonzero(arr num) 1: same_nums.append(num) new_arrs [] for num in same_nums: new_arr np.argwhere(arr num) new_arrs.append(new_arr) print(new_arrs) # 优先尝试常见组合 common_pairs find_common_combinations(arr, new_arrs) print(常见可消除组合, common_pairs) for p1, p2 in common_pairs: if stop_flag: print(收到 F2 停止信号退出。) return y1, x1 p1 y2, x2 p2 x 9 x1 * 31 13 y 180 y1 * 35 13 x1_px 9 x2 * 31 13 y1_px 180 y2 * 35 13 print(p1, p2) l_param win32api.MAKELONG(x, y) win32api.SendMessage(hd, win32con.WM_LBUTTONDOWN, win32con.MK_LBUTTON, l_param) win32api.SendMessage(hd, win32con.WM_LBUTTONUP, 0, l_param) l_param1 win32api.MAKELONG(x1_px, y1_px) win32api.SendMessage(hd, win32con.WM_LBUTTONDOWN, win32con.MK_LBUTTON, l_param1) win32api.SendMessage(hd, win32con.WM_LBUTTONUP, 0, l_param1) time.sleep(0.0 / (1 1) * random.randint(0, 1)) # 原有暴力点击逻辑保持不变 for k in range(8): if stop_flag: print(收到 F2 停止信号退出。) return for new_arr in new_arrs: if stop_flag: print(收到 F2 停止信号退出。) return for i in range(len(new_arr)): for j in range(i 1, len(new_arr)): if stop_flag: print(收到 F2 停止信号退出。) return print(new_arr[i], new_arr[j]) x 9 new_arr[i][1] * 31 13 y 180 new_arr[i][0] * 35 13 x1 9 new_arr[j][1] * 31 13 y1 180 new_arr[j][0] * 35 13 l_param win32api.MAKELONG(x, y) win32api.SendMessage(hd, win32con.WM_LBUTTONDOWN, win32con.MK_LBUTTON, l_param) win32api.SendMessage(hd, win32con.WM_LBUTTONUP, 0, l_param) l_param1 win32api.MAKELONG(x1, y1) win32api.SendMessage(hd, win32con.WM_LBUTTONDOWN, win32con.MK_LBUTTON, l_param1) win32api.SendMessage(hd, win32con.WM_LBUTTONUP, 0, l_param1) time.sleep(0.0 / (i 1) * random.randint(0, 1)) finally: # 释放 DC避免 GDI 资源泄漏 try: win32gui.ReleaseDC(hd, hdc) except Exception: pass # 热键控制逻辑 def start_worker(): global running, stop_flag, worker_thread if running: print(已经在运行中忽略 F1。) return stop_flag False running True print(F1开始执行自动消除。) worker_thread threading.Thread(targetrun_wrapper, daemonTrue) worker_thread.start() def run_wrapper(): global running, stop_flag try: auto_play() except Exception as e: print(执行出错, e) finally: running False stop_flag False print(任务结束按 F1 可重新开始。) def stop_worker(): global stop_flag, running if not running: print(当前没有任务在运行。) return stop_flag True print(F2已发出停止信号将在当前点击后退出。) def main(): print(连连看自动脚本已启动。) print( F1 - 开始执行) print( F2 - 停止执行) print( CtrlC - 退出程序) keyboard.add_hotkey(f1, start_worker) keyboard.add_hotkey(f2, stop_worker) try: keyboard.wait() except KeyboardInterrupt: print(已退出。) if __name__ __main__: main()