20234206 2023-2024-2 《Python程序设计》综合实践
课程:《Python程序设计》
班级:2342
姓名:郑皓文
学号:20234206
实验教师:王志强
实验日期:2024年5月27日
必修/选修: 专选课
一、实验内容
利用Python软件编写小游戏程序:扫雷
二、实验过程
1.编程需求分析
扫雷小游戏是一款经典单人电脑游戏,核心玩法是在网格中,在避开有地雷的格子的前提下,揭开所有没有地雷的格子。因此,我们需要按照以下几个步骤来设计编码:
(1)创建网格
(2)随机安置一定数量的地雷
(3)让玩家填写坐标来揭开格子
(4)判断被揭开的格子是否有雷
(5)如果没有地雷,则计算周围地雷数量。如果有地雷,则提示游戏结束
(6)如果将所有没有地雷的格子揭开,则提示玩家获胜
2.初次代码编写尝试
在具体编写过程中,我将创建网格和地雷数这个步骤设置为玩家自由输入,参照课本《零基础学Python》,在网上查询资料、与其他同学讨论、最后由AI检查后,完成初次代码编写。
以下是我的初次代码编写:
import random print("欢迎来到扫雷") print("行列数均从0开始计算") def create_mine_field(rows, cols, num_mines): minefield = [[0 for _ in range(cols)] for _ in range(rows)] mines_placed = 0 while mines_placed < num_mines: row = random.randint(0, rows - 1) col = random.randint(0, cols - 1) if minefield[row][col] != -1: minefield[row][col] = -1 mines_placed += 1 for row in range(rows): for col in range(cols): if minefield[row][col] == -1: continue for r in range(max(0, row - 1), min(rows, row + 2)): for c in range(max(0, col - 1), min(cols, col + 2)): if minefield[r][c] == -1: minefield[row][col] += 1 return minefield def reveal_square(minefield, revealed, row, col): if row < 0 or row >= len(minefield) or col < 0 or col >= len(minefield[0]) or revealed[row][col]: return False revealed[row][col] = True if minefield[row][col] == -1: return "踩到雷啦" if minefield[row][col] == 0: for r in range(max(0, row - 1), min(len(minefield), row + 2)): for c in range(max(0, col - 1), min(len(minefield[0]), col + 2)): reveal_square(minefield, revealed, r, c) return None def display_mine_field(revealed, minefield): for row in range(len(minefield)): for col in range(len(minefield[0])): if revealed[row][col]: if minefield[row][col] == -1: print("X", end=" ") else: print(minefield[row][col], end=" ") else: print(".", end=" ") print() def all_non_mines_revealed(revealed, minefield): revealed_count = sum(row.count(True) for row in revealed) mine_count = sum(row.count(-1) for row in minefield) total_cells = len(minefield) * len(minefield[0]) return revealed_count == total_cells - mine_count def play_minesweeper(): rows =int(input("本次游戏行数为:")) cols =int(input("本次游戏列数为:")) num_mines = int(input("本次游戏炸弹个数为:")) minefield = create_mine_field(rows, cols, num_mines) revealed = [[False for _ in range(cols)] for _ in range(rows)] while True: display_mine_field(revealed, minefield) try: row = int(input("第几行: ")) col = int(input("第几列 : ")) except ValueError: print("请输入有效的数字。") continue result = reveal_square(minefield, revealed, row, col) if result: print(result) break elif all_non_mines_revealed(revealed, minefield): print("恭喜完成扫雷!") break play_minesweeper()
我反复测试代码,查找错误,最后得到正确运行成果:
3.二次代码修改尝试
但是,由上面这张图片可以看出,按照这个代码编写出来并不能以小窗口的形式呈现。同时另一个局限性是只能通过填写坐标的方式确定揭开的格子所在行列,这种方式不仅在网格数较多的时候比较麻烦,而且只能从0开始计数,相对比较容易犯错。因此,我在其他同学建议下开始学习如何制作小窗口游戏。学习之后,我了解到tkinter库以及其他函数的运用。
于是,我对之前已经编写好的扫雷代码进行了修改,使得它在运行过程中可以以小窗口方式呈现:
import random import tkinter as tk def create_mine_field(rows, cols, num_mines): minefield = [[0 for _ in range(cols)] for _ in range(rows)] mines_placed = 0 while mines_placed < num_mines: row = random.randint(0, rows - 1) col = random.randint(0, cols - 1) if minefield[row][col] != -1: minefield[row][col] = -1 mines_placed += 1 for row in range(rows): for col in range(cols): if minefield[row][col] == -1: continue for r in range(max(0, row - 1), min(rows, row + 2)): for c in range(max(0, col - 1), min(cols, col + 2)): if minefield[r][c] == -1: minefield[row][col] += 1 return minefield def reveal_square(minefield, revealed, row, col): if row < 0 or row >= len(minefield) or col < 0 or col >= len(minefield[0]) or revealed[row][col]: return False revealed[row][col] = True if minefield[row][col] == -1: return "踩到雷啦" if minefield[row][col] == 0: for r in range(max(0, row - 1), min(len(minefield), row + 2)): for c in range(max(0, col - 1), min(len(minefield[0]), col + 2)): reveal_square(minefield, revealed, r, c) return None def all_non_mines_revealed(revealed, minefield): revealed_count = sum(row.count(True) for row in revealed) mine_count = sum(row.count(-1) for row in minefield) total_cells = len(minefield) * len(minefield[0]) return revealed_count == total_cells - mine_count def on_square_click(event): row = event.widget.grid_info()['row'] col = event.widget.grid_info()['column'] result = reveal_square(minefield, revealed, row, col) if result: print(result) for widget in minefield_frame.winfo_children(): widget.unbind('<Button-1>') elif all_non_mines_revealed(revealed, minefield): print("恭喜完成扫雷!") for widget in minefield_frame.winfo_children(): widget.unbind('<Button-1>') update_display() def update_display(): for row in range(rows): for col in range(cols): button = minefield_frame.grid_slaves(row=row, column=col)[0] if revealed[row][col]: if minefield[row][col] == -1: button.config(text="X", bg="red") else: button.config(text=str(minefield[row][col]), bg="white") else: button.config(text="", bg="gray") rows = int(input("本次游戏行数为:")) cols = int(input("本次游戏列数为:")) num_mines = int(input("本次游戏炸弹个数为:")) minefield = create_mine_field(rows, cols, num_mines) revealed = [[False for _ in range(cols)] for _ in range(rows)] root = tk.Tk() root.title("扫雷游戏") minefield_frame = tk.Frame(root) minefield_frame.pack() for row in range(rows): for col in range(cols): button = tk.Button(minefield_frame, width=2, height=1) button.grid(row=row, column=col) button.bind('<Button-1>', on_square_click) update_display() root.mainloop()
4.编写思路
第一,我导入random库和tkinter库,用于生成随机数,并且创建游戏界面
第二,提示用户输入行列数和地雷数量,并设置参数,从而生成游戏界面
第三,在创建雷区的时候我运用create_mine_field函数,将所有值初始化为0,随机设置地雷,并将地雷设置为-1,非地雷单元格计算周围地雷数并记录
第四,在揭示方块的时候,我选择使用reveal_square和all_non_mines_revealed函数,首先检查揭示位置是否有效(边界和是否已经揭示),并检查是否有地雷,如果有则提示游戏结束。其次检查是否所有位置都已揭示,如果是,则提示游戏结束。
第五,创建一个tkinter的root,设置好minefield_frame框架,从而用按钮表示各个单元格坐标,从而将玩家的点击事件和其他计算函数相连接
第六,利用update_display函数,对整个游戏作更新显示。
第七,设置主循环,并且初始化窗口和按钮,让游戏编码可以进入事件循环
5.成果展示
扫雷游戏
三、实验中遇到的问题
由于自身学识有限,我在实际编写的时候遇到了许多问题,比如对于需要使用的函数并不了解,还有缩进以及函数运用的先后顺序。因此,在编写的过程中,我查找课本《零基础学Python》中的知识,与其他基础更好的同学们交流学习并且多次利用Pycharm自带的系统检查功能查找错误,最后再使用AI系统对代码进行检查。
这让我了解到,Python程序设计中,编写过程虽然复杂,但是也只是第一步,查找错误、修改代码同样也是非常重要的。就好像在学习生活中,我们不能只想着做完事情,还要学会查漏补缺,将事情做的没有漏洞,才算做好。
四、学习感悟
实际上,在Python这类计算机程序设计上,我并没有很好的基础,学习起来也相对吃力。但是,我十分感谢王老师幽默风趣的教学风格,还有认真负责的教学风格。在学习过程中,我对于Python的理解更加深入,最后终于完成了这个小游戏的设计。虽然扫雷只是一个相对简单的单人单机游戏,编码设计也不算复杂,但是对我来说依然很有纪念意义,而我也有了很深刻的感悟。
首先,Python的使用范围十分广泛,无论是程序设计还是爬虫,在充分利用的情况下都可以对我们的工作生活有很大的作用。
其次,我们在学习Python等程序设计的时候,应当充分利用手边资源。教材、课堂学习、网络资源、AI系统都是非常优质的资源。但是我们同样要意识到,不能由于AI的便捷性产生依赖心理,只是简单使用AI编写程序就草草了事,更重要的是对编写过程的学习,最后掌握成自我的知识。
最后,对于课堂,我认为王老师的讲述已经十分充分,涉及各个方面,也会给我们找寻许多案例供同学们参考。希望王老师可以保持自己的个性风格,就已经很棒啦 :)