20244105 实验四《Python程序设计》实验报告
20244105 2024-2025-2 《Python程序设计》实验四报告
课程:《Python程序设计》
班级: 2441
姓名: 高睿晗
学号:20244105
实验教师:王志强
实验日期:2025年5月20——30日
必修/选修: 公选课
1.实验内容
Python综合应用:爬虫、数据处理、可视化、机器学习、神经网络、游戏、网络安全等。
例如:编写从社交网络爬取数据,实现可视化舆情监控或者情感分析。
例如:利用公开数据集,开展图像分类、恶意软件检测等
例如:利用Python库,基于OCR技术实现自动化提取图片中数据,并填入excel中。
例如:爬取天气数据,实现自动化微信提醒
例如:利用爬虫,实现自动化下载网站视频、文件等。
例如:编写小游戏:坦克大战、贪吃蛇、扫雷等等
注:在Windows/Linux系统上使用VIM、PDB、IDLE、Pycharm等工具编程实现。
2. 实验过程及结果
在本次实验中,我综合考虑了Python各个板块的知识和个人的能力与爱好,选择编写一个简易版消消乐游戏的程序。
消消乐是一个经典的三消类游戏,在游戏中,玩家通过鼠标点击以及键盘控制移动方块,当横向或纵向出现3个或更多连续相同颜色的方块时,这些方块会被消除,消除的方块会消失并得分。
实验设计
本次实验的整体设计对我而言是一个不小的挑战,为了实现游戏中的某些功能的正常运行,需要使用一些之前从未接触过的模块及函数。经过上网查找相关资料,学习相关知识,我初步完成了实验整体框架的设计——
首先,本实验需通过 Pygame 库实现游戏页面的正常运行,同时我需要引入几个模块,以实现游戏的运行:
init_game()——对游戏进行初始化,生成棋盘。
draw_game()——设计游戏页面,用不同颜色绘制方块,紫色边框标记选中方块,并显示分数和操作提示。
check_matches()——在棋盘中查找横向或纵向连成三个及以上的方块。
update_game()——将匹配方块置0并计算下落。
ensure_valid_board()——防止出现同一颜色的方块剩余个数不足三个的情况。
以下是具体的实验过程:
(1)首先,为了保障游戏页面的成功运行,我在PyCharm软件包中搜索并下载了Pygame。

(2)然后对游戏进行初始化。首先导入Pygame用于游戏的开发,导入random以便随机生成游戏元素。使用pygame.init()对Pygame进行初始化。

接着设计游戏页面,尽可能实现游戏窗口的美观性,通过SCREEN_WIDTH,SCREEN_HEIGHT=400,550定义窗口尺寸;设置标题为“PythonPygame消消乐”;通过font=pygame.font.SysFont(["SimHei","Arial"],36)orpygame.font.Font(None,36)尝试设置字体。
定义游戏中方块的颜色,如RED、YELLOW等;定义方块尺寸GRID_SIZE、棋盘行列数ROWS,COLS、每个消除方块的得分SCORE_PER_TILE;游戏状态GAME_PLAYING和GAME_WON,用于表示游戏进行中与胜利状态。

(3)应用init_game()函数初始化消消乐游戏,通过while函数构建循环。使用[random.randint(1,5)for_inrange(COLS)]for_inrange(ROWS)生成二维列表,其中每个元素是1到5之间的随机整数,代表不同颜色的方块。通过all(sum(row.count(c)forrowinboard)>=3forcinrange(1,6))检查每种颜色(1-5)在棋盘board中的数量是否都至少为3个。若满足该条件,说明棋盘布局合理,避免无法完成消除。

(4)下面使用draw_game()绘制游戏界面。首先,通过screen.fill(BLACK)让黑色填充整个屏幕。然后,通过两层嵌套的for循环遍历棋盘的每一个格子。根据GRID_SIZE确定方块在屏幕上的区域,使用pygame.draw.rect函数,依据方块颜色编号选择对应的颜色绘制方块填充区域,再绘制宽度为2的黑色边框;之后,使用font.render生成方块中心表示颜色编号的文本,并通过screen.blit将其绘制在方块中心位置;若selected与当前方块坐标(row,col)相等,说明当前方块是被选中状态,为了让用户看的更清楚,则再绘制一个宽度为4的紫色边框来突出显示选中状态。

(5)接着在游戏界面上绘制文字信息。通过font.render使用之前定义的字体,以白色渲染显示当前分数的文本,文本内容为“分数:具体分数值”,再通过screen.blit将渲染后的文本绘制到屏幕上指定位置,让玩家能实时看到自己的得分。设置提示文本"鼠标选择方块,方向键移动,空格确认,R键重置",然后将其绘制在屏幕上稍低于分数显示的位置,帮助玩家了解游戏玩法。

(6)接着绘制游戏胜利界面的部分。当游戏状态state等于GAME_WON时,使用之前定义的字体分别渲染“恭喜胜利!”文本和最终分数文本,让玩家在游戏胜利时能看到祝贺信息和最终得分。

(7)下面运用check_matches()函数检测棋盘上可消除的方块组合。创建一个空集合matches,用于存储可消除方块的坐标。接着,通过两层嵌套循环遍历棋盘的每一行,在每行中从左到右检查连续三个方块,当这三个方块颜色相同时,将它们的坐标添加到集合matches中,以此检测水平方向的可消除组合。再通过另外两层嵌套循环遍历棋盘的每一列,从上到下检查连续三个方块,若这三个方块颜色相同,就把它们的坐标添加到集合matches,用于检测垂直方向的可消除组合。这一步骤为之后的消除操作提供了依据。

(8)通过update_game()函数更新游戏状态。接收棋盘、要消除的方块坐标集合以及当前分数作为参数,将对应的棋盘方块值设为0来表示消除,并按每个方块对应的分数增加当前分数。接着,按列处理方块下落,对每一列分别找出空行和有方块的行(filled列表存储有方块的行号),然后通过遍历空行列表,将有方块行中的方块依次下移到空行位置,实现方块下落效果。最后,检查整个棋盘是否所有方块都为0,若全为0则表示游戏胜利,返回更新后的分数score和游戏胜利状态GAME_WON。

(9)通过ensure_valid_board()函数确保棋盘状态始终满足可消除条件。若发现某种颜色的数量大于0且小于3,意味着该颜色方块数量过少,难以形成可消除组合。此时,从数量不少于3的颜色中随机选择一种作为替换颜色。

(10)调用init_game()函数,获取游戏初始化的结果,分别将返回的棋盘状态赋值给board、当前选中方块状态赋值给selected、初始分数赋值给score、游戏初始状态赋值给game_state,为游戏启动准备好初始数据。创建一个Clock对象,用于控制游戏的帧率。在Pygame中,通过该对象可以设置每秒的帧数,从而控制游戏画面更新的速度,避免游戏运行过快或过慢,保证游戏的流畅性和稳定性。

(11)下面编写游戏的主循环代码。通过while函数构建循环,持续运行游戏。每次循环先调用draw_game()渲染游戏画面,呈现棋盘、分数等信息。接着,使用pygame.event.get()遍历用户输入事件:若event.type是pygame.QUIT,即用户点击关闭窗口,调用pygame.quit()退出Pygame并结束程序;若为pygame.KEYDOWN(按键按下事件),按R键时重新初始化游戏;游戏进行中且有方块选中时,方向键可移动选中方块,按空格键则检测可消除方块,有可消除方块时更新游戏状态,并在未胜利时修复棋盘,之后取消方块选中;若event.type是pygame.MOUSEBUTTONDOWN且鼠标左键点击(event.button==1),在游戏进行中且点击位置在棋盘内时,选中对应方块。

(12)最后,通过pygame.display.flip()更新整个显示表面到屏幕上,在每次绘制完游戏画面后调用,将内存中绘制好的图像显示出来,保证玩家能看到最新画面。通过clock.tick(30)设置游戏帧率为每秒30帧,通过控制循环执行速度,避免游戏画面更新过快或过慢,维持稳定流畅的游戏体验。

至此,游戏程序已全部编写完成,我尝试运行了游戏程序,用鼠标点击任意一个方块,选中的方块会被紫色边框高亮显示。选中方块后,通过键盘方向键可以将选中的方块与相邻方块交换位置。移动完成后,按空格键确认操作,当横向或纵向出现3个或更多连续相同颜色的方块时,这些方块会被消除。消除的方块会消失并得分。经测试,程序运行正常!!!(完结撒花~)


程序源代码如下:
点击查看代码
import pygame, random
pygame.init()
SCREEN_WIDTH, SCREEN_HEIGHT = 400, 550
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption("Python Pygame 消消乐")
font = pygame.font.SysFont(["SimHei", "Arial"], 36) or pygame.font.Font(None, 36)
WHITE, BLACK, RED, GREEN, BLUE, YELLOW, PURPLE = (
(255, 255, 255), (0, 0, 0), (255, 0, 0), (0, 255, 0),
(0, 0, 255), (255, 255, 0), (128, 0, 128)
)
GRID_SIZE, ROWS, COLS, SCORE_PER_TILE = 80, 5, 5, 10
GAME_PLAYING, GAME_WON = 0, 1
def init_game():
while True:
board = [[random.randint(1, 5) for _ in range(COLS)] for _ in range(ROWS)]
if all(sum(row.count(c) for row in board) >= 3 for c in range(1, 6)):
return board, None, 0, GAME_PLAYING
def draw_game(board, selected, score, state):
screen.fill(BLACK)
for row in range(ROWS):
for col in range(COLS):
if board[row][col]:
rect = pygame.Rect(col * GRID_SIZE, row * GRID_SIZE, GRID_SIZE, GRID_SIZE)
pygame.draw.rect(screen, [RED, GREEN, BLUE, YELLOW, WHITE][board[row][col] - 1], rect)
pygame.draw.rect(screen, BLACK, rect, 2)
screen.blit(font.render(str(board[row][col]), True, BLACK),
font.render(str(board[row][col]), True, BLACK).get_rect(center=rect.center))
if selected == (row, col):
pygame.draw.rect(screen, PURPLE, rect, 4)
screen.blit(font.render(f"分数: {score}", True, WHITE), (10, ROWS * GRID_SIZE + 10))
screen.blit(font.render("鼠标选择方块,方向键移动,空格确认,R键重置", True, WHITE), (10, ROWS * GRID_SIZE + 50))
if state == GAME_WON:
s = pygame.Surface((SCREEN_WIDTH, SCREEN_HEIGHT), pygame.SRCALPHA)
s.fill((0, 0, 0, 180))
screen.blit(s, (0, 0))
screen.blit(font.render("恭喜胜利!", True, YELLOW),
font.render("恭喜胜利!", True, YELLOW).get_rect(center=(SCREEN_WIDTH // 2, SCREEN_HEIGHT // 2)))
screen.blit(font.render(f"分数: {score}", True, WHITE),
font.render(f"分数: {score}", True, WHITE).get_rect(
center=(SCREEN_WIDTH // 2, SCREEN_HEIGHT // 2 + 40)))
def check_matches(board):
matches = set()
for row in range(ROWS):
for col in range(COLS - 2):
if board[row][col] == board[row][col + 1] == board[row][col + 2] != 0:
matches.update([(row, col), (row, col + 1), (row, col + 2)])
for col in range(COLS):
for row in range(ROWS - 2):
if board[row][col] == board[row + 1][col] == board[row + 2][col] != 0:
matches.update([(row, col), (row + 1, col), (row + 2, col)])
return matches
def update_game(board, eliminated, score):
for row, col in eliminated:
board[row][col] = 0
score += SCORE_PER_TILE
for col in range(COLS):
empty = [row for row in range(ROWS) if board[row][col] == 0]
filled = [row for row in range(ROWS) if board[row][col] != 0]
for idx, row in enumerate(empty):
if idx < len(filled):
board[row][col] = board[filled[-(idx + 1)]][col]
board[filled[-(idx + 1)]][col] = 0
return score, GAME_WON if all(all(cell == 0 for cell in row) for row in board) else GAME_PLAYING
def ensure_valid_board(board):
counts = [sum(row.count(c) for row in board) for c in range(6)]
for c in range(1, 6):
if 0 < counts[c] < 3:
replace_c = random.choice([k for k in range(1, 6) if counts[k] >= 3])
for i in range(ROWS):
for j in range(COLS):
if board[i][j] == c:
board[i][j] = replace_c
counts[c] -= 1
counts[replace_c] += 1
if counts[c] == 0:
return board
return board
board, selected, score, game_state = init_game()
clock = pygame.time.Clock()
while True:
draw_game(board, selected, score, game_state)
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
exit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_r:
board, selected, score, game_state = init_game()
elif game_state == GAME_PLAYING and selected:
row, col = selected
if event.key == pygame.K_UP and row > 0:
board[row][col], board[row - 1][col] = board[row - 1][col], board[row][col]
selected = (row - 1, col)
elif event.key == pygame.K_DOWN and row < ROWS - 1:
board[row][col], board[row + 1][col] = board[row + 1][col], board[row][col]
selected = (row + 1, col)
elif event.key == pygame.K_LEFT and col > 0:
board[row][col], board[row][col - 1] = board[row][col - 1], board[row][col]
selected = (row, col - 1)
elif event.key == pygame.K_RIGHT and col < COLS - 1:
board[row][col], board[row][col + 1] = board[row][col + 1], board[row][col]
selected = (row, col + 1)
elif event.key == pygame.K_SPACE:
eliminated = check_matches(board)
if eliminated:
score, game_state = update_game(board, eliminated, score)
if game_state != GAME_WON:
board = ensure_valid_board(board)
selected = None
elif event.type == pygame.MOUSEBUTTONDOWN and event.button == 1 and game_state == GAME_PLAYING:
row, col = event.pos[1] // GRID_SIZE, event.pos[0] // GRID_SIZE
if 0 <= row < ROWS and 0 <= col < COLS:
selected = (row, col)
pygame.display.flip()
clock.tick(30)
3. 实验过程中遇到的问题和解决过程
- 问题1:游戏程序较为复杂,涉及大量知识盲区。
- 问题1解决方案:通过上网搜集资料,适当运用AI工具以及小红书、B站等网络平台进行自主学习。
- 问题2:游戏功能不够完善,游戏操作有难度。
- 问题2解决方案:通过搜集相关资料,反复修改代码,最终实现了鼠标与键盘双重控制游戏,使得操作更为便捷;同时,通过不断优化游戏界面,增加胜利提示等功能,使得游戏越来越完善。
实验总结
本次实验对于我来说是一次极大的挑战,实验中涉及的知识盲区之多,让我一度非常迷茫,不知从何处下手。最初编写的代码试运行时,游戏的各种功能还十分不完善,我只能通过键盘控制方块的移动,以至于并不能精准选择我想移动的方块,如何实现精准选择与移动方块,成为了困扰我的一大难题。后来我想到,能不能通过编写代码实现鼠标与键盘共同控制完成一次游戏呢?有了这个思路,我通过搜集资料,尝试编写相关代码,最终实现了鼠标与键盘对游戏的共同控制,通过鼠标点击,我可以选择我想移动的方块;通过键盘上的方向键,我可以控制方块的移动方向,当游戏功能终于达到了我预期的效果时,我再一次体会到了Python带给我的大大的成就感!!!
在本次实验编写游戏以及游戏程序试运行的过程中,我也深刻体会到了Python的魅力。每一次的发现问题与解决问题,都是我成长的过程。在相关资料的搜集中,我更好巩固了之前学到的Python相关知识,更学到了诸多关于Python的新知识,同时,这一过程也进一步培养起了我自主学习的能力,这种能力在以后的学习中是十分宝贵的。在此,我要感谢王老师,为我们提供了这次宝贵的学习机会,让我们有机会去深入地了解Python,探索Python的奥秘,感受成功的喜悦!
课程总结
本学期在Python的课堂上,我学到了许多,收获了许多。如果用一个词来概括我的Python学习历程,我想,那就是——突破。
作为一名文科生,我在上大学前从未接触过Python的相关知识,甚至在大学前都不知道有“Python”这一事物的存在(妥妥的纯文科生)直到本学期,我有幸走进了王老师的Python课堂,开启了一场全新的体验。起初,Python的知识在我眼里是抽象的,难懂的,我也自然而然地产生了一种畏难的情绪。然而,在王老师的课堂上,Python好像换了一副面孔,它不再像之前一样那么可怕,在王老师通俗的讲解下,我不那么畏惧它了。从最初的一些基本符号,到后来的一些基本函数和语句,我逐渐了解了Python。在尝试编写代码的过程中,我曾遇到诸多困难,缩进的错误以及符号使用的错误,我已不知道犯过多少次。但每一次查找错误到修正错误的过程,都见证着我的成长与进步。从最初只能输出一句“人生苦短,我用Python”,到后来在老师的指导下成功编写猜数字以及石头剪刀布的游戏程序,“突破”在此刻具象化了。当猜数字小游戏编写并运行成功的时候,我第一次感受到了Python原来也可以这么有趣耶hhh~
后来随着学习的深入,我也越来越体会到了Python功能的强大,第三次实验课给我留下的印象尤为深刻。在那次实验课上,我接触到了socket函数,我和同学相互配合,分别构建服务器与客户端,仅仅通过编写几行代码,就可以实现客户端与服务器之间的对话。当两台电脑成功实现对话时,我被Python的强大功能深深震撼了,虽然在实验过程中曾出现了许多问题,但实验成功带来的成就感,让一切困难都显得微不足道。
Python课程带给我的收获远远不止知识本身。在代码的编写过程中,我进一步培养起了严谨踏实的态度。代码的编写是一个容不得差错的过程,哪怕一个细小到难以引起人注意的错误也可能会导致最后程序运行的失败。经历了多次因缩进错误、符号错误导致的程序运行失败后,我在程序编写中越来越关注每一个看似微不足道的细节,这种严谨细致的态度让我在其他学科的学习中也受益良多。其次,Python综合实践中涉及的知识点之广,更是提升了我自主学习的能力,我学会了如何合理有效利用各种网络资源。对于AI工具的应用,我逐渐学会了辩证看待AI给出的答案,我会在使用AI工具时保持自己的独立思考,在学习中,AI提供给我的只是参考思路而不是最终的答案,最终的答案还需我自己整合所有知识得出。在这一过程中,我提升了自己独立思考与理性判断的能力,这对于我以后的成长也是大有裨益。此外,每一次Python实验中,我逐渐学会勇敢面对一切困难与挑战,在每一个困难的解决中实现自身的突破。
最后,我要再次感谢王老师这一学期的辛苦付出,感谢王老师为我们带来了如此丰富多彩的课程,让我们每一个文科生也能体会到Python的魅力。未来我也会继续探索Python的相关知识,实现自身编程能力与信息素养的进一步突破!
课程建议
建议老师在讲到后面socket函数那里的时候可以稍稍放慢一点速度,因为这里实在是有点抽象耶~
还有就是课上在跟着老师一起编写代码时会有点跟不上,建议可以稍稍放慢一下速度呀嘻嘻(主要是作为文科生,对PyCharm的应用实在是不咋熟练呜呜呜)
别的就没什么啦,老师讲的真的超级好!!!

浙公网安备 33010602011771号