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

20232301郑好 2024-05-28 22:37:26

20232301郑好 2023-2024-2 《Python程序设计》实验四报告
课程:《Python程序设计》
班级: 2323
姓名: 郑好
学号:20232301
实验教师:王志强
实验日期:2024年5月26日
必修/选修: 公选课

1.实验内容
Python综合应用:爬虫、数据处理、可视化、机器学习、神经网络、游戏、网络安全等
本次实验我使用python来编写扫雷游戏

  1. 实验过程及结果
    代码设计
  2. 导入必要模块
 import tkinter as tk
import random
import tkMessageBox

这段代码导入了必要的模块tkinter用于GUI界面的创建,tkMessageBox用于显示消息框,以及random用于生成随机数。
2.初始化

class Minesweeper:
    def __init__(self, master, rows=10, cols=10, mines=10):
        self.master = master
        self.rows = rows
        self.cols = cols
        self.mines = mines
        self.clicked = [[False for _ in range(cols)] for _ in range(rows)]
        self.flags = [[False for _ in range(cols)] for _ in range(rows)]
        self.board = [[0 for _ in range(cols)] for _ in range(rows)]
        self.buttons = [[None for _ in range(cols)] for _ in range(rows)]
        self.create_board()
        self.place_mines()
        self.calculate_numbers()
        self.draw()

这段代码定义了一个Minesweeper类,__init__方法用于初始化游戏的参数,包括行数、列数和地雷数量,以及创建游戏界面,并初始化游戏板、点击记录、插旗记录等数据结构。
3.创建按钮

def create_board(self):
    for i in range(self.rows):
        for j in range(self.cols):
            button = tk.Button(self.master, text=" ", width=2, height=1)
            button.grid(row=i, column=j)
            button.bind("<Button-1>", lambda event, row=i, col=j: self.left_click(event, row, col))
            button.bind("<Button-3>", lambda event, row=i, col=j: self.toggle_flag(event, row, col))
            self.buttons[i][j] = button

这段代码定义了create_board方法,用于在游戏界面上创建按钮,通过bind方法绑定左键点击和右键点击事件。
4.放置地雷

def place_mines(self):
    mines = self.mines
    while mines > 0:
        row = random.randint(0, self.rows - 1)
        col = random.randint(0, self.cols - 1)
        if self.board[row][col] == 0:
            self.board[row][col] = -1
            mines -= 1

这段代码定义了place_mines方法,用于在游戏板上随机放置地雷。

5.计算地雷数

def calculate_numbers(self):
    for i in range(self.rows):
        for j in range(self.cols):
            if self.board[i][j] == -1:
                continue
            count = 0
            for ii in range(max(0, i-1), min(self.rows, i+2)):
                for jj in range(max(0, j-1), min(self.cols, j+2)):
                    if self.board[ii][jj] == -1:
                        count += 1
            self.board[i][j] = count

这段代码定义了calculate_numbers方法,用于计算每个格子周围的地雷数量,并更新游戏板。

6.展示状态

def draw(self):
    for i in range(self.rows):
        for j in range(self.cols):
            if self.clicked[i][j]:
                if self.board[i][j] == -1:
                    self.buttons[i][j]['text'] = '*'
                elif self.board[i][j] == 0:
                    self.buttons[i][j]['text'] = ' '
                else:
                    self.buttons[i][j]['text'] = str(self.board[i][j])
            elif self.flags[i][j]:
                self.buttons[i][j]['text'] = 'P'
            else:
                self.buttons[i][j]['text'] = ' '

这段代码定义了draw方法,根据游戏状态更新界面显示,展示点击过的格子的状态和数字,以及插旗状态。

7.处理左键点击事件

def left_click(self, event, row, col):
    if self.clicked[row][col] or self.flags[row][col]:
        return
    if self.board[row][col] == -1:
        tkMessageBox.showinfo("Game Over", "You clicked on a mine! Game Over.")
    else:
        self.clicked[row][col] = True
        if self.board[row][col] == 0:
            self.clear_empty_cells(row, col)
    self.draw()

这段代码定义了left_click方法,处理左键点击事件。如果点击的是地雷,则游戏结束,显示游戏结束的消息;否则标记该格子为已点击,并清除周围的空格子。最后更新游戏界面。

8.标记功能

def toggle_flag(self, event, row, col):
    if self.clicked[row][col]:
        return
    self.flags[row][col] = not self.flags[row][col]
    self.draw()

这段代码定义了toggle_flag方法,处理右键点击事件。如果点击的是已经点击的格子,则不做任何操作。否则,在插旗状态和非插旗状态之间切换,并更新游戏界面。

9.清除空格

def clear_empty_cells(self, row, col):
    for i in range(max(0, row-1), min(self.rows, row+2)):
        for j in range(max(0, col-1), min(self.cols, col+2)):
            if not self.clicked[i][j]:
                self.clicked[i][j] = True
                if self.board[i][j] == 0:
                    self.clear_empty_cells(i, j)

这段代码定义了clear_empty_cells方法,用于清除周围的空格子。在点击到一个空格子后,递归地清除其周围的其他空格子,直到所有与空格子相邻的空格子都被清除。

10.主函数

if __name__ == '__main__':
    root = Tk()
    root.title('Minesweeper')
    
    rows, cols, mines = 10, 10, 10
    game = Minesweeper(root, rows, cols, mines)
    
    root.mainloop()

这段代码是主函数部分,用于创建游戏的窗口并运行游戏。首先创建了一个Tk实例作为游戏窗口,设置窗口标题为'Minesweeper'。然后初始化游戏的行数、列数和地雷数,创建Minesweeper类的实例并将游戏窗口和参数传入。最后通过调用root.mainloop()来启动游戏的主循环,使游戏界面显示出来并等待用户与游戏交互。

完整代码


import tkinter as tk
import tkinter.messagebox as tkMessageBox
import random

class Minesweeper:
    def __init__(self, master, rows=10, cols=10, mines=10):
        self.master = master
        self.rows = rows
        self.cols = cols
        self.mines = mines
        self.board = [[0 for _ in range(cols)] for _ in range(rows)]
        self.clicked = [[False for _ in range(cols)] for _ in range(rows)]
        self.flags = [[False for _ in range(cols)] for _ in range(rows)]
        self.buttons = [[None for _ in range(cols)] for _ in range(rows)]
        self.create_board()
        self.place_mines()
        self.calculate_numbers()
        self.draw()

    def create_board(self):
        for i in range(self.rows):
            for j in range(self.cols):
                button = tk.Button(self.master, width=2, command=lambda i=i, j=j: self.left_click(i, j))
                button.grid(row=i, column=j)
                button.bind("<Button-3>", lambda event, i=i, j=j: self.toggle_flag(event, i, j))
                self.buttons[i][j] = button

    def place_mines(self):
        mines_placed = 0
        while mines_placed < self.mines:
            row = random.randint(0, self.rows - 1)
            col = random.randint(0, self.cols - 1)
            if self.board[row][col] != -1:
                self.board[row][col] = -1
                mines_placed += 1

    def calculate_numbers(self):
        for i in range(self.rows):
            for j in range(self.cols):
                if self.board[i][j] == -1:
                    continue
                count = 0
                for r in range(i-1, i+2):
                    for c in range(j-1, j+2):
                        if 0 <= r < self.rows and 0 <= c < self.cols and self.board[r][c] == -1:
                            count += 1
                self.board[i][j] = count

    def draw(self):
        for i in range(self.rows):
            for j in range(self.cols):
                if self.clicked[i][j]:
                    if self.board[i][j] == -1:
                        self.buttons[i][j].config(text="X", state=tk.DISABLED)
                    else:
                        self.buttons[i][j].config(text=str(self.board[i][j]), state=tk.DISABLED)
                elif self.flags[i][j]:
                    self.buttons[i][j].config(text="F", state=tk.NORMAL, fg="red")
                else:
                    self.buttons[i][j].config(text="", state=tk.NORMAL, fg="black")

    def left_click(self, row, col):
        if not self.clicked[row][col] and not self.flags[row][col]:
            self.clicked[row][col] = True
            if self.board[row][col] == -1:
                tkMessageBox.showinfo("Game Over", "You clicked on a mine! Game over.")
                self.reveal_all_mines()
            elif self.board[row][col] == 0:
                self.expand_empty(row, col)
            self.draw()
            if self.check_win():
                tkMessageBox.showinfo("Congratulations", "You win!")

    def toggle_flag(self, event, row, col):
        if not self.clicked[row][col]:
            self.flags[row][col] = not self.flags[row][col]
            self.draw()

    def expand_empty(self, row, col):
        if self.board[row][col] == 0:
            self.buttons[row][col].config(text="", state=tk.DISABLED)
            for r in range(row - 1, row + 2):
                for c in range(col - 1, col + 2):
                    if 0 <= r < self.rows and 0 <= c < self.cols:
                        self.left_click(r, c)

    def reveal_all_mines(self):
        for i in range(self.rows):
            for j in range(self.cols):
                if self.board[i][j] == -1:
                    self.buttons[i][j].config(text="X", state=tk.DISABLED)

    def check_win(self):
        for i in range(self.rows):
            for j in range(self.cols):
                if not self.clicked[i][j] and self.board[i][j] != -1:
                    return False
        return True

def main():
    root = tk.Tk()
    root.title('Minesweeper')
    game = Minesweeper(root)
    root.mainloop()

if __name__ == "__main__":
    main()

演示视频
屏幕录制 2024-05-28 221536.mp4
https://www.alipan.com/s/NFMoM6DuQGE
点击链接保存,或者复制本段内容,打开「阿里云盘」APP ,无需下载极速在线查看,视频原画倍速播放。

  1. 实验过程中遇到的问题和解决过程
    问题及解决方法:
    问题1:初步编写时,考虑到windows扫雷游戏中有直接清除空格子的功能,但对于代码实现存在疑问
    问题1解决方法:经过网上查询,采用了递归的方法,清除所有相邻空格子
    问题2:对于左右键点击功能的实现不了解,存在困惑
    问题2解决方法:查询资料,了解到了编写Minesweeper类游戏逻辑的重要方法,同时了解了需要导入哪些函数
    问题3:对于扫雷的数字表示是如何生成的一开始理解有误
    问题3解决方法:经过思考,了解到实际上数字在一开始便生成好了,更新的只是格子的显示状态,解决了问题

实验四感想体会
通过在实验四编写这段代码,我对Python的基本语法和数据结构有了更深入的了解。在编写扫雷游戏的过程中,我学到了很多关于Python编程和游戏开发的具体知识,:
我学习了如何使用Python的GUI库,如tkinter或pygame,设计游戏界面,包括绘制游戏界面、响应用户操作等。
首先,在编写扫雷游戏时,涉及到了一些算法设计,如雷区生成算法、周围雷数计算等,通过解决这些问题,提升了算法设计和优化能力。我还复习了如何使用Python的调试工具进行代码调试,定位和解决bug。了解了Minesweeper类游戏逻辑,同时,通过优化代码逻辑和算法,提高代码执行效率。这也是我第一次编写游戏,是一次全新的体验,不禁让我感叹很多看上去很简单的游戏,背后是一个程序员无尽的脱发和艰辛【哭】
这些具体知识和技能的学习,让我在Python编程和游戏开发方面有了更深入的了解和实践经验,为我的学习打下了坚实的基础。

课程总结
在过去的几个月里,我参与了Python程序设计这门课程的学习,可谓是受益匪浅。最初我选择这门课的原因在于,我们的大学生创业项目要求利用python进行相关研究,包括音频分析与图谱生成,恰好学校开设了这门课程,我便欣然选择了这门课程。由于有c语言学习的基础,在学习python时能够理解编程的基本思想,例如面向用户和面向对象的编程,这是我们的一大优势,但是在学习的过程中我也认识到他与c语言编程存在显著的区别,总体看上去,python的库相对较多,语法也相对更好理解,例如print的输出不强制要求规定格式,但是其格式相对严格,对于缩进有着很严格的要求,两者各有优势,同时,在后续的学习中,我学习了python中函数的定义、调用、参数传递、返回值等高级知识,提高了代码的可读性和可维护性,同时也使代码更为灵活,同时我还学习了之前所没有学过的web编程和爬虫技术,使我了解到python在功能上的多样性,其应用范围更广更宽,这也是为什么近年来python的使用率在逐年上升。总的来讲,python是一名使用且相对简明的语言,十分值得学习,通过这次的课程,我很自豪我获得了一项新的技能,拓宽了新的视野,了解了一门新的编程语言,去实现更多的功能,我们的项目也得以进行了有力推进,我十分感谢这门课程所带给我的丰富的知识!
以那句话结尾吧——“人生苦短,我用Python!”

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

110

社区成员

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

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