20254219 2025-2026-2 《Python程序设计》实验四综合实践

20254219 2025-2026-2 《Python程序设计》实验4 综合实践

课程:《Python程序设计》
班级: 2542
姓名: 施菲特
学号:20254219
实验教师:王志强
实验日期:2026年5月19日~6月7日
必修/选修: 专选课

1.实验内容

(1)具体内容

Python综合应用:爬虫、数据处理、可视化、机器学习、神经网络、游戏、网络安全等。

  • 例如:编写从社交网络爬取数据,实现可视化舆情监控或者情感分析。
  • 例如:利用公开数据集,开展图像分类、恶意软件检测等。
  • 例如:利用Python库,基于OCR技术实现自动化提取图片中数据,并填入excel中。
  • 例如:爬取天气数据,实现自动化微信提醒。
  • 例如:利用爬虫,实现自动化下载网站视频、文件等。
  • 例如:编写小游戏:坦克大战、贪吃蛇、扫雷等等。
    注:在Windows/Linux系统上使用VIM、PDB、IDLE、Pycharm等工具编程实现.

(2)实验要求

  • 程序能运行,功能丰富(至少5个功能),需求提交源代码,并建议录制程序运行的视频。
  • 综合实践报告,要体现实验分析、设计、实现过程、结果等信息,格式规范,逻辑清晰,结构合理。
  • 在实践报告中,需要对全课进行总结,并写课程感想体会、意见和建议等。

2. 实验过程及结果

(一)准备阶段:

程序选择与环境准备
(1)综合Python各版块知识的掌握情况和个人兴趣等因素,我选择设计一款五子棋游戏作为实验四 Python综合实践的实验对象;
(2)首先必须准备好开发环境。因为我们要做图形界面,不能只靠Python原生代码,所以需要安装Pygame;
(3)同时按住“win+R”,打开命令提示符窗口,输入命令“cmd”;
(4)在打开的窗口输入“pip install pygame”并回车结果如下图所示:

image
(5)经查询得到我的电脑上已经安装过版本为2.6.1的pygame了,可以直接进行代码写作。

整体架构设计
(1)在完成五子棋小游戏时,将游戏拆分为多个模块,各个模块分别完成不同的功能,可以提高代码的可维护性和可扩展性。经过综合考虑分析,我将代码设计为:常量配置模块棋盘数据与绘制模块胜负判断模块和主程序事件交互模块。具体设计思路如下图所示:

逻辑
(2)完成基本的程序环境适配与程序架构搭建,接下来就可以进入代码的创作了。

(二)程序实现过程

第一模块:常量配置模块
(1)首当其冲要完成的整个程序最前面的常量配置模块,负责导入库、定义全局常量和颜色。
(2)用import导入pygame库,为程序提供图形绘制、事件响应等功能;
(3)代码中的EMPTY、BLACK、WHITE是用数字统一表示空位置、黑棋、白棋,方便后续逻辑判断;
(4)我学习了RGB的工作原理,了解到每种颜色都有一个强度值,通常用0到255之间的数字表示:0表示该颜色完全关闭,255表示该颜色完全开启。因此我定义黑白棋子的RGB颜色值,统一管理显示样式。
(5)一开始有点不知道怎么去设计,后来想到用数字代替文字,写逻辑更简单、不易出错。所以我把常量写在最前面,后面所有模块都能直接用,不用重复定义。
(6)具体代码与图片如下所示:

点击查看代码
import pygame
# 导入pygame模块
print(pygame.ver)
# 检查pygame的版本,检查pygame有没有导入成功

EMPTY = 0
BLACK = 1
WHITE = 2
# 定义三个常量函数,用来表示白棋,黑棋,以及 空

black_color = [0, 0, 0]
# 定义黑色(黑棋用,画棋盘)
white_color = [255, 255, 255]
# 定义白色(白棋用)

image

第二模块:棋盘数据与绘制模块
(1)其次要完成的是棋盘数据与绘制模块,用类封装棋盘的数据存储、重置、落子和绘制功能。
(2)由于棋盘的设计存数据又要画界面,所以用类把它们放在一起,使代码整体结构变得清晰。
(3)用_init_初始化15×15的棋盘组数,再用reset清空棋盘所有位置设为空,用move去判断位置是否为空,再用draw去绘制棋盘线、外框、天元、星位;
(4)一开始画棋盘时坐标老是对不准,反复调试后,把起点设为(40,40)、格子大小设为40px,才终于将棋盘对齐。
(5)具体代码与图片如下所示:

点击查看代码
# 定义棋盘这个类
class RenjuBoard(object):

    def __init__(self):
        # self._board = board = [[EMPTY] * 15 for _ in range(15)]
        # 将棋盘每一个交叉点都看作列表的一个元素位,一共有15*15共225个元素
        self._board = [[]] * 15
        self.reset()
    #重置棋盘
    def reset(self):
        for row in range(len(self._board)):
            self._board[row] = [EMPTY] * 15
    #定义棋盘上的下棋函数,row表示行,col表示列,is_black表示判断当前点位该下黑棋,还是白棋
    def move(self, row, col, is_black):
        if self._board[row][col] == EMPTY:
            self._board[row][col] = BLACK if is_black else WHITE
            return True
        return False
    # 给棋盘定义一个函数将自己在screen上面画出来,使用pygame.draw()函数。并且顺便将下了的棋子也画出来
    def draw(self, screen):
        for h in range(1, 16):
            pygame.draw.line(screen, black_color,
                             [40, h * 40], [600, h * 40], 1)
            pygame.draw.line(screen, black_color,
                             [h * 40,40], [h * 40, 600], 1)
        # 给棋盘加一个外框,使美观
        pygame.draw.rect(screen, black_color, [36, 36, 568, 568], 3)

        # 在棋盘上标出,天元以及另外4个特殊点位
        pygame.draw.circle(screen, black_color, [320, 320], 5, 0)
        pygame.draw.circle(screen, black_color, [160, 160], 3, 0)
        pygame.draw.circle(screen, black_color, [160, 480], 3, 0)
        pygame.draw.circle(screen, black_color, [480, 160], 3, 0)
        pygame.draw.circle(screen, black_color, [480, 480], 3, 0)
        #做2次for循环取得棋盘上所有交叉点的坐标
        for row in range(len(self._board)):
            for col in range(len(self._board[row])):
                # 将下在棋盘上的棋子画出来
                if self._board[row][col] != EMPTY:
                    ccolor = black_color \
                        if self._board[row][col] == BLACK else white_color
                    # 取得这个交叉点下的棋子的颜色,并将棋子画出来
                    pos = [40 * (col + 1), 40 * (row + 1)]
                    # 画出棋子
                    pygame.draw.circle(screen, ccolor, pos, 18, 0)

image

第三模块:胜负判断模块
(1)然后写胜负判断模块,要让整个程序独立实现五子棋的胜负规则逻辑。
(2)用flag计数连续同色棋子,异色则清零;
(3)任意方向凑够5颗,输出胜负并结束游戏,无胜负则返回True,游戏继续;
(4)胜负判断是整个代码编写过程中最难的一步,要用斜向判断容易数组越界,反复修改坐标范围才能稳定,虽然代码很长,但逻辑很简单:遇到同色就计数,断了就清零,满5就赢
(5)具体代码与图片如下所示:

点击查看代码
# 定义函数,传入当前棋盘上的棋子列表,输出结果,不管黑棋白棋胜,都是传回False,未出结果则为True
def is_win(board):
    for n in range(15):
        # 判断垂直方向胜利
        flag = 0
        # flag是一个标签,表示是否有连续以上五个相同颜色的棋子
        for b in board._board:
            if b[n] == 1:
                flag += 1
                if flag == 5:
                    print('黑棋胜')
                    return False
            else:
            # else表示此时没有连续相同的棋子,标签flag重置为0
                flag = 0

        flag = 0
        for b in board._board:
            if b[n] == 2:
                flag += 1
                if flag == 5:
                    print('白棋胜')
                    return False
            else:
                flag = 0

        # 判断水平方向胜利
        flag = 0
        for b in board._board[n]:
            if b == 1:
                flag += 1
                if flag == 5:
                    print('黑棋胜')
                    return False
            else:
                flag = 0

        flag = 0
        for b in board._board[n]:
            if b == 2:
                flag += 1
                if flag == 5:
                    print('白棋胜')
                    return False
            else:
                flag = 0

        # 判断正斜方向胜利

        for x in range(4, 25):
            flag = 0
            for i,b in enumerate(board._board):
                if 14 >= x - i >= 0 and b[x - i] == 1:
                    flag += 1
                    if flag == 5:
                        print('黑棋胜')
                        return False
                else:
                    flag = 0

        for x in range(4, 25):
            flag = 0
            for i,b in enumerate(board._board):
                if 14 >= x - i >= 0 and b[x - i] == 2:
                    flag += 1
                    if flag == 5:
                        print('白棋胜')
                        return False
                else:
                    flag = 0

        #判断反斜方向胜利
        for x in range(11, -11, -1):
            flag = 0
            for i,b in enumerate(board._board):
                if 0 <= x + i <= 14 and b[x + i] == 1:
                    flag += 1
                    if flag == 5:
                        print('黑棋胜')
                        return False
                else:
                    flag = 0

        for x in range(11, -11, -1):
            flag = 0
            for i,b in enumerate(board._board):
                if 0 <= x + i <= 14 and b[x + i] == 2:
                    flag += 1
                    if flag == 5:
                        print('白棋胜')
                        return False
                else:
                    flag = 0

    return True

image

第四模块:主程序与事件交互模块
(1)最后要写的是主程序与事件交互模块,作为程序入口,统筹整个游戏流程。
(2)首先,编写编写main函数,作为程序入口,统筹整个游戏流程;
(3)初始化Pygame、创建640×640游戏窗口、设置标题和棕黄色背景;
(4)将鼠标点击的像素坐标转换成棋盘行列坐标,调用落子方法;
(5)落子成功后切换棋手、重绘棋盘并刷新画面,每次落子后调用胜负判断函数,分出胜负则结束游戏;
(6)具体代码与图片如下所示:

点击查看代码
def main():
    # 创建棋盘对象
    board = RenjuBoard()
    # 黑棋先手
    is_black = True

    # 初始化窗口
    pygame.init()
    pygame.display.set_caption('五子棋-IT入门')
    screen = pygame.display.set_mode((640,640))
    screen.fill([125,95,24])
    board.draw(screen)
    pygame.display.flip()

    # 主循环
    running = True
    while running:
        for event in pygame.event.get():
            # 关闭窗口
            if event.type == pygame.QUIT:
                running = False
            # 鼠标左键落子
            elif event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
                x, y = event.pos
                # 像素坐标转棋盘行列
                row = round((y - 40) / 40)
                col = round((x - 40) / 40)
                # 落子成功
                if board.move(row, col, is_black):
                    is_black = not is_black
                    screen.fill([125, 95, 24])
                    board.draw(screen)
                    pygame.display.flip()
                    # 判断胜负
                    if not is_win(board):
                        running = False
    pygame.quit()

if __name__ == '__main__':
    main()

image

模块顺序与功能整体微总结

  • 常量配置模块:导入库、定义全局常量;
  • 棋盘数据与绘制模块:封装棋盘数据和绘制;
  • 胜负判断模块:独立实现胜负规则;
  • 主程序与事件交互模块:程序入口,统筹游戏流程。
    这样拆分后,代码结构清晰、职责分明,方便阅读、修改和扩展。

(三)程序源代码以及运行结果

1.程序源代码

点击查看代码
import pygame
# 导入pygame模块
print(pygame.ver)
# 检查pygame的版本,检查pygame有没有导入成功

EMPTY = 0
BLACK = 1
WHITE = 2
# 定义三个常量函数,用来表示白棋,黑棋,以及 空

black_color = [0, 0, 0]
# 定义黑色(黑棋用,画棋盘)
white_color = [255, 255, 255]
# 定义白色(白棋用)

# 定义棋盘这个类
class RenjuBoard(object):

    def __init__(self):
        # self._board = board = [[EMPTY] * 15 for _ in range(15)]
        # 将棋盘每一个交叉点都看作列表的一个元素位,一共有15*15共225个元素
        self._board = [[]] * 15
        self.reset()
    #重置棋盘
    def reset(self):
        for row in range(len(self._board)):
            self._board[row] = [EMPTY] * 15
    #定义棋盘上的下棋函数,row表示行,col表示列,is_black表示判断当前点位该下黑棋,还是白棋
    def move(self, row, col, is_black):
        if self._board[row][col] == EMPTY:
            self._board[row][col] = BLACK if is_black else WHITE
            return True
        return False
    # 给棋盘定义一个函数将自己在screen上面画出来,使用pygame.draw()函数。并且顺便将下了的棋子也画出来
    def draw(self, screen):
        for h in range(1, 16):
            pygame.draw.line(screen, black_color,
                             [40, h * 40], [600, h * 40], 1)
            pygame.draw.line(screen, black_color,
                             [h * 40,40], [h * 40, 600], 1)
        # 给棋盘加一个外框,使美观
        pygame.draw.rect(screen, black_color, [36, 36, 568, 568], 3)

        # 在棋盘上标出,天元以及另外4个特殊点位
        pygame.draw.circle(screen, black_color, [320, 320], 5, 0)
        pygame.draw.circle(screen, black_color, [160, 160], 3, 0)
        pygame.draw.circle(screen, black_color, [160, 480], 3, 0)
        pygame.draw.circle(screen, black_color, [480, 160], 3, 0)
        pygame.draw.circle(screen, black_color, [480, 480], 3, 0)
        #做2次for循环取得棋盘上所有交叉点的坐标
        for row in range(len(self._board)):
            for col in range(len(self._board[row])):
                # 将下在棋盘上的棋子画出来
                if self._board[row][col] != EMPTY:
                    ccolor = black_color \
                        if self._board[row][col] == BLACK else white_color
                    # 取得这个交叉点下的棋子的颜色,并将棋子画出来
                    pos = [40 * (col + 1), 40 * (row + 1)]
                    # 画出棋子
                    pygame.draw.circle(screen, ccolor, pos, 18, 0)

# 定义函数,传入当前棋盘上的棋子列表,输出结果,不管黑棋白棋胜,都是传回False,未出结果则为True
def is_win(board):
    for n in range(15):
        # 判断垂直方向胜利
        flag = 0
        # flag是一个标签,表示是否有连续以上五个相同颜色的棋子
        for b in board._board:
            if b[n] == 1:
                flag += 1
                if flag == 5:
                    print('黑棋胜')
                    return False
            else:
            # else表示此时没有连续相同的棋子,标签flag重置为0
                flag = 0

        flag = 0
        for b in board._board:
            if b[n] == 2:
                flag += 1
                if flag == 5:
                    print('白棋胜')
                    return False
            else:
                flag = 0

        # 判断水平方向胜利
        flag = 0
        for b in board._board[n]:
            if b == 1:
                flag += 1
                if flag == 5:
                    print('黑棋胜')
                    return False
            else:
                flag = 0

        flag = 0
        for b in board._board[n]:
            if b == 2:
                flag += 1
                if flag == 5:
                    print('白棋胜')
                    return False
            else:
                flag = 0

        # 判断正斜方向胜利

        for x in range(4, 25):
            flag = 0
            for i,b in enumerate(board._board):
                if 14 >= x - i >= 0 and b[x - i] == 1:
                    flag += 1
                    if flag == 5:
                        print('黑棋胜')
                        return False
                else:
                    flag = 0

        for x in range(4, 25):
            flag = 0
            for i,b in enumerate(board._board):
                if 14 >= x - i >= 0 and b[x - i] == 2:
                    flag += 1
                    if flag == 5:
                        print('白棋胜')
                        return False
                else:
                    flag = 0

        #判断反斜方向胜利
        for x in range(11, -11, -1):
            flag = 0
            for i,b in enumerate(board._board):
                if 0 <= x + i <= 14 and b[x + i] == 1:
                    flag += 1
                    if flag == 5:
                        print('黑棋胜')
                        return False
                else:
                    flag = 0

        for x in range(11, -11, -1):
            flag = 0
            for i,b in enumerate(board._board):
                if 0 <= x + i <= 14 and b[x + i] == 2:
                    flag += 1
                    if flag == 5:
                        print('白棋胜')
                        return False
                else:
                    flag = 0

    return True


def main():
    # 创建棋盘对象
    board = RenjuBoard()
    # 用于判断是下黑棋还是白棋
    is_black = True
    # pygame初始化函数,固定写法
    pygame.init()
    pygame.display.set_caption('五子棋-IT入门') # 改标题
    # pygame.display.set_mode()表示建立个窗口,左上角为坐标原点,往右为x正向,往下为y轴正向
    screen = pygame.display.set_mode((640,640))
    # 给窗口填充颜色,颜色用三原色数字列表表示
    screen.fill([125,95,24])
    board.draw(screen)  # 给棋盘类发命令,调用draw()函数将棋盘画出来
    pygame.display.flip()  # 刷新窗口显示

    running = True
    # while 主循环的标签,以便跳出循环
    while running:
        # 遍历建立窗口后发生的所有事件,固定写法
        for event in pygame.event.get():
            # 根据事件的类型,进行判断
            if event.type == pygame.QUIT:
                running = False

            elif event.type == pygame.KEYUP:
                pass
            # pygame.MOUSEBUTTONDOWN表示鼠标的键被按下
            elif event.type == pygame.MOUSEBUTTONDOWN and \
                    event.button == 1:# button表示鼠标左键
                x, y = event.pos  # 拿到鼠标当前在窗口上的位置坐标
                # 将鼠标的(x, y)窗口坐标,转化换为棋盘上的坐标
                row = round((y - 40) / 40)
                col = round((x - 40) / 40)
                if board.move(row, col, is_black):
                    is_black = not is_black
                    screen.fill([125, 95, 24])
                    board.draw(screen)
                    pygame.display.flip()
                    # 调用判断胜负函数
                    if not is_win(board):
                        #break
                        running = False



    pygame.quit()



if __name__ == '__main__':
    main()

2.程序运行结果
视频链接🔗:【五子棋代码运行结果】https://www.bilibili.com/video/BV18GJp6wEZY?vd_source=e37a1907547bdcb930dbf6b12acbaca8

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

  • 问题1:鼠标点击位置与落子位置不一致、棋子无法对准棋盘交叉点
    问题1解决方案:棋盘起始坐标为(40, 40),每个格子边长固定为40像素。同时,使用round()四舍五入修正坐标偏差。再点击不同位置,反复微调坐标,最终实现棋子精准落在棋盘交叉点上。
  • 问题2:同一位置可以重复落子,违反五子棋规则
    问题2解决方案:在move函数内增加判断条件if self._board[row][col] == EMPTY,仅当位置为空时才允许落子,非空位直接返回False,禁止重复落子。
  • 问题3:鼠标点击落子,代码执行正常,但窗口看不到新落下的棋子
    问题3解决方案:每次完成棋盘重绘后,添加pygame.display.flip()语句,强制刷新整个窗口画面,新棋子正常显示。
  • 问题4:无论点击多少次鼠标,棋盘上始终只有黑棋(或白棋),无法实现双人交替对弈。
    问题4解决方案:在落子成功的分支中添加代码is_black = not is_black,对棋手状态取反,完成黑白棋交替,实现双人轮流落子功能。
  • 问题5:棋子绘制后画面残留、出现重影
    问题5解决方案:在每次重绘棋盘前,执行screen.fill([125,95,24])重新填充棋盘底色,清空上一帧画面,再执行棋盘和棋子绘制,彻底解决画面重影问题。

4.2026年Python专选课课程总结与感悟

(一)知识点总结回顾:

1.Python简介:英文本义是蟒蛇,是跨平台语言,不需要预先编译成机器码,而是由解释器逐行解释执行的解释型语言。
2.TIOBE:是一个编程语言流行度排名指数,每月更新一次。
3.开发环境IDE与解释器的关系:解释器:Python代码的“翻译官”,负责将Python代码逐行翻译成计算机能执行的机器指令;IDE是写代码、管理项目的 “工作台”,比如PyCharm、VSCode。
4.Python中最基础的几类数据类型

  • 数字类型:整型(int):整数,如10、-3;浮点型(float):小数,如3.14、-0.5。
  • 字符串类型(str):用单/双/三引号包裹的文本,如"Python"。
  • 布尔类型(bool):只有两个值True(真)和False(假),常用于条件判断。

5.运算符类型

  • 算术运算符:+(加)、-(减)、*(乘)、/(除)。
  • 比较运算符:==(等于)、!=(不等于)、>(大于)、<(小于)。
  • 赋值运算符:=(赋值)、+=、-=、*=、/= 等。
  • 逻辑运算符:and(与)、or(或)、not(非),用于组合条件判断。

6.input()函数相关:用于接收用户从键盘输入的内容,返回的是字符串类型。如果要接收数字,需要用int() 或float() 转换。
7.循环语句简介:while循环:先判断条件,条件为真时执行循环体,条件为假时退出循环;for循环:遍历序列(如列表、字符串),适用于已知循环次数或遍历对象的场景。
8.序列包含及种类:序列是指元素有序排列、可通过索引访问的数据类型,Python中的序列有列表(list)、元组(tuple)、字符串(str)、字节串(bytes)、范围对象(range)等。

(二)课程总结回顾:

没上这门课之前,Python在我心中留下来深奥难懂的刻板印象,但是真正上了这门课程,我发现Python是有趣的,值得探索的一门好课程。
随着课程推进,我逐渐掌握了变量、函数、循环等基础语法,慢慢地我会主动探索了。完成实验内容时,我遇到过诸多难题,一次次的调试和修改代码,让我压力直线飙升,可当代码成功运行,看到预期的结果时,那种成就感又难以言表。老师给予的要求不高,给我们放宽了条件,所以我可以产生更多精力去探索。
编写代码过程中,我认识了代码整体性、美观性、可读性的重要性。我们写代码需要具有整体观念,要提前引入需要用到的工具,提前定义一些函数方便后面使用,考虑可能发生的错误情况,对错误情况进行规避。写完代码要看一看代码整体的美观性,合适的地方需要隔开,方便阅读。这段旅程让我明白,编程不仅是职业技能,更是一种用逻辑梳理混沌、用坚持化解困境的生活态度。我相信未来的生活中我仍然可以使用python便利自己的学习和生活,课程的结束不代表我与python说再见,而是开启了我自己主动探索的路程!

(三)课程建议:

  • 前面的基础知识比较容易理解,但是后面就都比较难了,比如用socket函数编制服务器和客户端的那个实验,当初就不是特别理解,老师以后讲的时候可以稍微放慢一点速度!
  • 还有有时候老师编写代码的速度比较快,感觉有点跟不上,建议老师稍微停留几秒或者提醒大家记一下重点步骤。
  • 对于文科生来说Python的学习难度确实很大,感觉光听课还是不够的,老师可以在课前几天发布预习内容让大家提早学习一下下节课要讲的重点内容,也可以推荐一些相关的资料,这样应该可以帮助同学们在课堂上跟上进度!
    最后,老师讲得特别好,感谢您一个学期以来的教导!

参考资料

posted @ 2026-06-14 15:26  施菲特  阅读(8)  评论(0)    收藏  举报