PyAutoGUI实战用Python打造《扫雷》自动解谜AIWindows自带的《扫雷》游戏是许多人童年的记忆。这款看似简单的游戏背后隐藏着严谨的逻辑推理恰好为编程爱好者提供了一个绝佳的练手项目。今天我们将使用Python的PyAutoGUI库从零开始构建一个能自动玩《扫雷》的AI脚本。这不仅是图像识别和自动化控制的完美结合更是一次逻辑思维的编程实践。1. 环境准备与基础配置在开始编写扫雷AI之前我们需要确保开发环境配置正确。PyAutoGUI是一个跨平台的GUI自动化库支持Windows、macOS和Linux系统。安装过程非常简单pip install pyautogui opencv-python numpy pillow安装完成后建议先测试PyAutoGUI的基本功能是否正常工作。创建一个简单的测试脚本import pyautogui print(pyautogui.size()) # 获取屏幕分辨率 pyautogui.moveTo(100, 100, duration1) # 移动鼠标到(100,100)位置注意PyAutoGUI的坐标系统以屏幕左上角为原点(0,0)x轴向右增加y轴向下增加。为了确保脚本能准确识别扫雷窗口我们需要先确定游戏窗口的位置和大小。最简单的方法是使用PyAutoGUI的截图功能# 获取游戏窗口截图 game_window pyautogui.screenshot(region(x, y, width, height))2. 游戏界面识别技术扫雷游戏的核心识别任务包括数字识别、未点击方块识别和旗帜标记识别。PyAutoGUI提供了强大的图像识别功能我们可以利用locateOnScreen()方法来实现这些功能。2.1 数字模板准备首先我们需要为每个数字(1-8)创建模板图像。这些模板将用于后续的图像匹配截取游戏中数字1-8的清晰图像样本使用图像编辑工具裁剪出单个数字保存为png格式命名如1.png, 2.png等# 数字识别函数示例 def recognize_number(image): numbers [1, 2, 3, 4, 5, 6, 7, 8] for num in numbers: template ftemplates/{num}.png location pyautogui.locate(template, image, confidence0.9) if location: return int(num) return None2.2 游戏状态分析扫雷游戏界面由多个方块组成每个方块可能处于以下状态之一状态类型描述识别方法未点击灰色方块颜色匹配已点击显示数字或空白数字识别旗帜小红旗标记图像匹配地雷游戏结束时显示图像匹配为了提高识别准确率我们可以结合多种方法def get_cell_state(cell_image): # 检查是否为旗帜 if pyautogui.locate(flag_template.png, cell_image, confidence0.85): return flag # 检查是否为未点击方块 if is_unopened(cell_image): return unopened # 尝试识别数字 number recognize_number(cell_image) if number is not None: return str(number) # 空白方块 return empty3. 游戏逻辑与AI策略有了基本的识别能力后我们需要为AI设计游戏策略。扫雷的核心逻辑是根据已知数字推断周围方块的安全性。3.1 基础安全判断最简单的策略是寻找绝对安全的点击如果一个已打开的数字方块周围恰好有相应数量的旗帜则剩余未点击的方块一定是安全的如果一个数字等于其周围未点击方块的数量则所有这些方块都必须是地雷def find_safe_clicks(board): safe_clicks [] for y in range(board.height): for x in range(board.width): cell board.get_cell(x, y) if cell.isdigit(): number int(cell) neighbors board.get_neighbors(x, y) flagged sum(1 for n in neighbors if n.state flag) unopened [n for n in neighbors if n.state unopened] # 规则1数字等于周围旗帜数剩余未点击是安全的 if number flagged and unopened: safe_clicks.extend(unopened) # 规则2数字等于未点击数所有未点击都是地雷 if number - flagged len(unopened) and unopened: for cell in unopened: cell.mark_as_mine() return safe_clicks3.2 高级概率分析对于更复杂的情况我们可以引入概率计算计算每个未点击方块成为地雷的概率选择概率最低的方块进行点击def calculate_probabilities(board): probabilities {} unopened_cells [cell for row in board.cells for cell in row if cell.state unopened] for cell in unopened_cells: # 获取所有影响此方块的数字单元格 influencing_numbers get_influencing_numbers(cell, board) if not influencing_numbers: probabilities[cell] 0.2 # 默认概率 continue # 基于约束条件计算概率 total_mines sum(int(num) for num in influencing_numbers) flagged sum(1 for num in influencing_numbers if num.flagged_neighbors) remaining_mines total_mines - flagged possible_locations sum(1 for num in influencing_numbers for neighbor in num.neighbors if neighbor.state unopened) if possible_locations 0: probabilities[cell] remaining_mines / possible_locations else: probabilities[cell] 0 return probabilities4. 脚本实现与优化将上述组件整合成一个完整的自动化脚本需要考虑执行效率、错误处理和用户交互。4.1 主循环结构def main(): initialize_game() # 确保游戏在正确位置启动 while not game_over(): try: # 获取当前游戏状态 board capture_game_board() # 寻找安全点击 safe_clicks find_safe_clicks(board) if safe_clicks: for cell in safe_clicks: click_cell(cell) continue # 如果没有确定的安全点击使用概率分析 probabilities calculate_probabilities(board) if probabilities: safest min(probabilities.items(), keylambda x: x[1])[0] click_cell(safest) continue # 没有可用策略随机点击 random_click(board) except Exception as e: handle_error(e) break4.2 性能优化技巧局部截图只截取游戏区域而非整个屏幕缓存机制记住已识别的方块状态减少重复识别多线程处理将图像识别和逻辑计算分离到不同线程失败恢复检测游戏失败/胜利状态并相应处理# 优化后的截图函数 def capture_game_board(): if not hasattr(capture_game_board, last_board): # 首次运行截取整个游戏区域 full_image pyautogui.screenshot(regionGAME_REGION) board analyze_full_image(full_image) capture_game_board.last_board board return board else: # 增量更新只检查可能变化的区域 changed_cells find_changed_cells(capture_game_board.last_board) for cell in changed_cells: cell_image pyautogui.screenshot(regionget_cell_region(cell)) cell.state get_cell_state(cell_image) return capture_game_board.last_board5. 进阶功能与扩展思路一个完整的扫雷AI还可以加入更多智能功能和用户体验改进。5.1 学习与适应机制通过记录游戏历史AI可以学习玩家的习惯或调整自己的策略class LearningAI: def __init__(self): self.memory {} # 存储位置模式及其结果 def remember_pattern(self, pattern, was_mine): if pattern not in self.memory: self.memory[pattern] {mines: 0, safe: 0} if was_mine: self.memory[pattern][mines] 1 else: self.memory[pattern][safe] 1 def predict_from_memory(self, pattern): if pattern in self.memory: stats self.memory[pattern] total stats[mines] stats[safe] return stats[mines] / total return None5.2 可视化调试界面为帮助调试和理解AI的决策过程可以添加可视化功能def draw_analysis_overlay(board, probabilities): # 创建一个透明覆盖层 overlay Image.new(RGBA, (board.width*CELL_SIZE, board.height*CELL_SIZE), (0,0,0,0)) draw ImageDraw.Draw(overlay) # 为每个方块绘制概率 for y in range(board.height): for x in range(board.width): cell board.get_cell(x, y) if cell.state unopened and cell in probabilities: prob probabilities[cell] color (255, int(255*(1-prob)), int(255*(1-prob)), 150) draw.rectangle([x*CELL_SIZE, y*CELL_SIZE, (x1)*CELL_SIZE, (y1)*CELL_SIZE], fillcolor) text f{prob:.0%} draw.text((x*CELL_SIZE5, y*CELL_SIZE5), text, fill(0,0,0,255)) # 显示覆盖层 overlay.show()在实际项目中我发现最难处理的是游戏速度的适应性。不同电脑上扫雷的动画速度可能不同需要仔细调整点击间隔。一个实用的技巧是开始时进行几次测试点击测量动画完成的时间然后基于这个时间设置合理的延迟参数。
PyAutoGUI实战:用Python写个游戏外挂?不,我们来做个自动玩《扫雷》的AI脚本
PyAutoGUI实战用Python打造《扫雷》自动解谜AIWindows自带的《扫雷》游戏是许多人童年的记忆。这款看似简单的游戏背后隐藏着严谨的逻辑推理恰好为编程爱好者提供了一个绝佳的练手项目。今天我们将使用Python的PyAutoGUI库从零开始构建一个能自动玩《扫雷》的AI脚本。这不仅是图像识别和自动化控制的完美结合更是一次逻辑思维的编程实践。1. 环境准备与基础配置在开始编写扫雷AI之前我们需要确保开发环境配置正确。PyAutoGUI是一个跨平台的GUI自动化库支持Windows、macOS和Linux系统。安装过程非常简单pip install pyautogui opencv-python numpy pillow安装完成后建议先测试PyAutoGUI的基本功能是否正常工作。创建一个简单的测试脚本import pyautogui print(pyautogui.size()) # 获取屏幕分辨率 pyautogui.moveTo(100, 100, duration1) # 移动鼠标到(100,100)位置注意PyAutoGUI的坐标系统以屏幕左上角为原点(0,0)x轴向右增加y轴向下增加。为了确保脚本能准确识别扫雷窗口我们需要先确定游戏窗口的位置和大小。最简单的方法是使用PyAutoGUI的截图功能# 获取游戏窗口截图 game_window pyautogui.screenshot(region(x, y, width, height))2. 游戏界面识别技术扫雷游戏的核心识别任务包括数字识别、未点击方块识别和旗帜标记识别。PyAutoGUI提供了强大的图像识别功能我们可以利用locateOnScreen()方法来实现这些功能。2.1 数字模板准备首先我们需要为每个数字(1-8)创建模板图像。这些模板将用于后续的图像匹配截取游戏中数字1-8的清晰图像样本使用图像编辑工具裁剪出单个数字保存为png格式命名如1.png, 2.png等# 数字识别函数示例 def recognize_number(image): numbers [1, 2, 3, 4, 5, 6, 7, 8] for num in numbers: template ftemplates/{num}.png location pyautogui.locate(template, image, confidence0.9) if location: return int(num) return None2.2 游戏状态分析扫雷游戏界面由多个方块组成每个方块可能处于以下状态之一状态类型描述识别方法未点击灰色方块颜色匹配已点击显示数字或空白数字识别旗帜小红旗标记图像匹配地雷游戏结束时显示图像匹配为了提高识别准确率我们可以结合多种方法def get_cell_state(cell_image): # 检查是否为旗帜 if pyautogui.locate(flag_template.png, cell_image, confidence0.85): return flag # 检查是否为未点击方块 if is_unopened(cell_image): return unopened # 尝试识别数字 number recognize_number(cell_image) if number is not None: return str(number) # 空白方块 return empty3. 游戏逻辑与AI策略有了基本的识别能力后我们需要为AI设计游戏策略。扫雷的核心逻辑是根据已知数字推断周围方块的安全性。3.1 基础安全判断最简单的策略是寻找绝对安全的点击如果一个已打开的数字方块周围恰好有相应数量的旗帜则剩余未点击的方块一定是安全的如果一个数字等于其周围未点击方块的数量则所有这些方块都必须是地雷def find_safe_clicks(board): safe_clicks [] for y in range(board.height): for x in range(board.width): cell board.get_cell(x, y) if cell.isdigit(): number int(cell) neighbors board.get_neighbors(x, y) flagged sum(1 for n in neighbors if n.state flag) unopened [n for n in neighbors if n.state unopened] # 规则1数字等于周围旗帜数剩余未点击是安全的 if number flagged and unopened: safe_clicks.extend(unopened) # 规则2数字等于未点击数所有未点击都是地雷 if number - flagged len(unopened) and unopened: for cell in unopened: cell.mark_as_mine() return safe_clicks3.2 高级概率分析对于更复杂的情况我们可以引入概率计算计算每个未点击方块成为地雷的概率选择概率最低的方块进行点击def calculate_probabilities(board): probabilities {} unopened_cells [cell for row in board.cells for cell in row if cell.state unopened] for cell in unopened_cells: # 获取所有影响此方块的数字单元格 influencing_numbers get_influencing_numbers(cell, board) if not influencing_numbers: probabilities[cell] 0.2 # 默认概率 continue # 基于约束条件计算概率 total_mines sum(int(num) for num in influencing_numbers) flagged sum(1 for num in influencing_numbers if num.flagged_neighbors) remaining_mines total_mines - flagged possible_locations sum(1 for num in influencing_numbers for neighbor in num.neighbors if neighbor.state unopened) if possible_locations 0: probabilities[cell] remaining_mines / possible_locations else: probabilities[cell] 0 return probabilities4. 脚本实现与优化将上述组件整合成一个完整的自动化脚本需要考虑执行效率、错误处理和用户交互。4.1 主循环结构def main(): initialize_game() # 确保游戏在正确位置启动 while not game_over(): try: # 获取当前游戏状态 board capture_game_board() # 寻找安全点击 safe_clicks find_safe_clicks(board) if safe_clicks: for cell in safe_clicks: click_cell(cell) continue # 如果没有确定的安全点击使用概率分析 probabilities calculate_probabilities(board) if probabilities: safest min(probabilities.items(), keylambda x: x[1])[0] click_cell(safest) continue # 没有可用策略随机点击 random_click(board) except Exception as e: handle_error(e) break4.2 性能优化技巧局部截图只截取游戏区域而非整个屏幕缓存机制记住已识别的方块状态减少重复识别多线程处理将图像识别和逻辑计算分离到不同线程失败恢复检测游戏失败/胜利状态并相应处理# 优化后的截图函数 def capture_game_board(): if not hasattr(capture_game_board, last_board): # 首次运行截取整个游戏区域 full_image pyautogui.screenshot(regionGAME_REGION) board analyze_full_image(full_image) capture_game_board.last_board board return board else: # 增量更新只检查可能变化的区域 changed_cells find_changed_cells(capture_game_board.last_board) for cell in changed_cells: cell_image pyautogui.screenshot(regionget_cell_region(cell)) cell.state get_cell_state(cell_image) return capture_game_board.last_board5. 进阶功能与扩展思路一个完整的扫雷AI还可以加入更多智能功能和用户体验改进。5.1 学习与适应机制通过记录游戏历史AI可以学习玩家的习惯或调整自己的策略class LearningAI: def __init__(self): self.memory {} # 存储位置模式及其结果 def remember_pattern(self, pattern, was_mine): if pattern not in self.memory: self.memory[pattern] {mines: 0, safe: 0} if was_mine: self.memory[pattern][mines] 1 else: self.memory[pattern][safe] 1 def predict_from_memory(self, pattern): if pattern in self.memory: stats self.memory[pattern] total stats[mines] stats[safe] return stats[mines] / total return None5.2 可视化调试界面为帮助调试和理解AI的决策过程可以添加可视化功能def draw_analysis_overlay(board, probabilities): # 创建一个透明覆盖层 overlay Image.new(RGBA, (board.width*CELL_SIZE, board.height*CELL_SIZE), (0,0,0,0)) draw ImageDraw.Draw(overlay) # 为每个方块绘制概率 for y in range(board.height): for x in range(board.width): cell board.get_cell(x, y) if cell.state unopened and cell in probabilities: prob probabilities[cell] color (255, int(255*(1-prob)), int(255*(1-prob)), 150) draw.rectangle([x*CELL_SIZE, y*CELL_SIZE, (x1)*CELL_SIZE, (y1)*CELL_SIZE], fillcolor) text f{prob:.0%} draw.text((x*CELL_SIZE5, y*CELL_SIZE5), text, fill(0,0,0,255)) # 显示覆盖层 overlay.show()在实际项目中我发现最难处理的是游戏速度的适应性。不同电脑上扫雷的动画速度可能不同需要仔细调整点击间隔。一个实用的技巧是开始时进行几次测试点击测量动画完成的时间然后基于这个时间设置合理的延迟参数。