20244124孙文博 实验四Python综合实践

20244124孙文博 2024-2025《Python程序设计》实验四Python综合实践
课程:《Python程序设计》
班级: 2441
姓名: 孙文博
学号:20244124
实验教师:王志强
实验日期:2025年5月13日
必修/选修: 公选课
一、实验要求和分析
(一)实验要求
Python综合应用:爬虫、数据处理、可视化、机器学习、神经网络、游戏、网络安全等。
例如:编写从社交网络爬取数据,实现可视化舆情监控或者情感分析。
例如:利用公开数据集,开展图像分类、恶意软件检测等
例如:利用Python库,基于OCR技术实现自动化提取图片中数据,并填入excel中。
例如:爬取天气数据,实现自动化微信提醒
例如:利用爬虫,实现自动化下载网站视频、文件等。
例如:编写小游戏:坦克大战、贪吃蛇、扫雷等等
(二)实验分析
1.选题分析:本次实验选择面广,实践方向开放。考虑到个人编创兴趣及编程结果的可操作性和运行合法性,综合个人能力水平,我选择了结合大数据模型编创一个俄罗斯方块小游戏。
2.完成思路分析:
(1)在代码编写前学习掌握俄罗斯方块游戏运行的基本流程——即形状生成、方块掉落、位移操作、方块堆砌、满行消除等基本规则并梳理这些步骤的运行顺序。
(2)按顺序理解相应步骤的代码执行基本原理:
①通过列表数字的排布形状定义不同的俄罗斯方块形状,并通过random.随机函数在每次掉落方块初始化前随机生成新形状。
②通过遍历每一行数据确定已有方块的位置,确保新生成形状在掉落过程中不会出现重合等非正常情况。
③通过接入键盘up、down、left、right键实现方块掉落过程中的位移和旋转。
④新方块位置确定后,遍历每一行,找出并删除满格的一个或几个行。
二、实验设计
(一)功能设计
通过方块形状的生成、掉落、拼接、删除实现俄罗斯方块游戏所能实现的各种基本功能。
(二)基础量设计
1.游戏窗口大小:屏幕宽度为400像素,高度为500像素。
2.窗口颜色设计:以黑色为背景,方块形状掉落过程中为红色,掉落后为绿色。
3.单位方块大小:宽和高均为20个像素。
4.生成形状类型:共七种。
5.移动操作方式:共四种,包括左移、右移、加速下落、旋转。
(三)方块位置设计
通过在形状生成和下落中实时更新其包含的所有方块的横纵坐标实现对方块位置的把握,这样的设计思路也有利于对每行进行遍历。
三、实现过程
(一)下载pygame模块并初始化,使用import导入random函数以实现方块形状的随机生成。


(二)创建游戏窗口
1.设置屏幕宽度为400像素,高度为500像素。
2.使用pygame.display.set_caption()函数设置窗口的标题。
3.使用pygame.display.set_caption()函数设置窗口的标题,游戏名称为俄罗斯方块。

(三)定义颜色
1.红绿蓝三个颜色通道全部关闭,无彩色光线,显示结果为黑色。
2.红绿蓝三个颜色通道全部打开,三色调和显示为白色。
3.红蓝通道关闭,只保留绿色通道,显示为绿色。
4.绿蓝通道关闭,只保留红色通道,显示为红色。

(四)设置方块大小
1.规定每个方块像素为20*20。
2.通过对屏幕尺寸除以方块单位尺寸取商确认屏幕范围内在宽和高方向上所能容纳的最多方块数。

(五)定义方块形状
通过分行进行元素状态排列实现对七种不同形状的定义,其中0代表该位置为空,1代表该位置有方块。

  1. [ [1, 1, 1],定义第一种T字形形状
    [0, 1, 0]],

  2. [[0, 2, 2],
    [2, 2, 0]],定义第二种右上拐左下形状

  3. [[3, 3, 0],
    [0, 3, 3]],定义第三种左上拐右下形状

  4. [[4, 0, 0],
    [4, 4, 4]],定义第四种L字形形状

  5. [[0, 0, 5],
    [5, 5, 5]],定义第五种反向L字形形状

  6. [[6, 6, 6, 6]],定义第六种长条形形状

  7. [[7, 7],
    [7, 7]]定义第七种正方形形状

    (六)初始化方块并检验方块下落过程中的合法性
    1.定义生成新方块的new_block函数,随机按照上文定义的结果生成不同类型的形状,将其初始在游戏窗口左上角。
    2.定义check_position函数,board检查方块在游戏某位置放置的可操作性,shape代表方块形状,offset代表图形相对于初始位置(左上角)的偏移量,将偏移量分解为竖直方向和水平方向两部分。
    3.遍历每一行每一列并用try设置异常处理机制以处理可能存在的方块不适配情况——当单元格被占用或超出边界时,将会报错,其他情境下正常运行。

    (七)图形放置
    1.定义join_matrix(mat1, mat2, mat2_off):函数进行方块的放置,mat1是游戏窗格,mat2是被锁定的方块,mat2_off是方块的位移量。将方块位移量分解为水平和竖直两部分。
    2.分别对行和列进行遍历,若cell不为零,则该单元格成为方块的实体部分,需要锁定放置。
    3.将方块的单元格值 cell 复制到游戏板 mat1 的对应位置,y + off_y 和 x + off_x 是方块单元格在游戏板上的实际位置。
    4.返回更新后的mat1,此时游戏窗口页面完成更新。

    (八)检查和清除满行
    1.定义remove_row(board, row)函数设置清除行。
    2.定义一个清除行的函数clear_rows(board),定义列表full_rows用于存储所有满行的索引。
    3.遍历行中的方块,若某一行全部被填满,则用 full_rows.append(i)在满行的函数中追加该行。
    4.删去并返回一个空行。

    (九)编写主游戏循环程序
    1.创建游戏棋盘,grid_width和grid_height分别是棋盘的宽度和高度。
    2.用block表示生成一个新方块,用pygame.time.Clock()创建一个时钟对象clock用于控制游戏的帧率和时间间隔。
    3.当running即运行状态正常时,方块下落速度为500。
    4.在游戏正常状态下,通过screen.fill(black)将背景及时填充为黑色。
    5.用pygame.event.get()函数获取并遍历用户玩家的所有可能操作。若用户主动退出程序,则游戏结束;若按左键,则方块水平向左移动一个单位;若按右键,则方块水平向右移动一个单位;若按下键,则方块加速下落;若按上键,则方块顺时针旋转。左右以及加速操作通过方块整体的水平和竖直坐标变化实现,旋转操作通过代码的排布变化实现。在用户操作过程中,同时用check_position函数对方块形状的位置进行监视以防偏离边界。

    6.方块自然下落中竖直坐标加一,运用check_position()函数检验方块是否触底并继续检测满行情况。
    7.if not check_position(board, block, (block_x, block_y)):是方块触底或与其他方块重叠的情况。
    8.board = join_matrix(board, block, (block_x, block_y - 1))将方块状态退回到上一步。
    9.再次使用clear_rows(board)检测并清除所有满行,然后生成新方块。
    10.if not check_position(board, block, (block_x, block_y)):再次查看方块是否触底或重叠,若是,则游戏结束。

    11.使用enumerate函数遍历非锁定区域,对下落中的方块进行红色填充;遍历锁定区域,对完成下落的方块进行绿色填充。具体操作为以y为索引,row为内容遍历每一行,在每一行以x为索引,cell为内容遍历每一单元格,若cell值不为零则该位置有方块,对其进行相应颜色填充。

    12.调用pygame.display.flip()更新屏幕显示,将绘制的内容显示出来,调用pygame.time.delay(game_speed)将暂停程序一段时间以更新系统,时间间隔为设置的方块下落速度

    (十)退出程序
    1.调用pygame.quit退出程序,关闭窗口。
    2.if name == "main":表示下方的main()即主游戏循环将直接运行。

    四、结果
    程序可以正常运行,方块生成和满行清除功能完善,颜色清晰,不卡顿,游戏体验感良好。

    五、实验中遇到的困难
    (一)部分程序编写难度较大。
    问题解决方案:结合自己书写的前端代码向大数据模型求助,在得到结果后并没有简单复制粘贴,而是仔细思考代码的内在逻辑和每一句代码的实际作用,基本搞懂了每一段代码的运行逻辑。
    (二)方块颜色不会定义。
    问题解决方案:查找相关资料,了解到计算机显示屏由红绿蓝三种光源组成,通过三种光源的开关控制即可调配出不同的颜色。
    六、收获和感悟
    (一)本次实验感悟
    1.在实验设计中全面了解了俄罗斯方块的运行逻辑,确定了窗口布置、方块生成、方块下落控制、方块放置、满行消除的游戏流程顺序。
    2.认真钻研每一步代码的实际意义,成功看懂并理解了代码内在逻辑,在每一行代码后添加了有关自己理解的注释。
    3.本次实验综合运用了函数定义、模块导入、if循环、遍历、列表、文件操作等所学内容,让我对这个学期的学习有了系统的复习和实践意义上的提高。
    (二)课程总结
    本学期的课程对我的学习和工作效率提升具有深远的实践意义。
    首先,我掌握了Python编程的入门知识和基本原理,可以通过书写简单的代码完成诸如石头剪刀布、猜数字等小游戏,也可以通过文件操作编辑日记,还可以运用函数定义、循环语句等编写简单的应用程序(如计算BMI、超市记账等)。这些内容既丰富了我的知识储备,提升了我的理科素养,也让我感受到了“码农”的乐趣,使我改变了对敲代码索然无味的刻板印象。
    其次,我培养了一丝不苟、细致入微的学习习惯,也锻炼了思维方式,提高了理解能力。在Python代码的编写中有很多时刻需要注意的地方,比如说标点符号全部要用英文半角符号,要注意浮点型数据在计算中向其他类型数据的转换、要注意正确的缩进,不能使用Python中的保留字符,英文字母一定要拼写正确且前后变量书写要一致,“=”和“==”的区别要牢记。在代码运行中,往往“差之毫厘谬以千里”,一个个提示的错误总会提醒我细致细致再细致。在学习初期,我对变量的把握一直不是很清晰,比如会疑惑为何前一行定义x=10,后一行又可以定义x=“hello”,后来在请教同学之后,我明白Python作为动态类型语言,变量可以通过重新赋值成为不同类型的数据。类似这样的例子使我对编程语言有了更为深入的理解,也使我有效建立起来了编程逻辑和代码思维。
    最后,我的工作学习效率得到了提升。在学习中,我可以通过爬虫在百度等浏览器或网站上高效查找相关资料;在本月的部门工作中,我应用爬虫对部门征集的文章进行归档分类并保存在电子表格中,告别了一个个手动输入整理的传统方式,实现了工作效率的飞跃,得到了负责人的认可。在今后的学习生活中,我坚信一定会有更多的Python知识与实际需求双向奔赴,让编程和代码真正改变我的大学生活。
    (三)课程建议
    1.本课程确实难度较大,对于行管专业文科的同学来讲更是有着极大的挑战。在课上的确难以理解相关知识点,经常跟不上老师的介绍节奏。建议老师在每周上课前五到六天提前发布预习内容并鼓励同学们先自主学习,对知识框架有一个大致的了解,这样可能有助于改善同学们听不懂的状况。
    2.建议对于较难的实验,比如socket部分内容,老师可适当放慢讲课速度,将每一句代码都讲解得更加细致。
    3.建议老师适当维持课堂秩序,注意课堂纪律,营造更加良好的学习氛围。
    视频:


    【视频作业】 https://www.bilibili.com/video/BV1n2JczzEq1/?share_source=copy_web&vd_source=5c32d81fc3b7b6a0a9548194d788e5d0
    源代码如下:

import random
pygame.init()

screen_width = 400
screen_height = 500
screen = pygame.display.set_mode((screen_width, screen_height))
pygame.display.set_caption("俄罗斯方块")

BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)

block_size = 20
grid_width = screen_width // block_size
grid_height = screen_height // block_size

shapes = [
    [[1, 1, 1],
     [0, 1, 0]],

    [[0, 2, 2],
     [2, 2, 0]],

    [[3, 3, 0],
     [0, 3, 3]],

    [[4, 0, 0],
     [4, 4, 4]],

    [[0, 0, 5],
     [5, 5, 5]],

    [[6, 6, 6, 6]],

    [[7, 7],
     [7, 7]]
]

def new_block():
    return random.choice(shapes), 0, 0
def check_position(board, shape, offset):
    off_x, off_y = offset
    for y, row in enumerate(shape):
        for x, cell in enumerate(row):
            try:
                if cell and board[y + off_y][x + off_x]:
                    return False
            except IndexError:
                return False
    return True
def join_matrix(mat1, mat2, mat2_off):
    off_x, off_y = mat2_off
    for y, row in enumerate(mat2):
        for x, cell in enumerate(row):
            if cell:
                mat1[y + off_y][x + off_x] = cell
    return mat1

def remove_row(board, row):
    del board[row]
    return [[0 for _ in range(grid_width)]] + board
def clear_rows(board):
    full_rows = []
    for i, row in enumerate(board):
        if all(row):
            full_rows.append(i)
    for row in full_rows:
        board = remove_row(board, row)
    return board

def main():
    board = [[0 for _ in range(grid_width)] for _ in range(grid_height)]
    block, block_x, block_y = new_block()
    clock = pygame.time.Clock()#使用pygame.time.Clock()
    running = True
    game_speed = 500 

    while running:
        screen.fill(BLACK)
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_LEFT:
                    new_x = block_x - 1
                    if check_position(board, block, (new_x, block_y)):
                        block_x = new_x
                if event.key == pygame.K_RIGHT:
                    new_x = block_x + 1
                    if check_position(board, block, (new_x, block_y)):
                        block_x = new_x
                if event.key == pygame.K_DOWN:
                    new_y = block_y + 1
                    if check_position(board, block, (block_x, new_y)):
                        block_y = new_y
                if event.key == pygame.K_UP:
                    rotated_block = list(zip(*block[::-1]))
                    if check_position(board, rotated_block, (block_x, block_y)):
                        block = [list(row) for row in rotated_block]

        block_y += 1
        if not check_position(board, block, (block_x, block_y)):
            board = join_matrix(board, block, (block_x, block_y - 1))
            board = clear_rows(board)
            block, block_x, block_y = new_block()
            if not check_position(board, block, (block_x, block_y)):
                running = False

        for y, row in enumerate(board):
            for x, cell in enumerate(row):
                if cell:
                    pygame.draw.rect(screen, GREEN,
                                     (x * block_size, y * block_size, block_size, block_size),
                                     0)

        for y, row in enumerate(block):
            for x, cell in enumerate(row):
                if cell:
                    pygame.draw.rect(screen, RED,
                                     ((block_x + x) * block_size, (block_y + y) * block_size, block_size, block_size),
                                     0)

        pygame.display.flip()
        pygame.time.delay(game_speed)

    pygame.quit()

if __name__ == "__main__":
    main()```
posted @ 2025-05-17 13:22  20244124孙文博  阅读(91)  评论(0)    收藏  举报