20254109张家宝《Python程序设计》实验4报告

20254109 2025-2026-2 《Python程序设计》实验4报告
课程:《Python程序设计》
班级: 2541
姓名: 张家宝
学号:20254109
实验教师:王志强
实验日期:2026年5月26日
必修/选修: 专选课

一、实验内容
Python综合应用:爬虫、数据处理、可视化、机器学习、神经网络、游戏、网络安全等。
课代表和各小组负责人收集作业(源代码、视频、综合实践报告)

Python综合应用:爬虫、数据处理、可视化、机器学习、神经网络、游戏、网络安全等。
例如:编写从社交网络爬取数据,实现可视化舆情监控或者情感分析。
例如:利用公开数据集,开展图像分类、恶意软件检测等
例如:利用Python库,基于OCR技术实现自动化提取图片中数据,并填入excel中。
例如:爬取天气数据,实现自动化微信提醒
例如:利用爬虫,实现自动化下载网站视频、文件等。
例如:编写小游戏:坦克大战、贪吃蛇、扫雷等等
注:在Windows/Linux系统上使用VIM、PDB、IDLE、Pycharm等工具编程实现。

批阅:注意本次实验不算做实验总分,前三个实验每个实验15分,累计45分。本次实践算入综合实践,打分为45分。
评分标准:
(1)程序能运行,功能丰富(至少5个功能)。(需求提交源代码,并建议录制程序运行的视频)15分
(2)综合实践报告,要体现实验分析、设计、实现过程、结果等信息,格式规范,逻辑清晰,结构合理。20分。
(3)在实践报告中,需要对全课进行总结,并写课程感想体会、意见和建议等。10分
二、实验分析及设计

  1. 实验分析
    在老师的作业要求中,考虑到我个人水平不高以及个人兴趣,我选择编写经典的扫雷游戏作为本次实践项目。扫雷是一款家喻户晓的益智小游戏,逻辑清晰、交互友好,既贴合 Python 图形化编程的学习内容,又能完整覆盖界面设计、游戏逻辑、数据存储、交互操作等核心知识点。
    扫雷的代码结构简洁,功能拓展性强,同时不容易与其他同学的项目重复。结合 Python 3.13 的 Tkinter 内置库,无需安装第三方依赖,就能实现完整的可视化游戏界面,兼顾了实用性、趣味性和学习价值。
  2. 实验设计
    结合课程学习内容和扫雷游戏的核心玩法,我设计了七大核心功能模块,同时保证程序完整可运行、界面美观、逻辑完善:
    (1)可视化图形界面设计
    采用 Python 内置的 Tkinter 库实现可视化弹窗界面,主菜单固定为10cm×15cm的标准尺寸,布局简洁规整,包含标题、功能按钮、状态显示等元素,操作直观易懂,替代纯命令行界面,提升游戏体验。
    (2)多难度模式选择功能
    设计四种游戏难度,满足不同玩家的需求:初级(9×9,10 个地雷)、中级(16×16,40 个地雷)、高级(16×30,99 个地雷),同时新增自定义模式,支持玩家自由设置总格子数和地雷数量,实现个性化游戏体验。
    (3)完整的游戏交互操作
    实现扫雷标准操作逻辑:鼠标左键翻开格子,自动展开空白区域并显示周围地雷数量;鼠标右键标记 / 取消标记地雷,实时显示剩余地雷数量,完全复刻经典扫雷的操作方式,简单易上手。
    (4)游戏计时与胜负判定
    内置精准的计时系统,点击第一格开始计时,实时显示游戏用时;自动判定游戏胜负:踩到地雷则游戏失败,翻开所有安全格子则游戏胜利,胜利后弹窗提示通关用时,失败后展示所有地雷位置。
    (5)成绩记录与排名功能
    实现本地数据持久化存储,将每次胜利的游戏用时、时间自动保存到文件中;支持按难度分类查看成绩排名,自动按照用时从快到慢排序,展示历史最佳成绩,增加游戏的挑战性和趣味性。
    (6)游戏说明与帮助功能
    设计独立的游戏说明模块,清晰展示游戏目标、操作方式、数字含义、胜负规则、难度说明等内容,新手也能快速理解游戏玩法,完善游戏的引导功能。
    (7)菜单切换与退出功能
    实现游戏主菜单与游戏界面的自由切换,随时可以返回主菜单重新选择难度;支持安全退出游戏,所有数据自动保存,程序运行稳定无卡顿、无报错,兼容 Python 3.13 最新版本。
    三、实验实现过程
  3. 开发环境
    编程语言:Python 3.13
    开发工具:任意 Python 代码编辑器
    依赖库:Tkinter(Python 内置)、json、random、datetime(内置标准库)
  4. 核心实现步骤
    (1)框架搭建:创建主窗口,初始化游戏全局变量(地雷位置、标记状态、计时、成绩数据等);
    image

(2)主菜单设计:编写可视化菜单界面,集成难度选择、成绩排名、游戏说明、退出等按钮;
image

(3)游戏核心逻辑:随机生成地雷位置、计算格子周围地雷数、实现空白区域自动展开、标记地雷功能;
初始化游戏
image
image
自定义游戏
image

(4)计时与胜负判断:编写计时函数,实时更新时间,判断胜利 / 失败条件并执行对应逻辑;
image
游戏实施核心逻辑
image
image

(5)成绩管理:通过 json 文件实现成绩的读取、保存、排序、展示功能,分难度展示排名;
image
image
游戏结束程序
image

(6)界面优化:固定窗口尺寸,设置字体、颜色、按钮样式,修复兼容性 bug,保证程序稳定运行;
在原先只有2×2的页面过小的基础上,我通过对程序的修改,将它做了扩充。
image

(7)功能测试:测试所有交互功能、难度切换、成绩记录、胜负判定,确保无报错、无逻辑漏洞。

四. 程序运行结果
程序可完美运行,主菜单界面规整美观,四种难度模式均可正常启动,鼠标左右键交互流畅,计时精准,地雷标记与自动展开功能正常,游戏胜负判定准确,成绩记录与排名实时更新,游戏说明清晰完整,整体运行稳定、无卡顿、无报错,达到了预期的设计目标。详细游戏运行时的视频如下:
https://www.bilibili.com/video/BV1CsV66sExd/?spm_id_from=333.1387.homepage.video_card.click
源代码已在附图中给出:
image
image
image
image
image
image
image
image

点击查看代码 import tkinter as tk from tkinter import ttk, messagebox, simpledialog import random import json import os from datetime import datetime

SCORE_FILE = "minesweeper_scores.json"

class MinesweeperGame:
def init(self, root):
self.root = root
# ========== 固定窗口大小:约 10cm × 15cm (378px × 567px) ==========
self.root.geometry("378x567")
self.root.title("扫雷游戏")
self.root.resizable(False, False) # 禁止拖拽缩放

self.buttons = []
self.mines = []
self.flags = set()
self.revealed = 0
self.total_cells = 0
self.total_mines = 0
self.game_started = False
self.start_time = 0
self.timer_id = None

定义ttk按钮样式,解决font/width报错

self.style = ttk.Style()
self.style.configure("Menu.TButton", font=("微软雅黑", 11), padding=4)

self.scores = self.load_scores()
self.show_main_menu()

==================== 成绩存储系统 ====================

def load_scores(self):
if not os.path.exists(SCORE_FILE):
return {"初级": [], "中级": [], "高级": [], "自定义": []}
try:
with open(SCORE_FILE, 'r', encoding='utf-8') as f:
return json.load(f)
except:
return {"初级": [], "中级": [], "高级": [], "自定义": []}

def save_scores(self):
try:
with open(SCORE_FILE, 'w', encoding='utf-8') as f:
json.dump(self.scores, f, ensure_ascii=False, indent=4)
except:
pass

def add_score(self, difficulty, time_used):
score_info = {
"时间": round(time_used, 2),
"日期": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
}
self.scores[difficulty].append(score_info)
self.scores[difficulty].sort(key=lambda x: x["时间"])
self.save_scores()

def show_rank(self):
rank_window = tk.Toplevel(self.root)
rank_window.title("成绩排名")
rank_window.geometry("520x420")
rank_window.resizable(False, False)

ttk.Label(rank_window, text="🏆 扫雷成绩排行榜", font=("微软雅黑", 14, "bold")).pack(pady=10)
tab_control = ttk.Notebook(rank_window)
tabs = {}
for diff in ["初级", "中级", "高级", "自定义"]:
tabs[diff] = ttk.Frame(tab_control)
tab_control.add(tabs[diff], text=diff)
tab_control.pack(expand=1, fill="both", padx=10, pady=5)

for diff, frame in tabs.items():
score_list = self.scores[diff]
if not score_list:
ttk.Label(frame, text="暂无成绩记录", font=("微软雅黑", 12)).pack(pady=30)
continue

ttk.Label(frame, text="排名", font=("黑体", 10, "bold")).grid(row=0, column=0, padx=8, pady=6)
ttk.Label(frame, text="用时(秒)", font=("黑体", 10, "bold")).grid(row=0, column=1, padx=8, pady=6)
ttk.Label(frame, text="游戏时间", font=("黑体", 10, "bold")).grid(row=0, column=2, padx=8, pady=6)

for i, s in enumerate(score_list[:15], 1):
ttk.Label(frame, text=str(i)).grid(row=i, column=0, padx=8, pady=3)
ttk.Label(frame, text=str(s["时间"])).grid(row=i, column=1, padx=8, pady=3)
ttk.Label(frame, text=s["日期"]).grid(row=i, column=2, padx=8, pady=3)

==================== 游戏说明 ====================

def show_game_rules(self):
rules = """
🎮 扫雷游戏说明

  1. 游戏目标:翻开所有安全格子,标记全部地雷

  2. 操作方式:
    左键点击:翻开格子
    右键点击:标记/取消标记地雷(红旗)

  3. 数字含义:代表周围8格的地雷数量

  4. 胜负规则:
    踩到地雷 → 游戏失败
    翻开所有安全格 → 游戏胜利

  5. 难度:
    初级:9×9,10个雷
    中级:16×16,40个雷
    高级:16×30,99个雷
    自定义:可设置总格子数与地雷数量
    """
    messagebox.showinfo("游戏规则说明", rules)

    ==================== 主菜单(适配10cm×15cm小窗口) ====================

    def show_main_menu(self):
    for widget in self.root.winfo_children():
    widget.destroy()

    标题适配小窗口

    tk.Label(self.root, text="扫雷游戏", font=("微软雅黑", 22, "bold")).pack(pady=25)

    菜单按钮,紧凑布局适配小尺寸窗口

    ttk.Button(self.root, text="初级难度", command=lambda: self.start_game(9, 9, 10, "初级"),
    style="Menu.TButton").pack(pady=3)
    ttk.Button(self.root, text="中级难度", command=lambda: self.start_game(16, 16, 40, "中级"),
    style="Menu.TButton").pack(pady=3)
    ttk.Button(self.root, text="高级难度", command=lambda: self.start_game(16, 30, 99, "高级"),
    style="Menu.TButton").pack(pady=3)
    ttk.Button(self.root, text="自定义模式", command=self.custom_game, style="Menu.TButton").pack(pady=3)
    ttk.Button(self.root, text="成绩排名", command=self.show_rank, style="Menu.TButton").pack(pady=3)
    ttk.Button(self.root, text="游戏说明", command=self.show_game_rules, style="Menu.TButton").pack(pady=3)
    ttk.Button(self.root, text="退出游戏", command=self.root.quit, style="Menu.TButton").pack(pady=10)

    ==================== 自定义游戏 ====================

    def custom_game(self):
    total = simpledialog.askinteger("自定义设置", "请输入总格子数(25 - 900):", minvalue=25, maxvalue=900)
    if not total:
    return

    max_m = max(1, int(total * 0.8))
    mines = simpledialog.askinteger("自定义设置", f"请输入地雷数(1 - {max_m}):", minvalue=1, maxvalue=max_m)
    if not mines:
    return

    side = int(total ** 0.5)
    rows, cols = side, side
    while rows * cols < total:
    cols += 1
    while rows * cols > total:
    cols -= 1
    if cols < 1:
    rows -= 1
    cols = side

    self.start_game(rows, cols, mines, "自定义")

    ==================== 游戏初始化 ====================

    def start_game(self, rows, cols, mine_count, difficulty):
    if self.timer_id:
    self.root.after_cancel(self.timer_id)

    self.difficulty = difficulty
    self.rows = rows
    self.cols = cols
    self.total_mines = mine_count
    self.total_cells = rows * cols
    self.flags.clear()
    self.revealed = 0
    self.game_started = False
    self.start_time = 0

    for widget in self.root.winfo_children():
    widget.destroy()

    top = ttk.Frame(self.root)
    top.pack(fill="x", padx=10, pady=4)
    self.mine_lb = ttk.Label(top, text=f"地雷总数:{mine_count}", font=("微软雅黑", 9))
    self.mine_lb.pack(side="left")
    self.time_lb = ttk.Label(top, text="时间:0", font=("微软雅黑", 9))
    self.time_lb.pack(side="right")

    self.game_f = ttk.Frame(self.root)
    self.game_f.pack(padx=5, pady=4)

    self.buttons = []
    for i in range(rows):
    row_btns = []
    for j in range(cols):
    btn = tk.Button(self.game_f, width=2, height=1, relief=tk.RAISED, bg="#f0f0f0")
    btn.bind("", lambda e, x=i, y=j: self.reveal(x, y))
    btn.bind("", lambda e, x=i, y=j: self.flag(x, y))
    btn.grid(row=i, column=j, padx=1, pady=1)
    row_btns.append(btn)
    self.buttons.append(row_btns)

    self.generate_mines()
    ttk.Button(self.root, text="返回主菜单", command=self.show_main_menu, style="Menu.TButton").pack(pady=6)

    def generate_mines(self):
    self.mines = [[False] * self.cols for _ in range(self.rows)]
    cnt = 0
    while cnt < self.total_mines:
    x = random.randint(0, self.rows - 1)
    y = random.randint(0, self.cols - 1)
    if not self.mines[x][y]:
    self.mines[x][y] = True
    cnt += 1

    ==================== 计时系统 ====================

    def start_timer(self):
    if not self.game_started:
    self.game_started = True
    self.start_time = datetime.now()
    self.update_timer()

    def update_timer(self):
    if not self.game_started:
    return
    cost = int((datetime.now() - self.start_time).total_seconds())
    self.time_lb.config(text=f"时间:{cost}")
    self.timer_id = self.root.after(1000, self.update_timer)

    ==================== 核心逻辑 ====================

    def near_mines(self, x, y):
    cnt = 0
    for dx in (-1, 0, 1):
    for dy in (-1, 0, 1):
    if dx == 0 and dy == 0:
    continue
    nx, ny = x + dx, y + dy
    if 0 <= nx < self.rows and 0 <= ny < self.cols and self.mines[nx][ny]:
    cnt += 1
    return cnt

    def reveal(self, x, y):
    self.start_timer()
    if (x, y) in self.flags or self.buttons[x][y]["state"] == "disabled":
    return
    if self.mines[x][y]:
    self.game_end(win=False)
    return
    self.dfs_reveal(x, y)
    if self.revealed == self.total_cells - self.total_mines:
    self.game_end(win=True)

    def dfs_reveal(self, x, y):
    if self.buttons[x][y]["state"] == "disabled":
    return
    self.buttons[x][y].config(state="disabled", bg="#e0e0e0")
    self.revealed += 1
    n = self.near_mines(x, y)
    color = ["", "blue", "green", "red", "purple", "orange", "cyan", "black", "gray"]
    if n > 0:
    self.buttons[x][y].config(text=str(n), fg=color[n], font=("Arial", 9, "bold"))
    else:
    for dx in (-1, 0, 1):
    for dy in (-1, 0, 1):
    nx, ny = x + dx, y + dy
    if 0 <= nx < self.rows and 0 <= ny < self.cols:
    self.dfs_reveal(nx, ny)

    def flag(self, x, y):
    if self.buttons[x][y]["state"] == "disabled":
    return
    if (x, y) in self.flags:
    self.buttons[x][y].config(text="")
    self.flags.remove((x, y))
    else:
    self.buttons[x][y].config(text="🚩", fg="red")
    self.flags.add((x, y))
    self.mine_lb.config(text=f"剩余地雷:{self.total_mines - len(self.flags)}")

    ==================== 游戏结束 ====================

    def game_end(self, win):
    self.game_started = False
    for i in range(self.rows):
    for j in range(self.cols):
    if self.mines[i][j]:
    self.buttons[i][j].config(text="💣", fg="red", state="disabled")
    else:
    self.buttons[i][j].config(state="disabled")

    if not win:
    messagebox.showerror("游戏结束", "💣 你踩到地雷了!")
    self.root.after(800, self.show_main_menu)
    return

    cost = (datetime.now() - self.start_time).total_seconds()
    messagebox.showinfo("胜利", f"🎉 恭喜通关!\n用时:{round(cost, 2)} 秒")
    self.add_score(self.difficulty, cost)
    self.root.after(800, self.show_main_menu)

if name == "main":
root = tk.Tk()
app = MinesweeperGame(root)
root.mainloop()

五、全课总结与课程感想体会、意见和建议
1、课程整体总结

本学期Python程序设计课程内容体系完整、知识点层层递进,整体涵盖七大核心模块:Python语言简介、基础语法规则、序列数据结构、字符串与正则表达式、函数与面向对象编程、异常调试与文件操作、网络爬虫基础。通过一学期的系统学习,我从零基础逐步掌握了Python的基础逻辑、编程思维与实战能力,实现了从看不懂代码、害怕编程,到能够独立分析问题、编写完整小程序、完成综合游戏项目的跨越。

第一,Python语言基础特性方面。我了解到Python是一门跨平台、解释型高级编程语言,可在Windows、Linux等多系统运行,语法简洁、可读性强,变量无需提前定义数据类型,由系统自动推断,极大降低了编程入门门槛.Python长期稳居主流编程语言前列,具备极强的实用性与普及性。

第二,Python基础语法知识。本学期系统学习了代码注释规范、系统保留字、基础数据类型与运算符体系。熟练掌握单行注释与多行注释的使用方式,明确了if、else、for、while、def等系统保留字的特殊用途;掌握整型、浮点型、复数等基础数据类型,以及算术运算符、比较运算符等常用运算规则,为后续所有代码编写打下语法基础。

第三,序列数据结构。重点学习了列表、元组、字典、集合四大序列结构,能够通过符号特征快速区分不同数据类型,掌握序列切片规则 [start:end:step],理解切片“左闭右开、含头不含尾”的核心规则。同时区分了 sort() 原地排序与 sorted() 生成新副本排序的差异,能够根据需求灵活处理序列数据。

第四,字符串操作。这里我们要着重记住“左闭右开”的原则。掌握字符串的定义方式、下标规则、切片截取方法,理解字符串不可变特性,能够熟练完成字符串截取、处理、格式调整等基础操作,满足文本处理类程序的开发需求。

第五,函数与面向对象编程。理解形参与实参的对应关系,能够独立封装函数简化代码结构。同时掌握面向对象编程的核心思想,区分类与对象的概念,理解类的实例化过程,熟悉面向对象三大核心特征:封装、继承、多态,初步建立起模块化、规范化的编程思维。

第六,异常处理、调试与文件操作。掌握Python常见异常捕获方式,熟练使用 try-except-else 结构处理程序异常,提升代码稳定性。了解冯·诺依曼体系五大硬件组成结构与计算机二进制运行原理。熟练掌握文件打开、写入、指针移动、关闭等操作,能够通过本地文件实现数据持久化保存,本次扫雷游戏的成绩记录功能正是基于文件操作实现。

第七,网络爬虫基础。了解爬虫的定义与工作原理,爬虫即模拟浏览器向服务器发送请求、获取并解析网页数据的自动化程序。掌握爬虫“爬取+解析”两大核心步骤,同时深刻认识到网络爬虫存在法律边界,了解《网络安全法》相关规范,树立合法合规的网络数据采集意识。

在本学期学习的基础上,我完成了本次综合性实践项目——扫雷游戏开发,综合运用界面设计、循环判断、函数封装、文件存储、异常处理等多章节知识点,实现了多难度模式、自定义游戏、成绩排名、计时系统、游戏说明、胜负判定等丰富功能,真正做到了理论结合实践。

2、课程学习感悟与体会

本学期的Python课程,对我而言是一次全新且珍贵的学习体验。在此之前,我几乎没有编程基础,对代码、程序开发始终抱有畏惧心理,认为编程晦涩难懂、难以掌握。但在老师细致、耐心、循序渐进的教学方式下,我一点点跟上课程节奏,逐渐褪去了对编程的陌生与恐惧,真正感受到了代码的魅力与乐趣。

编程是一门严谨且神奇的学科。一串简单的字母、数字与符号,按照规范的逻辑组合,就能实现丰富、完整、有趣的功能;而一个微小的符号错误、语法疏漏,就会导致整个程序无法运行。这种极致的严谨性,让我在学习过程中不断培养细心、耐心与逻辑思维能力。最让我感触深刻的是课程实验实践环节,从最初简单的代码运行,到后期独立完成游戏开发、实现数据交互,每一次程序成功运行,都让我充满成就感。

让我印象尤为深刻的是课堂实验中的通讯传输实验,这个实验我真的失败了好多次,在我抓耳挠腮想不出哪里错的时候,王老师你却一下子解决了这些问题,敬佩之情如滔滔江水啊!从开学初期的懵懂无知,到学期末期能够独立构思、设计、调试完整项目,我的编程能力和逻辑思维能力都得到了质的提升。

一学期的课程转瞬即逝,我十分感激老师一整个学期的悉心教导。老师教学严谨细致、耐心负责,对待每一位同学的问题都认真解答,甚至多次课后留堂为我们答疑解惑。同时也非常感谢学校和老师为我们行管专业开设Python选修课程,如果没有这次课程机会,我或许永远不会主动接触编程,也无法领略Python的趣味性与实用性。这门课程不仅让我掌握了一项实用技能,更拓宽了我的思维视野,让我收获颇丰、受益匪浅。
实话实说,王老师真的是我在进入电科院之后所有任课老师中最最没有老师架子的,特别特别的平易近人,而且上课又风趣,我一定要向所有接下去进入电科院的后生们强烈安利您的课!(虽然不知道行管还能开到什么时候)

3、课程意见与建议

整体而言,本学期的Python课程教学质量极高,老师教学认真、讲解细致、课堂节奏合理,理论与实践结合紧密,对零基础同学十分友好,我个人非常满意,没有过多意见。仅结合自身踩过的坑,提出一点小小的建议,希望能够帮助后续选课的同学能够更快更好的掌握这门课😜:学生没有压力动力肯定会减少啊,所以我觉得下学期的课程可以加一些期中考试啊,课堂小测之类的内容,这样学生们就会自动去复习跟预习啦,这真是一个促进学生们主动学习的好办法啊!
最后,衷心祝愿老师今后工作顺利、万事顺遂、平安喜乐、桃李芬芳!

posted @ 2026-06-02 23:53  张家宝  阅读(26)  评论(0)    收藏  举报