20234214 实验四 《Python程序设计》实验报告

20234214 2024-2025-2 《Python程序设计》实验四报告

课程:《Python程序设计》
班级: 2342
姓名: 唐果儿
学号:20234214
实验教师:王志强
实验日期:2025年5月13日
必修/选修: 专选课

一、实验内容

(一)实验内容
Python综合应用:爬虫、数据处理、可视化、机器学习、神经网络、游戏、网络安全等。
例如:编写从社交网络爬取数据,实现可视化舆情监控或者情感分析。
例如:利用公开数据集,开展图像分类、恶意软件检测等
例如:利用Python库,基于OCR技术实现自动化提取图片中数据,并填入excel中。
例如:爬取天气数据,实现自动化微信提醒
例如:利用爬虫,实现自动化下载网站视频、文件等。
例如:编写小游戏:坦克大战、贪吃蛇、扫雷等等
注:在Windows/Linux系统上使用VIM、PDB、IDLE、Pycharm等工具编程实现。
(二)实验要求
1.程序能运行,功能丰富。(需求提交源代码,并建议录制程序运行的视频)
2.综合实践报告,要体现实验分析、设计、实现过程、结果等信息,格式规范,逻辑清晰,结构合理。
3.在实践报告中,需要对全课进行总结,并写课程感想体会、意见和建议等。

二、实验过程及结果

(一)实验过程
1.环境配置与准备
本次实践需要完成的是中国象棋小游戏,需要使用Pygame开发库。Pygame是一个基于Python的游戏开发库,它提供了一系列的工具和接口,使开发人员能够轻松地创建各种类型的游戏,包括2D游戏和简单的3D游戏。
Pygame的安装:

此外,还需要准备一些棋子的图片素材

2.整体架构设计
在完成中国象棋小游戏时,需要将游戏拆分为多个模块,各自完成不同的功能,可以提高代码的可维护性和可扩展性。经过综合考虑分析,将代码设计为:主程序、棋子设计、玩家交互设计、“电脑玩家”设计、游戏状态管理五大模块。
python代码文件实现:

  • chinachess.py:作为主程序,负责游戏初始化、主循环、事件处理等核心功能。
点击查看代码
import pygame
import time
import constants
from button import Button
import pieces
import computer
import pickle  # 用于保存和加载游戏

class MainGame():
    window = None
    Start_X = constants.Start_X
    Start_Y = constants.Start_Y
    Line_Span = constants.Line_Span
    Max_X = Start_X + 8 * Line_Span
    Max_Y = Start_Y + 9 * Line_Span

    player1Color = constants.player1Color
    player2Color = constants.player2Color
    Putdownflag = player1Color
    piecesSelected = None

    button_go = None
    button_undo = None  # 悔棋按钮
    button_save = None  # 保存游戏按钮
    button_load = None  # 加载游戏按钮
    piecesList = []
    move_history = []  # 用于悔棋的历史记录

    def start_game(self):
        MainGame.window = pygame.display.set_mode([constants.SCREEN_WIDTH, constants.SCREEN_HEIGHT])
        pygame.display.set_caption("20234214唐果儿版权所有——中国象棋")
        MainGame.button_go = Button(MainGame.window, "重新开始", constants.SCREEN_WIDTH - 100, 300)
        MainGame.button_undo = Button(MainGame.window, "悔棋", constants.SCREEN_WIDTH - 100, 350)
        MainGame.button_save = Button(MainGame.window, "保存游戏", constants.SCREEN_WIDTH - 100, 400)
        MainGame.button_load = Button(MainGame.window, "加载游戏", constants.SCREEN_WIDTH - 100, 450)
        self.piecesInit()

        while True:
            time.sleep(0.1)
            MainGame.window.fill(constants.BG_COLOR)
            self.drawChessboard()
            MainGame.button_go.draw_button()
            MainGame.button_undo.draw_button()
            MainGame.button_save.draw_button()
            MainGame.button_load.draw_button()
            self.piecesDisplay()
            self.VictoryOrDefeat()
            self.Computerplay()
            self.getEvent()
            pygame.display.update()
            pygame.display.flip()

    def drawChessboard(self):
        mid_end_y = MainGame.Start_Y + 4 * MainGame.Line_Span
        min_start_y = MainGame.Start_Y + 5 * MainGame.Line_Span
        for i in range(0, 9):
            x = MainGame.Start_X + i * MainGame.Line_Span
            if i == 0 or i == 8:
                self.draw_line([x, MainGame.Start_Y], [x, MainGame.Max_Y], color=constants.RIVER_LINE_COLOR, width=2)
            else:
                self.draw_line([x, MainGame.Start_Y], [x, mid_end_y], color=constants.MAIN_LINE_COLOR, width=2)
                self.draw_line([x, min_start_y], [x, MainGame.Max_Y], color=constants.MAIN_LINE_COLOR, width=2)

        for i in range(0, 10):
            y = MainGame.Start_Y + i * MainGame.Line_Span
            self.draw_line([MainGame.Start_X, y], [MainGame.Max_X, y], color=constants.MAIN_LINE_COLOR, width=2)

        speed_dial_start_x = MainGame.Start_X + 3 * MainGame.Line_Span
        speed_dial_end_x = MainGame.Start_X + 5 * MainGame.Line_Span
        speed_dial_y1 = MainGame.Start_Y + 0 * MainGame.Line_Span
        speed_dial_y2 = MainGame.Start_Y + 2 * MainGame.Line_Span
        speed_dial_y3 = MainGame.Start_Y + 7 * MainGame.Line_Span
        speed_dial_y4 = MainGame.Start_Y + 9 * MainGame.Line_Span

        self.draw_line([speed_dial_start_x, speed_dial_y1], [speed_dial_end_x, speed_dial_y2])
        self.draw_line([speed_dial_start_x, speed_dial_y2], [speed_dial_end_x, speed_dial_y1])
        self.draw_line([speed_dial_start_x, speed_dial_y3], [speed_dial_end_x, speed_dial_y4])
        self.draw_line([speed_dial_start_x, speed_dial_y4], [speed_dial_end_x, speed_dial_y3])

    def draw_line(self, start, end, color=constants.BLACK, width=1):
        # 添加color和width参数,默认值保持兼容
        pygame.draw.line(MainGame.window, color, start, end, width)

    def piecesInit(self):
        MainGame.piecesList = []
        MainGame.piecesList.append(pieces.Rooks(MainGame.player2Color, 0, 0))
        MainGame.piecesList.append(pieces.Rooks(MainGame.player2Color, 8, 0))
        MainGame.piecesList.append(pieces.Elephants(MainGame.player2Color, 2, 0))
        MainGame.piecesList.append(pieces.Elephants(MainGame.player2Color, 6, 0))
        MainGame.piecesList.append(pieces.King(MainGame.player2Color, 4, 0))
        MainGame.piecesList.append(pieces.Knighs(MainGame.player2Color, 1, 0))
        MainGame.piecesList.append(pieces.Knighs(MainGame.player2Color, 7, 0))
        MainGame.piecesList.append(pieces.Cannons(MainGame.player2Color, 1, 2))
        MainGame.piecesList.append(pieces.Cannons(MainGame.player2Color, 7, 2))
        MainGame.piecesList.append(pieces.Mandarins(MainGame.player2Color, 3, 0))
        MainGame.piecesList.append(pieces.Mandarins(MainGame.player2Color, 5, 0))
        MainGame.piecesList.append(pieces.Pawns(MainGame.player2Color, 0, 3))
        MainGame.piecesList.append(pieces.Pawns(MainGame.player2Color, 2, 3))
        MainGame.piecesList.append(pieces.Pawns(MainGame.player2Color, 4, 3))
        MainGame.piecesList.append(pieces.Pawns(MainGame.player2Color, 6, 3))
        MainGame.piecesList.append(pieces.Pawns(MainGame.player2Color, 8, 3))

        MainGame.piecesList.append(pieces.Rooks(MainGame.player1Color, 0, 9))
        MainGame.piecesList.append(pieces.Rooks(MainGame.player1Color, 8, 9))
        MainGame.piecesList.append(pieces.Elephants(MainGame.player1Color, 2, 9))
        MainGame.piecesList.append(pieces.Elephants(MainGame.player1Color, 6, 9))
        MainGame.piecesList.append(pieces.King(MainGame.player1Color, 4, 9))
        MainGame.piecesList.append(pieces.Knighs(MainGame.player1Color, 1, 9))
        MainGame.piecesList.append(pieces.Knighs(MainGame.player1Color, 7, 9))
        MainGame.piecesList.append(pieces.Cannons(MainGame.player1Color, 1, 7))
        MainGame.piecesList.append(pieces.Cannons(MainGame.player1Color, 7, 7))
        MainGame.piecesList.append(pieces.Mandarins(MainGame.player1Color, 3, 9))
        MainGame.piecesList.append(pieces.Mandarins(MainGame.player1Color, 5, 9))
        MainGame.piecesList.append(pieces.Pawns(MainGame.player1Color, 0, 6))
        MainGame.piecesList.append(pieces.Pawns(MainGame.player1Color, 2, 6))
        MainGame.piecesList.append(pieces.Pawns(MainGame.player1Color, 4, 6))
        MainGame.piecesList.append(pieces.Pawns(MainGame.player1Color, 6, 6))
        MainGame.piecesList.append(pieces.Pawns(MainGame.player1Color, 8, 6))

    def piecesDisplay(self):
        for item in MainGame.piecesList:
            item.displaypieces(MainGame.window)

    def getEvent(self):
        eventList = pygame.event.get()
        for event in eventList:
            if event.type == pygame.QUIT:
                self.endGame()
            elif event.type == pygame.MOUSEBUTTONDOWN:
                pos = pygame.mouse.get_pos()
                mouse_x = pos[0]
                mouse_y = pos[1]
                if (
                        mouse_x > MainGame.Start_X - MainGame.Line_Span / 2 and mouse_x < MainGame.Max_X + MainGame.Line_Span / 2) and (
                        mouse_y > MainGame.Start_Y - MainGame.Line_Span / 2 and mouse_y < MainGame.Max_Y + MainGame.Line_Span / 2):
                    if MainGame.Putdownflag != MainGame.player1Color:
                        return

                    click_x = round((mouse_x - MainGame.Start_X) / MainGame.Line_Span)
                    click_y = round((mouse_y - MainGame.Start_Y) / MainGame.Line_Span)
                    click_mod_x = (mouse_x - MainGame.Start_X) % MainGame.Line_Span
                    click_mod_y = (mouse_y - MainGame.Start_Y) % MainGame.Line_Span
                    if abs(click_mod_x - MainGame.Line_Span / 2) >= 5 and abs(
                            click_mod_y - MainGame.Line_Span / 2) >= 5:
                        self.PutdownPieces(MainGame.player1Color, click_x, click_y)
                if MainGame.button_go.is_click():
                    self.piecesInit()
                    MainGame.Putdownflag = MainGame.player1Color
                    self.move_history = []
                elif MainGame.button_undo.is_click():
                    self.undo_move()
                elif MainGame.button_save.is_click():
                    self.save_game()
                elif MainGame.button_load.is_click():
                    self.load_game()

    def PutdownPieces(self, t, x, y):
        selectfilter = list(filter(lambda cm: cm.x == x and cm.y == y and cm.player == MainGame.player1Color,
                                   MainGame.piecesList))
        if len(selectfilter):
            MainGame.piecesSelected = selectfilter[0]
            return

        if MainGame.piecesSelected:
            arr = pieces.listPiecestoArr(MainGame.piecesList)
            if MainGame.piecesSelected.canmove(arr, x, y):
                removed_piece = self.PiecesMove(MainGame.piecesSelected, x, y)
                self.move_history.append((MainGame.piecesSelected, MainGame.piecesSelected.x, MainGame.piecesSelected.y, x, y, removed_piece))
                MainGame.Putdownflag = MainGame.player2Color
        else:
            fi = filter(lambda p: p.x == x and p.y == y, MainGame.piecesList)
            listfi = list(fi)
            if len(listfi) != 0:
                MainGame.piecesSelected = listfi[0]

    def PiecesMove(self, pieces, x, y):
        removed_piece = None
        for item in MainGame.piecesList:
            if item.x == x and item.y == y:
                MainGame.piecesList.remove(item)
                removed_piece = item
                break
        pieces.x = x
        pieces.y = y
        print("move to " + str(x) + " " + str(y))
        return removed_piece

    def Computerplay(self):
        if MainGame.Putdownflag == MainGame.player2Color:
            print("轮到电脑了")
            computermove = computer.getPlayInfo(MainGame.piecesList)
            piecemove = None
            for item in MainGame.piecesList:
                if item.x == computermove[0] and item.y == computermove[1]:
                    piecemove = item
            removed_piece = self.PiecesMove(piecemove, computermove[2], computermove[3])
            self.move_history.append((piecemove, piecemove.x, piecemove.y, computermove[2], computermove[3], removed_piece))
            MainGame.Putdownflag = MainGame.player1Color

    def VictoryOrDefeat(self):
        txt = ""
        result = [MainGame.player1Color, MainGame.player2Color]
        for item in MainGame.piecesList:
            if type(item) == pieces.King:
                if item.player == MainGame.player1Color:
                    result.remove(MainGame.player1Color)
                if item.player == MainGame.player2Color:
                    result.remove(MainGame.player2Color)

        if len(result) == 0:
            return
        if result[0] == MainGame.player1Color:
            txt = "失败!"
        else:
            txt = "胜利!"
        MainGame.window.blit(self.getTextSuface("%s" % txt), (constants.SCREEN_WIDTH - 100, 200))
        MainGame.Putdownflag = constants.overColor

    def getTextSuface(self, text):
        pygame.font.init()
        font = pygame.font.SysFont('kaiti', 18)
        txt = font.render(text, True, constants.TEXT_COLOR)
        return txt

    def endGame(self):
        print("exit")
        exit()

    def undo_move(self):
        try:
            if self.move_history:
                piece, old_x, old_y, new_x, new_y, removed_piece = self.move_history.pop()
                piece.x = old_x
                piece.y = old_y
                if removed_piece:
                    MainGame.piecesList.append(removed_piece)
                if MainGame.Putdownflag == MainGame.player1Color:
                    MainGame.Putdownflag = MainGame.player2Color
                else:
                    MainGame.Putdownflag = MainGame.player1Color
        except Exception as e:
            print(f"悔棋操作出现异常: {e}")

    def baocun(self):
        data = {
            'piecesList': MainGame.piecesList,
            'Putdownflag': MainGame.Putdownflag,
            'move_history': self.move_history
        }
        with open('game_save.pkl', 'wb') as f:
            pickle.dump(data, f)
        print("游戏已保存")

    def jiazai(self):
        try:
            with open('game_save.pkl', 'rb') as f:
                data = pickle.load(f)
            MainGame.piecesList = data['piecesList']
            MainGame.Putdownflag = data['Putdownflag']
            self.move_history = data['move_history']
            print("游戏已加载")
        except FileNotFoundError:
            print("未找到保存的游戏文件")

if __name__ == '__main__':
    MainGame().start_game()
  • pieces.py:定义各种棋子的类别、移动规则、图像显示等。
点击查看代码
import pygame
import constants

class  Pieces():
    def __init__(self, player,  x, y):
        self.imagskey = self.getImagekey()
        self.image = constants.pieces_images[self.imagskey]
        self.x = x
        self.y = y
        self.player = player
        self.rect = self.image.get_rect()
        self.rect.left = constants.Start_X + x * constants.Line_Span - self.image.get_rect().width / 2
        self.rect.top = constants.Start_Y + y * constants.Line_Span - self.image.get_rect().height / 2

    def displaypieces(self,screen):
        #print(str(self.rect.left))
        self.rect.left = constants.Start_X + self.x * constants.Line_Span - self.image.get_rect().width / 2
        self.rect.top = constants.Start_Y + self.y * constants.Line_Span - self.image.get_rect().height / 2
        screen.blit(self.image,self.rect);
        #self.image = self.images
        #MainGame.window.blit(self.image,self.rect)

    def canmove(self, arr, moveto_x, moveto_y):
        pass
    def getImagekey(self):
        return None
    def getScoreWeight(self,listpieces):
        return  None

class Rooks(Pieces):
    def __init__(self, player,  x, y):
        self.player = player
        super().__init__(player,  x, y)

    def getImagekey(self):
        if self.player == constants.player1Color:
            return "r_rook"
        else:
            return "b_rook"

    def canmove(self, arr, moveto_x, moveto_y):
        if self.x == moveto_x and self.y == moveto_y:
            return False
        if arr[moveto_x][moveto_y] ==self.player :
            return  False
        if self.x == moveto_x:
            step = -1 if self.y > moveto_y else 1
            for i in range(self.y +step, moveto_y, step):
                if arr[self.x][i] !=0 :
                    return False
            #print(" move y")
            return True

        if self.y == moveto_y:
            step = -1 if self.x > moveto_x else 1
            for i in range(self.x + step, moveto_x, step):
                if arr[i][self.y] != 0:
                    return False
            return True

    def getScoreWeight(self, listpieces):
        score = 11
        return score

class Knighs(Pieces):
    def __init__(self, player,  x, y):
        self.player = player
        super().__init__(player,  x, y)
    def getImagekey(self):
        if self.player == constants.player1Color:
            return "r_knigh"
        else:
            return "b_knigh"
    def canmove(self, arr, moveto_x, moveto_y):
        if self.x == moveto_x and self.y == moveto_y:
            return False
        if arr[moveto_x][moveto_y] == self.player:
            return False
        #print(str(self.x) +""+str(self.y))
        move_x = moveto_x-self.x
        move_y = moveto_y - self.y
        if abs(move_x) == 1 and abs(move_y) == 2:
            step = 1 if move_y > 0 else -1
            if arr[self.x][self.y + step] == 0:
                return True
        if abs(move_x) == 2 and abs(move_y) == 1:
            step = 1 if move_x >0 else -1
            if arr[self.x +step][self.y] ==0 :
                return  True

    def getScoreWeight(self, listpieces):
        score = 5
        return score

class Elephants(Pieces):
    def __init__(self, player, x, y):
        self.player = player
        super().__init__(player, x, y)
    def getImagekey(self):
        if self.player == constants.player1Color:
            return "r_elephant"
        else:
            return "b_elephant"
    def canmove(self, arr, moveto_x, moveto_y):
        if self.x == moveto_x and self.y == moveto_y:
            return False
        if arr[moveto_x][moveto_y] == self.player:
            return False
        if self.y <=4 and moveto_y >=5 or self.y >=5 and moveto_y <=4:
            return  False
        move_x = moveto_x - self.x
        move_y = moveto_y - self.y
        if abs(move_x) == 2 and abs(move_y) == 2:
            step_x = 1 if move_x > 0 else -1
            step_y = 1 if move_y > 0 else -1
            if arr[self.x + step_x][self.y + step_y] == 0:
                return True

    def getScoreWeight(self, listpieces):
        score = 2
        return score
class Mandarins(Pieces):

    def __init__(self, player,  x, y):
        self.player = player
        super().__init__(player,  x, y)

    def getImagekey(self):
        if self.player == constants.player1Color:
            return "r_mandarin"
        else:
            return "b_mandarin"
    def canmove(self, arr, moveto_x, moveto_y):
        if self.x == moveto_x and self.y == moveto_y:
            return False
        if arr[moveto_x][moveto_y] == self.player:
            return False
        if moveto_x <3 or moveto_x >5:
            return False
        if moveto_y > 2 and moveto_y < 7:
            return False
        move_x = moveto_x - self.x
        move_y = moveto_y - self.y
        if abs(move_x) == 1 and abs(move_y) == 1:
            return True
    def getScoreWeight(self, listpieces):
        score = 2
        return score

class King(Pieces):
    def __init__(self, player, x, y):
        self.player = player
        super().__init__(player, x, y)
    def getImagekey(self):
        if self.player == constants.player1Color:
            return "r_king"
        else:
            return "b_king"

    def canmove(self, arr, moveto_x, moveto_y):
        if self.x == moveto_x and self.y == moveto_y:
            return False
        if arr[moveto_x][moveto_y] == self.player:
            return False
        if moveto_x < 3 or moveto_x > 5:
            return False
        if moveto_y > 2 and moveto_y < 7:
            return False
        move_x = moveto_x - self.x
        move_y = moveto_y - self.y
        if abs(move_x) + abs(move_y) == 1:
            return True
    def getScoreWeight(self, listpieces):
        score = 150
        return score
class Cannons(Pieces):
    def __init__(self, player,  x, y):
        self.player = player
        super().__init__(player, x, y)
    def getImagekey(self):
        if self.player == constants.player1Color:
            return "r_cannon"
        else:
            return "b_cannon"

    def canmove(self, arr, moveto_x, moveto_y):
        if self.x == moveto_x and self.y == moveto_y:
            return False
        if arr[moveto_x][moveto_y] == self.player:
            return False
        overflag = False
        if self.x == moveto_x:
            step = -1 if self.y > moveto_y else 1
            for i in range(self.y + step, moveto_y, step):
                if arr[self.x][i] != 0:
                    if overflag:
                        return False
                    else:
                        overflag = True

            if overflag and arr[moveto_x][moveto_y] == 0:
                return False
            if not overflag and arr[self.x][moveto_y] != 0:
                return False

            return True

        if self.y == moveto_y:
            step = -1 if self.x > moveto_x else 1
            for i in range(self.x + step, moveto_x, step):
                if arr[i][self.y] != 0:
                    if overflag:
                        return False
                    else:
                        overflag = True

            if overflag and arr[moveto_x][moveto_y] == 0:
                return False
            if not overflag and arr[moveto_x][self.y] != 0:
                return False
            return True
    def getScoreWeight(self, listpieces):
        score = 6
        return score

class Pawns(Pieces):
    def __init__(self, player, x, y):
        self.player = player
        super().__init__(player,  x, y)
    def getImagekey(self):
        if self.player == constants.player1Color:
            return "r_pawn"
        else:
            return "b_pawn"

    def canmove(self, arr, moveto_x, moveto_y):
        if self.x == moveto_x and self.y == moveto_y:
            return False
        if arr[moveto_x][moveto_y] == self.player:
            return False
        move_x = moveto_x - self.x
        move_y = moveto_y - self.y

        if self.player == constants.player1Color:
            if self.y > 4  and move_x != 0 :
                return  False
            if move_y > 0:
                return  False
        elif self.player == constants.player2Color:
            if self.y <= 4  and move_x != 0 :
                return  False
            if move_y < 0:
                return False

        if abs(move_x) + abs(move_y) == 1:
            return True
    def getScoreWeight(self, listpieces):
        score = 2
        return score

def listPiecestoArr(piecesList):
    arr = [[0 for i in range(10)] for j in range(9)]
    for i in range(0, 9):
        for j in range(0, 10):
            if len(list(filter(lambda cm: cm.x == i and cm.y == j and cm.player == constants.player1Color,
                               piecesList))):
                arr[i][j] = constants.player1Color
            elif len(list(filter(lambda cm: cm.x == i and cm.y == j and cm.player == constants.player2Color,
                                 piecesList))):
                arr[i][j] = constants.player2Color

    return arr
  • button.py:实现按钮的设计,用于创建游戏中的各种按钮,如重新开始、悔棋、保存和加载游戏等。
点击查看代码
import pygame
class Button():
    def __init__(self, screen, msg, left,top):  # msg为要在按钮中显示的文本
        """初始化按钮的属性"""
        self.screen = screen
        self.screen_rect = screen.get_rect()

        self.width, self.height = 150, 50  # 这种赋值方式很不错
        self.button_color = (72, 61, 139)  # 设置按钮的rect对象颜色为深蓝
        self.text_color = (255, 255, 255)  # 设置文本的颜色为白色
        pygame.font.init()
        self.font = pygame.font.SysFont('kaiti', 20)  # 设置文本为默认字体,字号为40

        self.rect = pygame.Rect(0, 0, self.width, self.height)
        #self.rect.center = self.screen_rect.center  # 创建按钮的rect对象,并使其居中
        self.left = left
        self.top = top

        self.deal_msg(msg)  # 渲染图像

    def deal_msg(self, msg):
        """将msg渲染为图像,并将其在按钮上居中"""
        self.msg_img = self.font.render(msg, True, self.text_color, self.button_color)  # render将存储在msg的文本转换为图像
        self.msg_img_rect = self.msg_img.get_rect()  # 根据文本图像创建一个rect
        self.msg_img_rect.center = self.rect.center  # 将该rect的center属性设置为按钮的center属性

    def draw_button(self):
        #self.screen.fill(self.button_color, self.rect)  # 填充颜色
        self.screen.blit(self.msg_img, (self.left,self.top))  # 将该图像绘制到屏幕

    def is_click(self):
        point_x, point_y = pygame.mouse.get_pos()
        x = self.left
        y = self.top
        w, h = self.msg_img.get_size()

        in_x = x < point_x < x + w
        in_y = y < point_y < y + h
        return in_x and in_y
  • computer.py:实现电脑玩家的逻辑设计,根据当前棋局计算出最佳的落子位置。
点击查看代码
import constants
#import time
from pieces import listPiecestoArr

def getPlayInfo(listpieces):
    pieces = movedeep(listpieces ,1 ,constants.player2Color)
    return [pieces[0].x,pieces[0].y, pieces[1], pieces[2]]

def movedeep(listpieces, deepstep, player):
    arr = listPiecestoArr(listpieces)
    listMoveEnabel = []
    for i in range(0, 9):
        for j in range(0, 10):
            for item in listpieces:
                if item.player == player and item.canmove(arr, i, j):
                    #标记是否有子被吃 如果被吃 在下次循环时需要补会
                    piecesremove = None
                    for itembefore in listpieces:
                        if itembefore.x == i and itembefore.y == j:
                            piecesremove= itembefore
                            break
                    if piecesremove != None:
                        listpieces.remove(piecesremove)

                    #记录移动之前的位置
                    move_x = item.x
                    move_y = item.y
                    item.x = i
                    item.y = j

                    #print(str(move_x) + "," + str(move_y) + "," + str(item.x) + "  ,  " + str(item.y))
                    scoreplayer1 = 0
                    scoreplayer2 = 0
                    for itemafter in listpieces:
                        if itemafter.player == constants.player1Color:
                            scoreplayer1 += itemafter.getScoreWeight(listpieces)
                        elif  itemafter.player == constants.player2Color:
                            scoreplayer2 += itemafter.getScoreWeight(listpieces)

                    #print("得分:"+item.imagskey +", "+str(len(moveAfterListpieces))+","+str(i)+","+str(j)+"," +str(scoreplayer1) +"  ,  "+ str(scoreplayer2) )
                    #print(str(deepstep))
                    #如果得子 判断对面是否可以杀过来,如果又被杀,而且子力评分低,则不干
                    arrkill = listPiecestoArr(listpieces)

                    if scoreplayer2 > scoreplayer1 :
                        for itemkill in listpieces:
                            if itemkill.player == constants.player1Color and itemkill.canmove(arrkill, i, j):
                                scoreplayer2=scoreplayer1

                    if deepstep > 0 :
                        nextplayer = constants.player1Color if player == constants.player2Color else constants.player2Color
                        nextpiecesbest= movedeep(listpieces, deepstep -1, nextplayer)
                        listMoveEnabel.append([item, i, j, nextpiecesbest[3], nextpiecesbest[4], nextpiecesbest[5]])
                    else:
                        #print(str(len(listpieces)))
                        #print("得分:" + item.imagskey + ", " + str(len(listpieces)) + "," + str(move_x) + "," + str(move_y) + "," + str(i) + "  ,  " + str(j))
                        if player == constants.player2Color:
                            listMoveEnabel.append([item, i, j, scoreplayer1, scoreplayer2, scoreplayer1 - scoreplayer2])
                        else:
                            listMoveEnabel.append([item, i, j, scoreplayer1, scoreplayer2, scoreplayer2 - scoreplayer1])
                    #print("得分:"+str(scoreplayer1))
                    item.x = move_x
                    item.y = move_y
                    if piecesremove != None:
                        listpieces.append(piecesremove)

    list_scorepalyer1 = sorted(listMoveEnabel, key=lambda tm: tm[5], reverse=True)
    piecesbest = list_scorepalyer1[0]
    if deepstep ==1 :
        print(list_scorepalyer1)
    return piecesbest
  • constants.py:定义游戏中使用的各种常量,如屏幕尺寸、颜色、棋子图像等。
点击查看代码
import pygame

SCREEN_WIDTH=900
SCREEN_HEIGHT=650
Start_X = 50
Start_Y = 50
Line_Span = 60

player1Color = 1
player2Color = 2
overColor = 3

BG_COLOR=pygame.Color(200, 200, 200)
Line_COLOR=pygame.Color(255, 255, 200)
TEXT_COLOR=pygame.Color(255, 0, 0)

# 定义颜色
BLACK = ( 0, 0, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
GREEN = ( 0, 255, 0)
BLUE = ( 0, 0, 255)

MAIN_LINE_COLOR = (51, 34, 17)   # 深棕色(替代原黑色线条)
RIVER_LINE_COLOR = (204, 102, 0) # 橙色(河界专用)

repeat = 0

pieces_images = {
    'b_rook': pygame.image.load("imgs/s2/b_c.gif"),
    'b_elephant': pygame.image.load("imgs/s2/b_x.gif"),
    'b_king': pygame.image.load("imgs/s2/b_j.gif"),
    'b_knigh': pygame.image.load("imgs/s2/b_m.gif"),
    'b_mandarin': pygame.image.load("imgs/s2/b_s.gif"),
    'b_cannon': pygame.image.load("imgs/s2/b_p.gif"),
    'b_pawn': pygame.image.load("imgs/s2/b_z.gif"),

    'r_rook': pygame.image.load("imgs/s2/r_c.gif"),
    'r_elephant': pygame.image.load("imgs/s2/r_x.gif"),
    'r_king': pygame.image.load("imgs/s2/r_j.gif"),
    'r_knigh': pygame.image.load("imgs/s2/r_m.gif"),
    'r_mandarin': pygame.image.load("imgs/s2/r_s.gif"),
    'r_cannon': pygame.image.load("imgs/s2/r_p.gif"),
    'r_pawn': pygame.image.load("imgs/s2/r_z.gif"),
}

中国象棋小游戏程序设计流程图

3.游戏初始化
设置游戏窗口、棋子图像、初始化棋子位置

  • 定义游戏基本常量:屏幕宽度、高度、起始坐标、线条间距等

  • 在chinachess.py的MainGame类的start_game方法中进行游戏初始化操作:

  • 使用piecesInit初始化棋子的位置:
    先放置黑方(piayer2),摆放于棋盘上方0~4 行。接着放置红方(player1),和黑方对称分布在棋盘下方5~9 行。
    循环调用各棋子构造函数、传入颜色和坐标参数,使得所有棋子可以添加到游戏内的棋子列表,完成棋局初始化。
    代码如下:

4.绘制象棋棋盘(横线、竖线、九宫格)
绘制竖线,外侧两条竖线贯穿整个棋盘,中间七条竖线被河界分隔为上下两段。通过定义mid_end_y和min_start_y定义河道上下边沿
绘制横线,共十条横线贯穿整个棋盘宽度。
绘制九宫格斜线,包括左上角、右上角、左下角和右下角的四条斜线。

5.棋子管理设计

  • 定义棋子的不同种类(如Rooks车、Knights马、Elephants象等)

  • 规定棋子移动规则和功能。比如“车”的移动规则定义如下

6.玩家交互
需要处理好用户的鼠标点击操作——选子、落子。为了保证实际使用的合理,还需要判定玩家操作的合规性,如果不合规,则不予以响应。

  • 鼠标点击的操作规则:

  • 玩家落子的操作规则:

7.电脑玩家的运行逻辑
借鉴CSDN案例,基于极小化极大(Minimax)算法完善修改了本次实践作业的电脑玩家运行逻辑,基本框架如下:
模拟移动棋子并计算双方得分(通过getScoreWeight评估子力价值)
若得子,检查是否会被对方反杀(通过canmove判断)
递归评估对手的最优响应(深度减 1)


8.游戏状态管理设计

  • 判定游戏结束功能代码块

  • 悔棋功能代码块

  • 保存游戏和加载游戏代码块

(二)实验结果

三、实验过程中遇到的问题和解决过程

  • 问题1:pygame软件库在下载过程中反复报错,导致失败

  • 问题1解决方案:
    首先我去CSDN和B站中检索了相关问题,大致解决方案有两种,一种是检查是否安装pip并更新后进行安装,但当我在pycharm中检查解释器时,发现pip的更新和pygame下载一样,都会报错;所以我尝试了另一种解决办法,找到python的下载路径,在scripts文件夹中安装软件库并在计算机环境中进行更新,但此方法我在寻找路径时发现多个文件夹,无法准确解决问题。
    最后,我发现问题在于:pycharm中的代码是虚拟环境中运行的,系统python中安装了pygame。所以我通过更改pycharm的虚拟环境相关设置,即把pycharm项目的解释器换成系统python,就解决了所有的问题。

  • 问题2:游戏规则的完善制定,如悔棋等

  • 问题2解决方案:
    在初步完成大致游戏框架后,我就开始着手完善小游戏的规则,很多模块如悔棋、文件保存都是在最基础的游戏框架上完成的,但是这个完善的过程需要考虑很多方面,有的时候是牵一发而动全身的,所以经常会出现报错的情况,尤其是电脑玩家的一些逻辑框架是我在基于CSDN博主所提供的一些运行逻辑所做的,部分内容我从未涉及到,所以这时候我一般都会借助大模型工具完成代码的解释,一点一点理解完整代码的运行框架,最终完成实践任务。

其他(感悟、思考等)

这次节课作业和以往的实验有所不同,在以前,我总是听完老师上课的讲解后按部就班的开展实验,无论是实验的目的还是问题的解决,这些都是由于课程作业——“实验”本身的要求,我所做的就是被动接受和解决实验中出现的问题,这一过程对于我们这些初学者来说无疑是最好的学习与进步方式,但我总觉得在实验中,我们缺少了一些主体性与主动学习解决问题的动力。但在最后的这一次实验中,我们被要求自主选题,每个人都可以用自己一学期学习的内容完成一个从“想法”到“成果”的,属于自己的作品,因此,无论完成过程中遇到何种困难,我都有一种完全不同的动力,去面对自己选择道路中的阻碍。在选题时,我想要运用我们已经学到的知识制作一个和以往作品完全不同的游戏成果,这让我想起了前几天刚刚和同学在微信小程序中下象棋的事情,当时我就在心里想,能够自己做一个可以自己和自己下棋的游戏是不是也不错?这是这个游戏产生的最初灵感。
但在实现的过程中可以说是困难重重,首先的下载pygame就难住了我,让我产生了退却的情绪。但我想,就算在这时候放弃,选择其他方向也会遇到不同的困难,退缩一次无法彻底解决问题。因此我在csdn上搜索这一问题,发现许多人也遇到这样的问题,按照教程很快找到了解决方法。第一步走好了后面就畅通起来,每当遇到问题时,我通过寻求技术人员的经验帖、询问大模型、请教同学等各种各样的方式解决一个个问题,最终顺利完成了实验。
这是python课程一学期以来最后一个课程任务,因为其具有的综合性让我复习运用了先前学到的许多知识,加深了印象。python在我的眼里从不愿开始的艰难任务到现在,因为一个个的小知识点的掌握,变为了在实践中有时能够灵光一现的理解与运用的新技能,感谢一学期的python课程,让身为文科生的我接触到本在大学四年都不会接触到的神奇代码。

课程总结、感想体会及意见建议

之于收获,从Python简介(面向对象、面向过程、开发环境、印象最深刻的一句话:人生苦短,我用Python!) 到Python语法(数据类型、if else、while、for 还有序列、字典、列表、元组、切片),再到文件(rwab+)、网络编程Socket……从所学知识上来看是丰富的,虽然还不能做到对每个知识板块了如指掌,但当提到这方面知识时,我并不是空白的;猜拳游戏、数字运算游戏、双向对话游戏以及此次的中国象棋游戏,设计的是游戏,收获的是python知识。通过这门课程的学习,我深刻感受到了python的魅力与实用性,即使我所了解到的只是冰山一角。 python对于小白来说,基础语法是简洁易懂的,在王老师的教导下,让我们这些初学者上手快,轻松实现基础应用。在学习的过程中,我不仅提高了自己的编程能力,还培养了逻辑思维和解决问题的能力。此外还学到了上述提及的编程知识,如何编写清晰易懂的代码、如何避免常见的错误、如何进行有效的调试以及如何与王老师有效的沟通等。这些知识和技能对于我的职业发展具有重要的意义,无论是实践成果,还是实践精神。目前我所掌握的只是python知识的皮毛,但我认为这是一个起点。未来如果有机会或者工作需要的话,我会深入学习的,关注python社区的发展动态和新技术成果,就是在实验中,我几乎每次都会想社区进行求教,并且在社区和老师的帮助下,解决了一个个对我来说的难题,所以CSDN社区对我来说,就像是知识问答的平台,助你学习,助你进步。
关于建议,对于我们这些既缺少理科思维又缺乏编程基础的文科生,python课程无疑是艰难的,因此我认为您在课程中的讲解已经十分细致易懂,只要在课程上认真听您讲课的学生,我相信在完成任何作业、回答任何问题时都是没有困难的。因此,我认为现在的课程模式与您的教学方式都已经无需大改,但我发现每次上课中认真听课的学生十分稀少,令我印象深刻的是某次课上,您提问关于类和对象的问题时,连续十几名同学站起来说自己不会,我自认为已经是十分愚笨、没有天赋的学生,对于那个问题心中都已经有了答案,因此,我认为课上听讲的情况实为令人担忧,在日后的课程中是否能够增加一些随堂考核或计入成绩的提问答题(给大家一些紧迫感?)让大家不会可惜的错过您精彩的课程。
最后十分感谢您对于我们十分耐心的指导,在去年周围同学们选了您的课程时就已经听说您的风趣幽默与善解人意,在这一学期开始前就期待您的课程已久,在将来的学习中也会谨遵您的教诲:在dky的大环境中,努力学习、不断沉淀积累,时刻保持学习好习惯,不仅限于专业的学习!

参考资料

https://blog.csdn.net/weixin_43778179/article/details/109401899
https://zhuanlan.zhihu.com/p/141540899
https://blog.csdn.net/weixin_44313115/article/details/109008587
https://blog.csdn.net/qq_23126581/article/details/144297234
https://blog.csdn.net/cxh666888_/article/details/143364711
https://blog.csdn.net/weixin_49602952/article/details/138500202

posted @ 2025-07-02 08:51  20234214唐果儿  阅读(9)  评论(0)    收藏  举报