20232110周淳 2023-2024-2 《Python程序设计》实验四报告

20232110周淳 2024-05-22 19:58:40

20232110 2023-2024-2 《Python程序设计》实验四报告

课程:《Python程序设计》
班级: 2321
姓名: 周淳
学号:20232110
实验教师:王志强
实验日期:2024年5月15日
必修/选修: 公选课

1.实验内容

Python综合应用:
编写一个扫雷游戏,处理图形用户界面(GUI)和算法逻辑。
使用tkinter库(Python的标准GUI库)来创建界面。
游戏目标:实现一个基本的扫雷游戏,玩家需要标记或揭示游戏板上的格子,以找出所有的地雷而避免踩到它们。
①初始化游戏板:随机放置地雷和计算每个非地雷格子周围的地雷数量。
②创建游戏界面:显示游戏板的按钮网格。
③实现点击按钮以揭示或标记格子的功能。
④当玩家踩到地雷时,游戏结束。

2. 实验过程及结果

实验设计

①定义:

创建一个名为扫雷的类来管理游戏的状态和逻辑。
游戏板:存储每个格子的地雷数量或状态,用一个二维链表实现。
地雷位置:存储所有地雷的坐标。
已揭示格子:存储已揭示的格子坐标。这两个都是集合
初始化游戏板:随机放置地雷并计算每个非地雷格子的地雷数量。
创建小部件:使用tkinter库创建游戏界面,包括按钮网格。
揭示:处理按钮点击事件,揭示或标记格子,并递归揭示相邻的零地雷格子。

②界面设计:

使用tkinter库创建图形用户界面(GUI)。
游戏板以按钮网格的形式展示,每个按钮代表一个格子。
初始时,所有按钮都未揭示,格子显示“?”;已揭示的格子显示数字,若点到炸弹格子不反应并给出游戏结束的提示。

实验实现过程

①步骤:

步骤 1:初始化

导入必要的库(tkinter和random)。
定义常量(地雷数量、宽度和高度)。
创建扫雷类。

步骤 2:实现__init__方法

初始化游戏窗口,初始化游戏板、地雷位置和已揭示格子等属性,调用初始化游戏板和创建小部件方法。

步骤 3:实现初始化游戏板方法

随机放置地雷,确保不会重复放置。
遍历游戏板,对非地雷格子计算其周围的地雷数量。

步骤 4:实现创建小部件方法

使用循环创建按钮网格,并将每个按钮绑定到揭示方法上。
使用grid方法将按钮放置到游戏窗口的相应位置。

步骤 5:实现揭示方法

检查点击的格子是否已经被揭示或包含地雷。
如果格子是安全的(非地雷且未被揭示),则揭示它并递归揭示相邻的零地雷格子。
如果格子包含地雷,则打印游戏结束消息。

步骤 6:创建游戏实例并启动

创建扫雷类的实例,并将游戏窗口作为参数传递。
进入tkinter的主事件循环以启动游戏。

②具体实现:

1.在这个程序的实验过程中,首先定义了常量,包括地雷数量、宽度和高度,以便后续使用。然后创建了一个 扫雷 来管理游戏的逻辑。在这个类中,实现初始化游戏板、创建游戏界面以及处理揭示格子的方法。

import tkinter as tk
import random

地雷数量 = 10
宽度 = 10
高度 = 10

class 扫雷:
    def __init__(self, 主窗口):
        self.主窗口 = 主窗口
        self.游戏板 = [[0 for _ in range(宽度)] for _ in range(高度)]
        self.地雷位置 = set()
        self.已揭示格子 = set()
        self.初始化游戏板()
        self.创建小部件()

2.在初始化游戏板方法中,随机放置了一定数量的地雷,并计算了非地雷格子周围的地雷数量,以便在游戏进行过程中显示给玩家。

    def 初始化游戏板(self):

        for _ in range(地雷数量):
            x, y = random.randint(0, 宽度 - 1), random.randint(0, 高度 - 1)
            while (x, y) in self.地雷位置:
                x, y = random.randint(0, 宽度 - 1), random.randint(0, 高度 - 1)
            self.地雷位置.add((x, y))

        for x in range(宽度):
            for y in range(高度):
                if (x, y) not in self.地雷位置:
                    数量 = 0
                    for dx in [-1, 0, 1]:
                        for dy in [-1, 0, 1]:
                            if 0 <= x + dx < 宽度 and 0 <= y + dy < 高度 and (x + dx, y + dy) in self.地雷位置:
                                数量 += 1
                    self.游戏板[x][y] = 数量

3.接着,在创建游戏界面方法中,利用 Tkinter 创建了游戏界面上的格子按钮,并绑定了揭示方法,使得玩家点击按钮时可以揭示对应的格子。

    def 揭示(self, x, y):
        if (x, y) in self.已揭示格子:
            return

        if (x, y) in self.地雷位置:
            print("游戏结束!你踩到地雷了!")
            return

        self.已揭示格子.add((x, y))
        按钮 = self.主窗口.grid_slaves(row=y, column=x)[0]
        按钮.config(text=str(self.游戏板[x][y]), state=tk.DISABLED)

        if self.游戏板[x][y] == 0:
            for dx in [-1, 0, 1]:
                for dy in [-1, 0, 1]:
                    nx, ny = x + dx, y + dy
                    if 0 <= nx < 宽度 and 0 <= ny < 高度:
                        self.揭示(nx, ny)

根 = tk.Tk()
根.title("扫雷")
游戏 = 扫雷(根)
根.mainloop()

4.完整程序

import tkinter as tk
import random

地雷数量 = 10
宽度 = 10
高度 = 10

class 扫雷:
    def __init__(self, 主窗口):
        self.主窗口 = 主窗口
        self.游戏板 = [[0 for _ in range(宽度)] for _ in range(高度)]
        self.地雷位置 = set()
        self.已揭示格子 = set()
        self.初始化游戏板()
        self.创建小部件()

    def 初始化游戏板(self):

        for _ in range(地雷数量):
            x, y = random.randint(0, 宽度 - 1), random.randint(0, 高度 - 1)
            while (x, y) in self.地雷位置:
                x, y = random.randint(0, 宽度 - 1), random.randint(0, 高度 - 1)
            self.地雷位置.add((x, y))

        for x in range(宽度):
            for y in range(高度):
                if (x, y) not in self.地雷位置:
                    数量 = 0
                    for dx in [-1, 0, 1]:
                        for dy in [-1, 0, 1]:
                            if 0 <= x + dx < 宽度 and 0 <= y + dy < 高度 and (x + dx, y + dy) in self.地雷位置:
                                数量 += 1
                    self.游戏板[x][y] = 数量

    def 创建小部件(self):
        for x in range(宽度):
            for y in range(高度):
                按钮 = tk.Button(self.主窗口, text="?", command=lambda x=x, y=y: self.揭示(x, y))
                按钮.grid(row=y, column=x)

    def 揭示(self, x, y):
        if (x, y) in self.已揭示格子:
            return

        if (x, y) in self.地雷位置:
            print("游戏结束!你踩到地雷了!")
            return

        self.已揭示格子.add((x, y))
        按钮 = self.主窗口.grid_slaves(row=y, column=x)[0]
        按钮.config(text=str(self.游戏板[x][y]), state=tk.DISABLED)

        if self.游戏板[x][y] == 0:
            for dx in [-1, 0, 1]:
                for dy in [-1, 0, 1]:
                    nx, ny = x + dx, y + dy
                    if 0 <= nx < 宽度 and 0 <= ny < 高度:
                        self.揭示(nx, ny)

根 = tk.Tk()
根.title("扫雷")
游戏 = 扫雷(根)
根.mainloop()

实验结果

演示视频:

3. 实验过程中遇到的问题和解决过程

  • 问题1:pycharm提示没有pygame的模块
  • 问题1解决方案:在命令行或终端中,使用pip install pygame命令安装 pygame
  • 问题2:老师没讲过pygame的应用
  • 问题2解决方案:去学习通学习了python课程资料里的《第十三章 pygame游戏编程》
  • 问题3:__init__不太熟练,说实话还是不太懂
  • 问题3解决方案:去参考了网上的文章
  • 问题4:如何正确地更新按钮的显示内容以及如何处理递归揭示周围格子时的边界情况
  • 问题4解决方案:在揭示方法中根据按钮对应的格子状态来更新按钮的图标,可以通过添加边界检查条件来解决这个问题,确保递归只在合法的格子上进行,在递归调用前添加条件判断,检查当前格子是否在游戏板范围内,并且是否已经揭示。如果满足条件,则可以继续递归揭示周围的格子,否则直接返回不进行递归。这样可以确保递归过程中不会出现边界情况的错误。

4.本实验的思考

编写这个扫雷游戏的代码让我实践了如何创建简单的图形界面应用程序。在这个过程中,我学会了怎么处理用户的点击、更新界面内容以及利用递归算法来实现游戏逻辑。通过这个实验,我更加熟悉了面向对象编程的思想,将游戏的逻辑封装在一个类中,使得代码结构清晰易懂。同时,我也加深了对随机算法的理解,特别是在地雷位置的随机放置上。这个实验不仅提升了我的编程技能,也增强了我对游戏开发和图形界面应用程序的理解。我期待能够在未来的项目中继续运用这些知识,创造出更加有趣和实用的应用程序。

5.课程总结

1.感想与体会:
王志强老师不愧是学长学姐推荐的好老师,讲解通俗易懂、深入浅出,更重要的是上课很有亲和力,让人想听也听得进去。王老师这一学期的python课令我受益良多,相较于我高中学考层次的python学习经历更加深入、完整和系统,像是高中根本不会讲爬虫这一类的python应用方式,更没有机会给我们去实机操演,高中那完全是应试教育,大学这种边讲边尝试的教学方式明显更加有利于知识的吸收和掌握。总之这一学期让我回忆起高中被丢弃的知识也在此基础上学到了更多,也写了很多代码,实际动手能力有了长足发展。
2.意见与建议:
学习通每一章的讲义好像不是很全,有几章没有。希望上课的时候能给加分机会,比如回答问题、随机选人之类的,给大家更多机会展示自己。

6.参考资料

-  学习通python课程资料《第十三章 pygame游戏编程》

...全文
210 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

110

社区成员

发帖
与我相关
我的任务
社区描述
人生苦短,我用Python!
python3.11 高校
社区管理员
  • blackwall0321
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧