Python实现功能完整的扫雷小游戏

一、游戏功能亮点

本次实现的扫雷游戏在基础玩法之上,新增了三大核心功能,提升游戏体验与挑战性:

  • 计时器功能:游戏启动后自动计时,结束时显示通关或失败用时,增强竞技感;

  • 难度选择功能:提供初级、中级、高级三种模式,对应不同的格子尺寸与地雷数量,适配不同水平的玩家;

  • 排行榜功能:通过JSON文件实现数据持久化,记录各难度下的最快通关时间,支持实时查看与更新。

二、开发环境与核心技术

1. 开发环境

本项目基于Python 3.x开发,无需额外配置复杂环境,仅依赖Python标准库:

  • Tkinter:Python内置的GUI开发库,用于构建游戏窗口、按钮、状态栏等交互界面;

  • random:用于随机生成地雷的位置;

  • json与os:实现排行榜数据的持久化存储(读取/保存JSON文件)。

2. 核心技术逻辑

游戏的核心运行逻辑可拆解为以下几步:

  1. 初始化:创建游戏窗口、状态栏(旗子数量、计时器、功能按钮)、游戏网格;

  2. 地雷布置:随机在网格中放置指定数量的地雷,记录地雷位置;

  3. 交互响应:处理左键揭开格子、右键插旗/拔旗的操作,判断是否踩雷或通关;

  4. 辅助功能:计时器的启动/停止/更新、难度选择界面的切换、排行榜数据的加载/保存/展示。

三、详细实现步骤

1. 基础游戏框架搭建

首先定义扫雷游戏的核心类Minesweeper,在初始化方法中完成界面组件的创建与初始化:

  • 状态栏:包含剩余旗子数量显示、重置按钮、计时器显示、排行榜按钮;

  • 游戏网格:通过Tkinter的Button组件构建二维网格,绑定左键揭开、右键插旗事件;

  • 数据初始化:初始化地雷位置集合、已揭开格子集合、旗子集合、计时器数据等。

2. 核心游戏逻辑实现

(1)地雷布置与相邻地雷计数

通过random.randint随机生成地雷位置,确保地雷数量符合当前难度要求;定义count_adjacent_mines方法,遍历当前格子的8个相邻格子,统计地雷数量,为揭开格子时的数字显示提供依据。

(2)格子揭开与胜负判断

左键点击格子时,若点击到地雷则游戏失败;若为安全格子,则显示相邻地雷数量,若数量为0则递归揭开周围所有安全格子;定义check_win方法,当已揭开格子数量等于总格子数减去地雷数时,判定为游戏胜利。

(3)右键插旗功能

右键点击格子时,切换插旗/拔旗状态,同时更新状态栏的剩余旗子数量显示,确保旗子数量不超过当前难度的地雷数量。

3. 功能实现

(1)计时器功能

通过tkinter.after方法实现定时更新,每秒递增计时时间并刷新状态栏显示;游戏结束(胜利/失败)时调用stop_timer方法停止计时,重置游戏时也需停止当前计时器。

(2)难度选择功能

定义show_difficulty_selection函数,创建独立的难度选择窗口,提供三个难度按钮,点击后传递对应参数(格子尺寸、地雷数量)启动游戏;重置游戏时,返回难度选择界面,支持重新选择难度。

(3)排行榜功能

使用JSON文件minesweeper_leaderboard.json存储排行榜数据,初始化时若文件不存在则创建并初始化各难度记录为999秒(表示未通关);游戏胜利时,对比当前用时与历史最快记录,若创造新纪录则更新数据并保存;点击状态栏“排行榜”按钮,弹出窗口展示各难度的最快通关时间。

四、完整代码实现

import tkinter as tk from tkinter import messagebox import random import json import os # 排行榜文件路径 LEADERBOARD_FILE = "minesweeper_leaderboard.json" class Minesweeper: def __init__(self, master, rows=10, cols=10, mines=10, difficulty="初级"): self.master = master self.rows = rows self.cols = cols self.mines = mines self.difficulty = difficulty self.buttons = [] self.mine_positions = set() self.revealed = set() self.flags = set() self.time_elapsed = 0 self.timer_id = None self.leaderboard = self.load_leaderboard() # 创建顶部状态栏 self.status_frame = tk.Frame(master) self.status_frame.pack(pady=5) self.flag_label = tk.Label(self.status_frame, text=f"剩余旗子: {self.mines}", font=("Arial", 12)) self.flag_label.pack(side=tk.LEFT, padx=10) self.reset_button = tk.Button(self.status_frame, text="重置", command=self.reset_game, font=("Arial", 12)) self.reset_button.pack(side=tk.LEFT, padx=10) self.timer_label = tk.Label(self.status_frame, text="时间: 0s", font=("Arial", 12)) self.timer_label.pack(side=tk.LEFT, padx=10) self.leaderboard_button = tk.Button(self.status_frame, text="排行榜", command=self.show_leaderboard, font=("Arial", 12)) self.leaderboard_button.pack(side=tk.LEFT, padx=10) # 创建游戏网格 self.grid_frame = tk.Frame(master) self.grid_frame.pack() self.create_widgets() self.place_mines() self.start_timer() def create_widgets(self): """创建网格按钮""" for r in range(self.rows): row = [] for c in range(self.cols): btn = tk.Button( self.grid_frame, width=2, height=1, font=("Arial", 14), command=lambda r=r, c=c: self.reveal(r, c) ) btn.bind("<Button-3>", lambda e, r=r, c=c: self.toggle_flag(r, c)) # 右键插旗 btn.grid(row=r, column=c, padx=1, pady=1) row.append(btn) self.buttons.append(row) def place_mines(self): """随机放置地雷""" while len(self.mine_positions) < self.mines: r = random.randint(0, self.rows - 1) c = random.randint(0, self.cols - 1) self.mine_positions.add((r, c)) def count_adjacent_mines(self, r, c): """计算周围地雷数量""" count = 0 for dr in (-1, 0, 1): for dc in (-1, 0, 1): if dr == 0 and dc == 0: continue nr, nc = r + dr, c + dc if 0 <= nr < self.rows and 0 <= nc < self.cols: if (nr, nc) in self.mine_positions: count += 1 return count def reveal(self, r, c): """揭开格子""" if (r, c) in self.revealed or (r, c) in self.flags: return if (r, c) in self.mine_positions: self.game_over(False) return self.revealed.add((r, c)) mine_count = self.count_adjacent_mines(r, c) self.buttons[r][c].config( text=str(mine_count) if mine_count > 0 else "", state="disabled", bg="#f0f0f0" ) if mine_count == 0: # 递归展开周围格子 for dr in (-1, 0, 1): for dc in (-1, 0, 1): if dr == 0 and dc == 0: continue nr, nc = r + dr, c + dc if 0 <= nr < self.rows and 0 <= nc < self.cols: self.reveal(nr, nc) self.check_win() def toggle_flag(self, r, c): """右键插旗/拔旗""" if (r, c) in self.revealed: return if (r, c) in self.flags: self.flags.remove((r, c)) self.buttons[r][c].config(text="", bg="SystemButtonFace") else: if len(self.flags) < self.mines: self.flags.add((r, c)) self.buttons[r][c].config(text="🚩", bg="orange") self.update_flag_count() def update_flag_count(self): """更新旗子数量显示""" remaining = self.mines - len(self.flags) self.flag_label.config(text=f"剩余旗子: {remaining}") def check_win(self): """检查是否胜利""" if len(self.revealed) == self.rows * self.cols - self.mines: self.game_over(True) def game_over(self, win): """游戏结束处理""" self.stop_timer() for r in range(self.rows): for c in range(self.cols): if (r, c) in self.mine_positions: self.buttons[r][c].config(text="💣", bg="red") self.buttons[r][c].config(state="disabled") if win: # 更新排行榜 current_record = self.leaderboard.get(self.difficulty, 999) if self.time_elapsed < current_record: self.leaderboard[self.difficulty] = self.time_elapsed self.save_leaderboard() messagebox.showinfo("胜利", f"恭喜你,扫雷成功!用时: {self.time_elapsed} 秒\n🎉 新纪录!") else: messagebox.showinfo("胜利", f"恭喜你,扫雷成功!用时: {self.time_elapsed} 秒") else: messagebox.showerror("失败", f"踩到地雷了!游戏结束!用时: {self.time_elapsed} 秒") def start_timer(self): """启动计时器""" self.time_elapsed = 0 self.update_timer() def update_timer(self): """更新计时器显示""" self.time_elapsed += 1 self.timer_label.config(text=f"时间: {self.time_elapsed}s") self.timer_id = self.master.after(1000, self.update_timer) def stop_timer(self): """停止计时器""" if self.timer_id: self.master.after_cancel(self.timer_id) def reset_game(self): """重置游戏""" self.stop_timer() self.master.destroy() show_difficulty_selection() def load_leaderboard(self): """加载排行榜数据""" if os.path.exists(LEADERBOARD_FILE): with open(LEADERBOARD_FILE, "r") as f: return json.load(f) else: # 初始化排行榜 initial_leaderboard = { "初级": 999, "中级": 999, "高级": 999 } self.save_leaderboard(initial_leaderboard) return initial_leaderboard def save_leaderboard(self, data=None): """保存排行榜数据""" if data is None: data = self.leaderboard with open(LEADERBOARD_FILE, "w") as f: json.dump(data, f, indent=4) def show_leaderboard(self): """显示排行榜""" leaderboard_window = tk.Toplevel(self.master) leaderboard_window.title("排行榜") leaderboard_window.geometry("300x200") tk.Label(leaderboard_window, text="扫雷排行榜", font=("Arial", 16)).pack(pady=10) for difficulty, time in self.leaderboard.items(): if time == 999: display_time = "未通关" else: display_time = f"{time} 秒" tk.Label(leaderboard_window, text=f"{difficulty}: {display_time}", font=("Arial", 12)).pack(pady=5) def show_difficulty_selection(): """显示难度选择窗口""" def start_game(rows, cols, mines, difficulty): selection_root.destroy() root = tk.Tk() root.title(f"扫雷 - {difficulty}") Minesweeper(root, rows, cols, mines, difficulty) root.mainloop() selection_root = tk.Tk() selection_root.title("选择难度") selection_root.geometry("300x200") tk.Label(selection_root, text="请选择游戏难度:", font=("Arial", 14)).pack(pady=20) tk.Button( selection_root, text="初级 (9x9, 10个地雷)", font=("Arial", 12), command=lambda: start_game(9, 9, 10, "初级") ).pack(pady=5) tk.Button( selection_root, text="中级 (16x16, 40个地雷)", font=("Arial", 12), command=lambda: start_game(16, 16, 40, "中级") ).pack(pady=5) tk.Button( selection_root, text="高级 (16x30, 99个地雷)", font=("Arial", 12), command=lambda: start_game(16, 30, 99, "高级") ).pack(pady=5) selection_root.mainloop() if __name__ == "__main__": show_difficulty_selection()

五、游戏使用说明

1. 运行游戏

将上述代码保存为minesweeper.py,使用Python 3.x环境运行该文件,即可启动游戏。

2. 难度选择

游戏启动后,首先进入难度选择界面,三种难度参数如下:

  • 初级:9×9格子,10个地雷,适合新手入门;

  • 中级:16×16格子,40个地雷,难度适中;

  • 高级:16×30格子,99个地雷,挑战高阶玩家。

3. 核心操作

  • 左键点击:揭开当前格子,若为地雷则游戏失败,若为安全格子则显示相邻地雷数量;

  • 右键点击:在未揭开的格子上插旗/拔旗,用于标记疑似地雷的位置,旗子数量不超过当前难度的地雷数量;

  • 重置按钮:停止当前游戏,返回难度选择界面,可重新选择难度开始游戏;

  • 排行榜按钮:随时查看各难度下的最快通关时间。

4. 胜负判定与排行榜更新

  • 胜利条件:揭开所有非地雷格子,游戏自动停止计时,若用时刷新当前难度记录,会弹出“新纪录”提示;

  • 失败条件:左键点击到地雷,游戏自动停止计时,弹出失败提示;

  • 排行榜数据:保存在minesweeper_leaderboard.json文件中,关闭游戏后记录不丢失,可手动打开文件查看或修改。

六、拓展与优化方向

若想进一步完善游戏,可参考以下拓展方向:

  • 增加自定义难度功能:允许玩家手动设置格子尺寸与地雷数量;

  • 优化界面样式:为不同数量的相邻地雷设置不同颜色,提升视觉体验;

  • 增加音效反馈:在揭开格子、踩雷、胜利时添加对应的音效;

  • 完善排行榜:支持记录玩家昵称,显示历史前3名记录。

通过本项目的实现,不仅能掌握Tkinter GUI开发、数据持久化等基础技术,还能深入理解游戏的交互逻辑与状态管理,是Python实战练习的优质案例。快来尝试运行代码,挑战自己的扫雷最快记录吧!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/1120068.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

langchain的中文文档地址

中文文档地址&#xff1a;https://www.langchain.com.cn/docs/introduction/

一分钟读懂代付业务

代付业务主要分为个人代付与企业代付两大类型。对于企业而言&#xff0c;开通代付功能堪称降本增效的利器&#xff0c;核心优势有四&#xff1a;1. 724小时全天候服务&#xff1a;支持自动抵扣转账&#xff0c;不受节假日、上下班时间限制&#xff0c;资金流转更灵活。2. 解放财…

飞越中国沉浸式体验馆:7D互动影院引领全新娱乐风潮

飞越中国沉浸式体验馆的创新娱乐体验 在飞越中国沉浸式体验馆中&#xff0c;7D互动影院成为众多观众探寻新娱乐体验的首选。该影院利用先进技术&#xff0c;为观众提供超高清画质并结合动感座椅&#xff0c;创造出独特的沉浸感。在这里&#xff0c;观众不仅仅是被动观看&#x…

高考学校和专业的选择

高考学校和专业的选择是&#xff1a;专业占比&#xff1a;40%学校占比&#xff1a;30%地域占比&#xff1a;30%学校占比&#xff0c;国内就是按这个顺序&#xff0c;清北、C9、985、211、其它有一定名气的一二本、普通二本、末流二本原三本、大专。这儿值得一提的是&#xff0c…

CSS3 伸缩盒模型

一、伸缩容器、伸缩项目二、主轴与侧轴三、主轴方向四、主轴换行方式五、flex-flow六、主轴对齐方式七、侧轴对齐方式1、只有一行的情况2、多行的情况八、水平垂直居中九、基准长度十、flex复合属性十一、项目排序

Expected type ‘SecretStr | None‘, got ‘str‘ instead

错误原因 代码中有一个类型不匹配的问题&#xff1a;函数或方法期望接收的类型是 SecretStr | None&#xff08;即 SecretStr 类型或 None&#xff09;&#xff0c;但实际传入了一个普通的 str 字符串。 原因分析 使用了类型检查工具&#xff1a;你可能在使用像 mypy、pydantic…

从实验室到生产:模型量化的完整流程

从实验室到生产&#xff1a;模型量化的完整流程——让AI模型“瘦身”后跑起来 关键词 模型量化、INT8推理、动态量化、静态量化、量化感知训练、部署优化、边缘计算 摘要 当你在实验室训练出一个准确率95%的图像分类模型时&#xff0c;是否遇到过“部署瓶颈”&#xff1f;200MB…

CSS3 响应式布局

一、媒体类型二、媒体特性三、运算符

木材缺陷检测数据集-2394张图片 木材加工质检 家具制造质控 建筑材料检验 木材贸易分级 林业资源评估 智能仓储管理

&#x1f4e6;点击查看-已发布目标检测数据集合集&#xff08;持续更新&#xff09; 数据集名称图像数量应用方向博客链接&#x1f50c; 电网巡检检测数据集1600 张电力设备目标检测点击查看&#x1f525; 火焰 / 烟雾 / 人检测数据集10000张安防监控&#xff0c;多目标检测点…

AI安全与伦理:深度学习的“双刃剑”

深度学习的安全挑战深度学习模型容易受到对抗性攻击&#xff0c;攻击者通过微小的输入扰动误导模型产生错误输出。例如在图像识别中&#xff0c;加入人眼难以察觉的噪声可能导致模型将“熊猫”误判为“长臂猿”。这类攻击在自动驾驶、医疗诊断等高风险领域可能引发严重后果。数…

时间序列异常检测框架概述

时间序列异常检测&#xff08;Time Series Anomaly Detection, TSAD&#xff09;是识别时间序列数据中偏离正常模式的数据点或模式的技术。 一、异常类型分类 点异常&#xff08;Point Anomalies&#xff09;&#xff1a;单个异常数据点上下文异常&#xff08;Contextual Anoma…

从“平台”到“插件”:一个IT老兵眼中的宽基指数与“核心-卫星”投资架构

财富大厦的“操作系统” 作为一名在ICT行业摸爬滚打了三十多年的老兵 。职业习惯让我总想把复杂的事情模块化。投资不是赌博,而是一场关于“系统稳定性”与“功能扩展性”的长久运维。 [场景切入] 你的投资系统“宕机”了吗? 深夜,刚结束一个紧急的系统上线,拖着疲惫的身…

学霸同款10个AI论文网站,专科生轻松搞定毕业论文!

学霸同款10个AI论文网站&#xff0c;专科生轻松搞定毕业论文&#xff01; AI工具让论文写作不再难 在当今这个信息爆炸的时代&#xff0c;论文写作已经成为许多专科生必须面对的挑战。无论是选题、写大纲&#xff0c;还是撰写初稿和降重&#xff0c;每一个环节都可能让人感到压…

python基于django的公司财务预算管理系统_uggpfoob

目录项目概述核心功能技术实现优势与价值关于博主开发技术路线相关技术介绍核心代码参考示例结论源码lw获取/同行可拿货,招校园代理 &#xff1a;文章底部获取博主联系方式&#xff01;项目概述 Python基于Django的公司财务预算管理系统是一个高效、模块化的企业级应用&#x…

强烈安利9个AI论文平台,MBA毕业论文轻松搞定!

强烈安利9个AI论文平台&#xff0c;MBA毕业论文轻松搞定&#xff01; AI 工具如何让论文写作更高效 在当前的学术环境中&#xff0c;越来越多的 MBA 学生开始借助 AI 工具来提升论文写作的效率。尤其是在面对大量文献阅读、数据分析和逻辑构建时&#xff0c;传统的方法往往显得…

系统监控异常告警

背景&#xff1a;多个系统部署在多个ECS(Linux)服务器上&#xff0c;每次巡检或者日常管理都是大问题。而且还比较滞后&#xff0c;都是问题出现了&#xff0c;才去排查。所以&#xff0c;高级的管理应主动发现异常&#xff0c;提早介入&#xff0c;将风险扼杀在摇篮中。思路&a…

【Rokid AR录屏功能逆向分析:通过蓝牙HCI抓包实现CXR SDK未提供的AR录屏功能】

背景介绍 作为一名Rokid Glasses开发者&#xff0c;我最近在开发一个需要AR录屏功能的应用。然而&#xff0c;Rokid官方提供的CXR SDK中并没有直接封装AR录屏的功能。在查阅官方文档和API后&#xff0c;我意识到需要自己探索实现方案。 经过深入研究&#xff0c;我发现了通过蓝…

A2UI:让AI从“对话框“走向“动态界面“

A2UI解决的核心问题是&#xff1a;如何让AI代理安全地跨信任边界渲染UI。 这话听着有点绕&#xff0c;举项目中的一个示例就清楚了。你问AI助手“帮我订个餐厅”&#xff0c;传统的方式是一轮轮文字对话&#xff1a; 用户: "订个两人桌"AI: "什么时间&#xff1…

【路径规划】基于matlab模糊神经网络机器人路径规划【含Matlab源码 14859期】

&#x1f4a5;&#x1f4a5;&#x1f4a5;&#x1f4a5;&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;&#x1f49e;&#x1f49e;&#x1f49e;&#x1f49e;&#x1f49e;&#x1f49e;欢迎来到海神之光博客之家&#x1f49e;&#x1f49e;&#x1f49e;&#x1f49…