Bejeweled 3 经典模式 —— 穷举暴力试错版 v4(真零延迟)

发布时间:2026/11/6 1:38:46

Bejeweled 3 经典模式 —— 穷举暴力试错版 v4(真零延迟) # -*- coding: utf-8 -*- Bejeweled 3 经典模式 —— 穷举暴力试错版 v4真·零延迟 -------------------------------------------------------------------- Bejeweled 3 / 宝石迷阵3CHS 中文版 改动 ✓ pyautogui.PAUSE 0 ✓ 只截两格不截整屏 ✓ 优先用 mss 截屏快 5~10 倍 ✓ 预览降频到 200ms可关闭 ✓ 日志批量写 ✓ 每圈保证 112 对全部尝试 import os import json import time import threading import numpy as np import cv2 import pyautogui from PIL import Image, ImageTk import tkinter as tk from tkinter import ttk # ★ 零延迟关键 pyautogui.PAUSE 0 pyautogui.FAILSAFE False # ★ 优先用 mss 截屏 try: import mss _SCT mss.mss() HAS_MSS True except ImportError: HAS_MSS False try: import keyboard HAS_KEYBOARD True except ImportError: HAS_KEYBOARD False print([警告] 未安装 keyboard 库F1/F2 热键不可用。请运行: pip install keyboard) # 常量 BOARD_W 8 BOARD_H 8 DEFAULT_GEM_SIZE 101 BASE_DIR os.path.dirname(os.path.abspath(__file__)) CONFIG_PATH os.path.join(BASE_DIR, bej3_bf_config.json) DEFAULT_CONFIG { window_left: 0, window_top: 0, capture_width: 900, capture_height: 984, board_w: BOARD_W, board_h: BOARD_H, gem_size: DEFAULT_GEM_SIZE, x_margin: -1, y_margin: -1, hash_threshold: 6, bad_move_cooldown: 3.0, show_preview: True, } # 配置 def load_config(): if os.path.exists(CONFIG_PATH): try: with open(CONFIG_PATH, r, encodingutf-8) as f: c json.load(f) c[board_w] BOARD_W c[board_h] BOARD_H return {**DEFAULT_CONFIG, **c} except Exception: pass return dict(DEFAULT_CONFIG) def save_config(cfg): with open(CONFIG_PATH, w, encodingutf-8) as f: json.dump(cfg, f, indent2, ensure_asciiFalse) def get_margins(cfg): gs cfg[gem_size] xm cfg[x_margin] if cfg[x_margin] 0 else int((cfg[capture_width] - gs * cfg[board_w]) / 2) ym cfg[y_margin] if cfg[y_margin] 0 else int((cfg[capture_height] - gs * cfg[board_h]) / 2) return xm, ym def grab_window(cfg): 整屏截图预览用 region (int(cfg[window_left]), int(cfg[window_top]), cfg[capture_width], cfg[capture_height]) if HAS_MSS: mon {left: region[0], top: region[1], width: region[2], height: region[3]} img np.array(_SCT.grab(mon)) return cv2.cvtColor(img, cv2.COLOR_BGRA2BGR) return cv2.cvtColor(np.array(pyautogui.screenshot(regionregion)), cv2.COLOR_RGB2BGR) def grab_cell(cfg, x, y): ★ 只截一格速度极快 xm, ym get_margins(cfg) gs cfg[gem_size] px int(cfg[window_left]) xm x * gs py int(cfg[window_top]) ym y * gs if HAS_MSS: mon {left: px, top: py, width: gs, height: gs} img np.array(_SCT.grab(mon)) return cv2.cvtColor(img, cv2.COLOR_BGRA2BGR) return cv2.cvtColor(np.array(pyautogui.screenshot(region(px, py, gs, gs))), cv2.COLOR_RGB2BGR) def cell_center(cfg, x, y): xm, ym get_margins(cfg) gs cfg[gem_size] return (int(cfg[window_left]) xm x * gs gs // 2, int(cfg[window_top]) ym y * gs gs // 2) def cell_phash_from_crop(crop): 从小图直接算 64bit 哈希 if crop is None or crop.size 0: return None small cv2.resize(crop, (16, 16), interpolationcv2.INTER_AREA) gray cv2.cvtColor(small, cv2.COLOR_BGR2GRAY) flat gray.flatten() return np.packbits(flat flat.mean()) def cell_diff(h1, h2): return 999 if (h1 is None or h2 is None) else int((h1 ! h2).sum()) def all_adjacent_pairs(bw, bh): pairs [] for y in range(bh): for x in range(bw - 1): pairs.append((x, y, x 1, y)) for x in range(bw): for y in range(bh - 1): pairs.append((x, y, x, y 1)) return pairs # tkinter GUI class AutoGUI: def __init__(self, root, cfg): self.root root self.cfg cfg self.running False self.thread None self.photo None self.last_try None self.last_good False self._log_buf [] self._log_lock threading.Lock() root.title(Bejeweled 3 暴力试错版 v4真零延迟 [F1开始 F2停止]) root.resizable(False, False) left ttk.Frame(root, padding8) left.grid(row0, column0, stickyn) ttk.Label(left, text实时画面 棋盘网格绿合法 红被弹回 白正在试, font(Microsoft YaHei, 10)).grid(row0, column0, pady(0, 4)) self.canvas tk.Canvas(left, widthcfg[capture_width], heightcfg[capture_height], bgblack, highlightthickness1, highlightbackground#888) self.canvas.grid(row1, column0) right ttk.Frame(root, padding8) right.grid(row0, column1, stickyn) row 0 ttk.Label(right, text【窗口位置】, font(Microsoft YaHei, 10, bold) ).grid(rowrow, column0, columnspan2, stickyw) row 1 self.var_x tk.IntVar(valuecfg[window_left]) self.var_y tk.IntVar(valuecfg[window_top]) row self._add_slider(right, row, 窗口 X 偏移, self.var_x, -2000, 2000, lambda v: cfg.update(window_leftint(float(v))), fmt%d) row self._add_slider(right, row, 窗口 Y 偏移, self.var_y, -2000, 2000, lambda v: cfg.update(window_topint(float(v))), fmt%d) ttk.Label(right, text【网格 / 边距】, font(Microsoft YaHei, 10, bold) ).grid(rowrow, column0, columnspan2, stickyw, pady(8, 0)) row 1 ttk.Label(right, textf棋盘: {cfg[board_w]} 列 × {cfg[board_h]} 行 (固定 8×8) ).grid(rowrow, column0, columnspan2, stickyw) row 1 self.var_gem tk.IntVar(valuecfg[gem_size]) row self._add_slider(right, row, 每格像素, self.var_gem, 16, 200, lambda v: cfg.update(gem_sizeint(float(v))), fmt%d) self.var_xm tk.IntVar(valuecfg[x_margin]) row self._add_slider(right, row, 水平边距(-1自动), self.var_xm, -1, 500, lambda v: cfg.update(x_marginint(float(v))), fmt%d) self.var_ym tk.IntVar(valuecfg[y_margin]) row self._add_slider(right, row, 垂直边距(-1自动), self.var_ym, -1, 500, lambda v: cfg.update(y_marginint(float(v))), fmt%d) ttk.Label(right, text【判定】, font(Microsoft YaHei, 10, bold) ).grid(rowrow, column0, columnspan2, stickyw, pady(8, 0)) row 1 self.var_ht tk.IntVar(valuecfg[hash_threshold]) row self._add_slider(right, row, 哈希阈值(大更松), self.var_ht, 2, 40, lambda v: cfg.update(hash_thresholdint(float(v))), fmt%d) self.var_show tk.BooleanVar(valuecfg.get(show_preview, True)) ttk.Checkbutton(right, text显示实时画面网格, variableself.var_show, commandlambda: cfg.update(show_previewself.var_show.get()) ).grid(rowrow, column0, columnspan2, stickyw) row 1 btns ttk.Frame(right) btns.grid(rowrow, column0, columnspan2, pady(10, 4), stickyew) row 1 ttk.Button(btns, text鼠标校准, commandself.calibrate).grid(row0, column0, padx2, stickyew) ttk.Button(btns, text保存配置, commandself.save).grid(row0, column1, padx2, stickyew) ttk.Button(btns, text重置 0,0, commandself.reset_pos).grid(row1, column0, padx2, stickyew) ttk.Button(btns, text退出, commandself.quit).grid(row1, column1, padx2, stickyew) btns.columnconfigure(0, weight1) btns.columnconfigure(1, weight1) self.btn_start ttk.Button(right, text▶ 开始暴力试错 (F1), commandself.toggle_run) self.btn_start.grid(rowrow, column0, columnspan2, pady(8, 4), stickyew) row 1 self.lbl_status ttk.Label(right, text就绪 | F1开始 F2停止, foreground#080, font(Microsoft YaHei, 10)) self.lbl_status.grid(rowrow, column0, columnspan2, stickyw) row 1 self.txt_log tk.Text(right, width44, height13, font(Consolas, 9)) self.txt_log.grid(rowrow, column0, columnspan2, stickyew) self.txt_log.configure(statedisabled) self._setup_hotkeys() self.refresh_preview() self._flush_log_periodic() def _setup_hotkeys(self): if not HAS_KEYBOARD: self.log([提示] 未安装 keyboard热键不可用) return try: keyboard.add_hotkey(f1, lambda: self.root.after(0, self._start_run), suppressFalse) keyboard.add_hotkey(f2, lambda: self.root.after(0, self._stop_run), suppressFalse) self.log([热键] F1开始 F2停止) except Exception as e: self.log(f[热键注册失败] {e}) def _start_run(self): if self.running: return self.running True self.btn_start.config(text■ 停止 (F2)) self.lbl_status.config(text暴力运行中真零延迟, foreground#080) self.log([开始] 穷举暴力试错已启动) self.thread threading.Thread(targetself.worker, daemonTrue) self.thread.start() def _stop_run(self): if not self.running: return self.running False self.btn_start.config(text▶ 开始暴力试错 (F1)) self.lbl_status.config(text已停止, foreground#c00) self.log([停止] 已停止) def _add_slider(self, parent, row, label, var, from_, to_, cmd, fmt%d): ttk.Label(parent, textlabel).grid(rowrow, column0, columnspan2, stickyw) row 1 s ttk.Scale(parent, from_from_, toto_, orienthorizontal, length280) s.set(var.get()) lbl ttk.Label(parent, textfmt % var.get(), width8) s.grid(rowrow, column0, stickyew) lbl.grid(rowrow, column1, stickyw) s._fmt fmt s._label lbl s._var var s._cmd cmd s.configure(commandlambda v, scales: self._on_slider(v, scale)) row 1 return row def _on_slider(self, v, scale): fmt scale._fmt var scale._var if fmt %d: var.set(int(float(v))) else: var.set(round(float(v), 2)) scale._label.config(textfmt % var.get()) if scale._cmd: scale._cmd(v) def refresh_preview(self): try: if self.cfg.get(show_preview, True): frame grab_window(self.cfg) vis frame.copy() xm, ym get_margins(self.cfg) gs self.cfg[gem_size] bw, bh self.cfg[board_w], self.cfg[board_h] for x in range(bw 1): px xm x * gs cv2.line(vis, (px, ym), (px, ym bh * gs), (255, 255, 255), 1) for y in range(bh 1): py ym y * gs cv2.line(vis, (xm, py), (xm bw * gs, py), (255, 255, 255), 1) if self.last_try is not None: x1, y1, x2, y2 self.last_try color (0, 230, 0) if self.last_good else (0, 0, 230) for (cx, cy) in ((x1, y1), (x2, y2)): px, py xm cx * gs, ym cy * gs cv2.rectangle(vis, (px 1, py 1), (px gs - 2, py gs - 2), color, 3) self.photo ImageTk.PhotoImage( Image.fromarray(cv2.cvtColor(vis, cv2.COLOR_BGR2RGB))) self.canvas.delete(all) self.canvas.create_image(0, 0, anchornw, imageself.photo) except Exception as e: self.log(f[预览错误] {e}) self.root.after(200, self.refresh_preview) # ★ 60ms → 200ms def calibrate(self): self.log(1 秒内把鼠标移到游戏棋盘【左上角第一格的中心】...) self.root.update() pos pyautogui.position() gs self.cfg[gem_size] xm, ym get_margins(self.cfg) self.cfg[window_left] pos.x - xm - gs // 2 self.cfg[window_top] pos.y - ym - gs // 2 self.var_x.set(self.cfg[window_left]) self.var_y.set(self.cfg[window_top]) self.log(f校准完成窗口左上角 ({self.cfg[window_left]}, {self.cfg[window_top]})) def reset_pos(self): self.var_x.set(0) self.var_y.set(0) self.cfg[window_left] 0 self.cfg[window_top] 0 def save(self): save_config(self.cfg) self.log(配置已保存) def toggle_run(self): if self.running: self._stop_run() else: self._start_run() # 暴力主循环真零延迟 def worker(self): pairs all_adjacent_pairs(self.cfg[board_w], self.cfg[board_h]) n len(pairs) bad_moves {} idx 0 total_tried 0 total_good 0 total_bad 0 lap 0 # ★ 预计算所有格子中心坐标省去循环内重复计算 centers {} for (x1, y1, x2, y2) in pairs: centers[(x1, y1)] cell_center(self.cfg, x1, y1) centers[(x2, y2)] cell_center(self.cfg, x2, y2) while self.running: try: now time.time() # 黑名单老化 if len(bad_moves) n * 0.6: old now - self.cfg[bad_move_cooldown] * 0.6 bad_moves {k: v for k, v in bad_moves.items() if v old} # ★ 每圈结束不清空黑名单只老化保证下一圈全试 if idx n: idx 0 lap 1 self.log(f[第 {lap} 圈] 尝试 {total_tried} | f合法 {total_good} | 被弹回 {total_bad}) # 不再 sleep纯忙循环 x1, y1, x2, y2 pairs[idx] key (x1, y1, x2, y2) idx 1 # if key in bad_moves: # continue # 1) 只截两格关键提速 c1 grab_cell(self.cfg, x1, y1) c2 grab_cell(self.cfg, x2, y2) h1a cell_phash_from_crop(c1) h1b cell_phash_from_crop(c2) # 2) 交换零延迟 p1 centers[(x1, y1)] p2 centers[(x2, y2)] pyautogui.moveTo(p1[0], p1[1], duration0) pyautogui.mouseDown() pyautogui.moveTo(p2[0], p2[1], duration0) pyautogui.mouseUp() # 3) 立刻再截两格判定 c1b grab_cell(self.cfg, x1, y1) c2b grab_cell(self.cfg, x2, y2) h2a cell_phash_from_crop(c1b) h2b cell_phash_from_crop(c2b) diff cell_diff(h1a, h2a) cell_diff(h1b, h2b) total_tried 1 good diff self.cfg[hash_threshold] self.last_try (x1, y1, x2, y2) self.last_good good if good: total_good 1 self.log(f ✓ ({x1},{y1})-({x2},{y2}) 累计 {total_good}) else: total_bad 1 # bad_moves[key] now self.cfg[bad_move_cooldown] if total_tried % 50 0: self.log(f[统计] 尝试 {total_tried} | 合法 {total_good} | f弹回 {total_bad} | 有效率 {total_good/total_tried*100:.0f}%) except Exception as e: self.log(f[异常] {e}) # ★ 日志批量写避免 Tk 锁竞争 def log(self, msg): with self._log_lock: self._log_buf.append(msg) def _flush_log_periodic(self): try: with self._log_lock: if self._log_buf: lines self._log_buf[:] self._log_buf.clear() self.txt_log.configure(statenormal) for m in lines: self.txt_log.insert(end, m \n) self.txt_log.see(end) self.txt_log.configure(statedisabled) except Exception: pass self.root.after(200, self._flush_log_periodic) def quit(self): self.running False if HAS_KEYBOARD: try: keyboard.remove_all_hotkeys() except Exception: pass self.root.after(200, self.root.destroy) # main def main(): print( * 64) print(Bejeweled 3 经典模式 —— 穷举暴力试错版 v4真零延迟) print( mss 截屏:, 已启用 if HAS_MSS else 未安装pip install mss 可再快 5~10 倍) print( 热键F1 开始 F2 停止) print( * 64) cfg load_config() root tk.Tk() AutoGUI(root, cfg) root.mainloop() if __name__ __main__: main()python-宝石迷阵3CHS 中文版-Bejeweled 3 经典模式游戏自动化脚本源代码.ziphttps://download.csdn.net/download/qq_32257509/93805601
延伸阅读

更多相关文章

2026/11/6 1:38:46

python语言-连连看3.2修改器代码QZQ

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/11/6 1:38:46

python语言-连连看v4.92修改器代码QZQ-2026-9-19

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/11/6 1:38:46

Bejeweled 3 经典模式 —— 穷举暴力试错版 v4(真零延迟)

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/11/6 1:38:46

python语言-连连看3.2修改器代码QZQ

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/11/6 1:38:46

python语言-连连看v4.92修改器代码QZQ-2026-9-19

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/11/6 1:33:46

6步走通 lego 开源贡献:ACME 证书客户端的参与开发指南

6步走通 lego 开源贡献:ACME 证书客户端的参与开发指南 【免费下载链接】lego Lets Encrypt/ACME client and library written in Go 项目地址: https://gitcode.com/gh_mirrors/le/lego lego 是一个用 Go 编写的 ACME 客户端与库,帮你的站点自动…

2026/11/5 15:39:06

面向复杂光照与角度的宠物面部识别鲁棒性增强策略

在智慧养宠时代,基于视觉的宠物身份识别技术正逐步从实验室走向家庭应用。然而,与配合度高的人类不同,宠物是典型的“非合作生物识别对象”——它们不会主动配合摄像头调整姿态,更无法控制光照环境。实际应用中,我们常…

2026/11/4 21:04:25

SSM电子书店源码全解析:结构、原理、部署与排错实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/11/6 1:03:39

MCU晶振电路设计全解析:从负载电容计算到PCB布局调试

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/11/5 15:39:06

面向复杂光照与角度的宠物面部识别鲁棒性增强策略

在智慧养宠时代,基于视觉的宠物身份识别技术正逐步从实验室走向家庭应用。然而,与配合度高的人类不同,宠物是典型的“非合作生物识别对象”——它们不会主动配合摄像头调整姿态,更无法控制光照环境。实际应用中,我们常…

2026/11/4 21:04:25

SSM电子书店源码全解析:结构、原理、部署与排错实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑