基于Python的中国象棋小游戏的设计与实现

基于Python的中国象棋小游戏的设计与实现

  • [第一章 绪论](#第一章 绪论)
    • [1.1 研究背景](#1.1 研究背景)
    • [1.2 研究意义](#1.2 研究意义)
  • [第二章 需求分析](#第二章 需求分析)
    • [2.1 需求分析](#2.1 需求分析)
      • 2.1.1核心功能需求
      • [2.1.2 用户体验需求](#2.1.2 用户体验需求)
      • [2.1.3 衍生功能需求](#2.1.3 衍生功能需求)
    • [2.2 可行性分析](#2.2 可行性分析)
      • [2.2.1 技术可行性](#2.2.1 技术可行性)
      • [2.2.2 经济可行性](#2.2.2 经济可行性)
      • [2.2.3 市场可行性](#2.2.3 市场可行性)
      • [2.2.4 法律与合规性](#2.2.4 法律与合规性)
  • [第三章 概要设计](#第三章 概要设计)
  • [第四章 详细设计](#第四章 详细设计)
    • [4.1 相关技术介绍](#4.1 相关技术介绍)
      • [4.1.1 Windows 10操作系统](#4.1.1 Windows 10操作系统)
      • [4.1.2 PyCharm](#4.1.2 PyCharm)
      • [4.1.3 Python 3.9](#4.1.3 Python 3.9)
    • [4.2 软件安装](#4.2 软件安装)
      • [4.2.1 PyCharm的安装(网上教程很多可自行下载安装)](#4.2.1 PyCharm的安装(网上教程很多可自行下载安装))
      • [4.2.2 Python 3.9的安装(网上教程很多可自行下载安装)](#4.2.2 Python 3.9的安装(网上教程很多可自行下载安装))
      • [4.2.3 PyCharm中选择Python 3.9解释器](#4.2.3 PyCharm中选择Python 3.9解释器)
      • [4.2.4 安装Pygame库](#4.2.4 安装Pygame库)
    • [4.3 主要功能实现](#4.3 主要功能实现)
    • [4.4 功能展示](#4.4 功能展示)
  • [第五章 测试](#第五章 测试)
  • [第六章 总结与展望](#第六章 总结与展望)
    • [6.1 总结](#6.1 总结)
    • [6.2 展示](#6.2 展示)
  • 参考文献
  • 致谢
  • 完整源程序代码

第一章 绪论

中国象棋拥有2000多年历史,是中华民族智慧和文化的象征,被列入国家级非物质文化遗产名录。但在数字化时代,传统棋类活动面临参与度下降的挑战。现代年轻人更倾向于电子游戏、短视频等快节奏娱乐,亟需通过数字化手段吸引新一代接触传统文化。国际象棋(Chess)的全球化成功案例表明,数字化是文化输出的重要途径,中国象棋也需要通过技术手段走向世界。

1.1 研究背景

在全球化与数字技术深度融合的当代,中国象棋作为传承两千余年的文化瑰宝,正面临双重挑战:一方面,年轻群体对传统文化的认知断层加速,实体棋类活动参与率持续走低;另一方面,国际文化竞争中,象棋的海外认知度远低于国际象棋。与此同时,人工智能技术的突破性发展(如AlphaGo)为棋类游戏数字化提供了全新路径,5G网络普及与跨平台开发框架成熟则为文化产品的创新传播奠定技术基础。在此背景下,开发中国象棋小游戏成为连接传统智慧与现代科技的关键节点,既是对非遗数字化保护的政策响应,亦是通过技术赋能实现文化破圈的实践探索。

1.2 研究意义

本项目的核心价值体现在文化、教育、技术三重维度:其一,通过游戏化载体活化传统文化,将象棋的战术哲学与历史典故融入互动体验,构建"寓文于乐"的传播模式,助力中华文化国际影响力提升;其二,开发智能教学系统与残局训练模块,为青少年思维训练提供可量化、个性化的数字工具,推动传统教育模式创新;其三,在技术层面整合强化学习算法与实时网络对战功能,既验证复杂博弈场景下的AI决策模型优化方案,又探索低延迟同步技术在回合制游戏中的实践路径,为传统文化产品的数字化转型提供技术范本。此外,项目通过适老化设计和多语言适配,促进数字包容与社会公平,其社会效益超越单纯的娱乐范畴,形成文化传承、科技创新与社会服务的多维价值网络。(河北象棋女队队长张婷婷在比赛中。河北省体育局棋牌运动中心供图

第二章 需求分析

2.1 需求分析

2.1.1核心功能需求

核心功能应该主要包括以下三个方面:首先,基础规则实现包括棋子移动逻辑(如马走日、象田字)、胜负判定(将死、困毙、将帅照面)、行棋禁手(长将、长捉)。其次,交互功能包含支持鼠标/触控操作、棋子移动动画、音效反馈(吃子、将军提示)。最后,模式扩展:单人模式(人机对战,含难度分级)、双人本地/在线对战、残局挑战、棋谱复盘。

2.1.2 用户体验需求

首先,界面设计要求传统棋盘视觉(木质纹理、篆体棋子)、自适应布局(PC/移动端)、新手引导动画。其次,性能要求要求低延迟响应(AI计算时间<1秒)、网络对战同步误差<50ms。

2.1.3 衍生功能需求

除了上述核心功能以外,还尝试实现AI教学功能,如实时棋局评分、推荐走法提示、历史错误分析报告。社交功能,如排行榜、对局回放分享、跨平台账号互通(微信/Steam)。

2.2 可行性分析

2.2.1 技术可行性

该项目能否实现主要考虑以下关键技术能否实现:

第一,开发工具成熟,Python(Pygame/Arcade)+ 开源引擎(Godot)可快速构建原型;网络对战可使用Socket.io或WebRTC实现低延迟通信。

第二,AI算法开源化,基于Stockfish(国际象棋引擎)改造的ElephantEye等开源项目提供算法参考,蒙特卡洛树搜索(MCTS)结合残局库可满足业余级AI需求。

第三,跨平台部署,通过PyInstaller(桌面端)、React Native(移动端)实现"一次开发,多端运行",降低维护成本。

2.2.2 经济可行性

利用免费素材(OpenGameArt的棋盘资源)、开源字体(思源宋体),美术成本可压缩至$500以内;开发周期约3-4个月(1名全栈工程师+兼职美术)。

基础功能免费(广告植入)+ 高级功能订阅(AI教练、无广告模式),参考《天天象棋》商业化路径,用户付费转化率预估3%-5%。

2.2.3 市场可行性

国内1.2亿象棋爱好者(中国棋院数据)+ 海外华人社群(约5000万),差异化定位"轻量化教学工具"。

内置《橘中秘》《梅花谱》等古籍残局数据库,形成内容护城河;与棋院合作认证线上段位系统,增强权威性。

2.2.4 法律与合规性

版权规避:传统象棋规则属公共知识,原创美术/音效素材确保无侵权风险。

数据安全:用户对局数据加密存储(AES-256),符合GDPR及《个人信息保护法》要求。

第三章 概要设计

本程序相对来说较为简单,实现的是单用户单机中国象棋小游戏的功能。该项目程序仅仅有简单的中国象棋的相关规则算法实现,并且未实现用户的等登入、个人相关资料、游戏缓存、互动联机模式以及其他复杂功能,因此项目并未设计相应的数据库。该小游戏为开发雏形阶段,开发者人员点击运行后,用户可以在相关界面上简单测试游戏。以下为中国象棋游戏简单的相关功能介绍。

3.1 关键功能分析

3.1.1 图形界面

使用pygame绘制棋盘和棋子,支持鼠标交互。

棋子用不同颜色区分红黑双方,文字标识类型(如"車""馬")。

3.1.2移动规则

每个棋子类(如Knight)继承自Piece,重写is_valid_move方法实现特定规则。

实现蹩马腿、塞象眼、炮隔山打牛等特殊逻辑。

3.1.3胜负判定

检测是否将死对方将帅(需扩展逻辑)。

检查是否困毙(无合法移动)。

3.1.4胜负判定回合控制

红黑双方轮流操作,通过current_player变量切换。

3.2 数据库设计

暂时未设计数据库,开发者人员可以在此基础自行设计优化。

第四章 详细设计

4.1 相关技术介绍

4.1.1 Windows 10操作系统

Windows 10 是微软公司于 2015 年 7 月 29 日正式发布的一款操作系统。他主要有以下优点:

  1. 界面美观
    Windows 10 的界面设计简洁明了,布局合理。开始菜单采用了磁贴和传统菜单相结合的方式。磁贴可以显示实时信息,例如新闻、天气、应用通知等。这种设计既保留了 Windows 系统经典的菜单操作方式,又增加了现代化的动态元素,方便用户快速获取重要信息。
  2. 兼容性强
    对于软件的兼容性,Windows 10 支持大量的旧版软件。无论是办公软件,如微软 Office 系列,还是各种游戏和专业设计软件,Windows 10 都能很好地运行。这使得用户在升级到 Windows 10 后,不需要重新安装大部分之前使用的软件,降低了使用门槛和成本。
    在硬件兼容性方面,Windows 10 能够支持多种硬件设备,包括各种品牌的电脑主板、显卡、打印机、扫描仪等。它的驱动程序库丰富,很多硬件设备在接入系统时可以自动安装相应的驱动程序,减少了用户查找和安装驱动的麻烦。
  3. 性能提升
    启动速度相比之前的 Windows 系统有很大提高。Windows 10 优化了系统启动过程,通过改进的引导加载程序和内核初始化等技术,使得系统能够更快地从关机状态启动到桌面。
    在多任务处理方面表现良好。Windows 10 提供了虚拟桌面功能,用户可以创建多个虚拟桌面来运行不同的应用程序。例如,一个桌面用于工作相关的文档处理和邮件收发,另一个桌面用于娱乐,如观看视频和玩游戏。这样可以有效避免任务之间的相互干扰,提高工作效率。
  4. 安全性加强
    Windows 10 引入了多项安全特性。例如,Windows Hello 是一种生物识别技术,支持指纹、面部识别和虹膜识别等多种身份验证方式。这比传统的密码登录更加安全可靠,因为生物特征很难被复制和破解。
    系统还内置了 Windows Defender 防病毒软件,能够实时监测和阻止病毒、恶意软件等的入侵。它会自动更新病毒库,以应对不断出现的新型恶意软件,为用户提供便捷的系统安全防护。

4.1.2 PyCharm

PyCharm 是一款功能强大的 Python 集成开发环境(IDE),由JetBrains公司开发。PyCharm 能够根据导入的模块、当前项目中的代码结构等提供智能的代码补全功能。其次,他可以实时检查代码中的语法错误、未使用的变量等。当出现错误时,会在代码旁边显示错误标记,并且在鼠标悬停时提供详细的错误信息,帮助开发者快速定位和修复问题。另外,允许开发者在 Python 脚本、Web 应用等不同类型的项目中进行调试。可以设置断点,在程序运行到断点处时暂停,查看变量的值、调用堆栈等信息。此外,对于数据科学和机器学习项目,集成了对数据可视化库(如 Matplotlib)、数据处理库(如 Pandas)等的友好支持。可以方便地在 IDE 内查看数据图表,调试数据处理流程。最后,其社区版是免费的,提供了基本的 Python 编程功能,包括智能代码编辑、版本控制集成等。对于个人学习和一些简单的项目开发已经足够使用。

4.1.3 Python 3.9

Python 3.9 是 Python 编程语言的一个重要版本,于 2020 年 10 月 5 日正式发布。他引入 | 和 |= 运算符,用于合并和更新字典,使字典操作更简洁,还采用基于 PEG(Parsing Expression Grammar)的新解析器,取代了之前的基于 LL(1) 的解析器,提高了语法解析的灵活性和性能。其次,他还进一步优化了基于生成器的协程,使用新的语法 async def 和 await,使异步编程更简洁高效;优化了事件循环机制,提高了异步 I/O 操作的性能。另外,对 ProcessPoolExecutor 类进行了优化,更好地管理多个子进程;对多进程间的共享内存机制进行了优化,减少了数据传递的开销。最后,他还对解释器进行了多项改进,如 PEP 573 引入了从 C 扩展类型的方法快速访问模块状态,提高了解释器的性能和稳定性。

4.2 软件安装

4.2.1 PyCharm的安装(网上教程很多可自行下载安装)

PyCharm的安装步骤如下‌:

‌1. 下载安装包‌

访问PyCharm官网下载对应操作系统的安装包。根据系统类型(Windows、macOS、Linux)和处理器架构(如Intel或ARM64)选择合适的版本。‌

社区版免费,专业版需付费但可试用30天。‌

‌2. ‌安装过程‌

双击下载的.exe(Windows)、.dmg(macOS)或.tar.gz(Linux)文件启动安装程序。‌

选择安装路径(建议不安装在系统盘),勾选所有可选组件(如创建桌面快捷方式、关联文件类型等)。‌

等待安装完成,完成后不要勾选"立即启动",选择稍后手动启动。‌

4.2.2 Python 3.9的安装(网上教程很多可自行下载安装)

Python 3.9的安装步骤如下‌:

‌1. 下载安装包‌

‌2. ‌安装过程‌

过于简单这里不详细介绍,如若有不懂的请参考:https://blog.csdn.net/weixin_55154866/article/details/134197661

4.2.3 PyCharm中选择Python 3.9解释器

打开PyCharm 并进入你的项目。

‌1. 打开设置:

在Windows或Linux上,可以通过点击File > Settings来访问。

在Mac上,可以通过点击PyCharm > Preferences来访问。

在设置窗口中,找到并点击Project: your_project_name > Python Interpreter。

‌2. 选择解释器:

如果你已经安装了Python 3.9,并且它没有被自动检测到,你可以点击右侧的齿轮图标(或下拉菜单),选择Add。

在弹出的窗口中,选择System Interpreter或Virtualenv Environment(如果你想要在一个虚拟环境中使用Python 3.9)。

选择你的Python 3.9解释器。如果你不确定它的位置,可以点击...按钮,然后浏览到你的Python安装目录(选择直接在4.2.2 Python 3.9安装的路径,也有自定义的路径,例如C:\python3\python.exe,通常在C:\Users\你的用户名\AppData\Local\Programs\Python\Python39\,Windows上;或在/usr/local/bin/python3.9,Linux或Mac上)。

  1. 应用并确认:选择解释器后,点击OK或Apply来保存你的设置。

4.2.4 安装Pygame库

‌1. 方法 1:通过 PyCharm 的终端(Terminal)执行

打开 PyCharm 项目:确保项目已加载到 PyCharm 中。

打开终端:

在 PyCharm 界面底部找到 Terminal 标签(通常在左下角)。

若未显示,可通过菜单栏 View → Tool Windows → Terminal 打开。

输入命令:

bash 复制代码
pip install pygame

‌2. 方法 2:通过 PyCharm 的图形化界面安装

打开设置界面:

菜单栏 File → Settings(Windows)或 PyCharm → Preferences(macOS)。

进入项目解释器配置:

左侧导航栏选择 Project: <项目名> → Python Interpreter。(下图展示为汉化包的PyCharm安装pygame的位置)

安装库:

点击右上角的 + 按钮(安装包按钮)。

在搜索框中输入 pygame。

选中 pygame 后点击 Install Package。

等待安装完成(底部进度条显示)。

4.3 主要功能实现

4.3.1图形界面

用户需要图形界面,所以得选一个合适的库。Pygame是Python中常用的游戏开发库,适合2D游戏,而且有较多的教程和资源,这对用户来说可能更容易上手。虽然Tkinter也是选项,但Pygame在图形渲染和事件处理上更强大,适合复杂的棋盘和棋子绘制。

4.3.2棋盘

中国象棋棋盘有特定的线条,比如九纵十横,中间的楚河汉界,还有九宫格。需要计算每个格子的尺寸,确保棋盘布局正确。棋子的摆放要符合初始位置,红黑双方的不同棋子名称也需要正确显示。

4.3.3移动规则

每个棋子有不同的走法,比如马的日字,象的田字,炮的隔山打牛等。需要为每个棋子编写移动验证函数,确保符合规则。特别是蹩马腿和塞象眼的情况,这些规则容易出错,需要仔细处理。

4.3.4游戏逻辑

游戏逻辑方面,需要处理轮流走子、胜负判定、将军和困毙的情况。胜负判定包括将死对方将帅,或者困毙,即对方无子可动。同时,还要处理和棋的情况,比如三次重复局面或长将的判定。

4.3.5事件处理

用户通过鼠标点击选择棋子和移动位置。需要跟踪鼠标事件,判断点击的是哪个位置,当前是否有棋子被选中,移动是否合法。合法的话就更新棋盘状态,并切换玩家回合。

4.3.6 其他功能

另外,用户可能需要保存棋局或回放功能,但根据问题描述,主要需求是实现基本玩法,所以可以先专注于核心功能,后续再扩展。

4.4 功能展示

4.4.1界面展示

由于功能简单清晰,设计也没有难度,主要功能和伪代码就不加说明简述了。

界面设计主要伪代码:

bash 复制代码
    def draw(self, screen):
        screen.fill(COLOR_BG)
        # ---------- 绘制横线(完整保留)----------
        for row in range(BOARD_ROWS):
            y = MARGIN_TOP + row * GRID_SIZE
            pygame.draw.line(screen, COLOR_LINE,
                             (MARGIN_LEFT, y),
                             (MARGIN_LEFT + BOARD_WIDTH, y), 2)

        # ---------- 绘制竖线(特殊处理河道区域)----------
        for col in range(BOARD_COLS):
            x = MARGIN_LEFT + col * GRID_SIZE
            # 仅最左、最右列绘制完整竖线
            if col == 0 or col == BOARD_COLS - 1:
                pygame.draw.line(screen, COLOR_LINE,
                                 (x, MARGIN_TOP),
                                 (x, MARGIN_TOP + BOARD_HEIGHT), 2)
            else:
                # 中间竖线分两段绘制(跳过河道区域)
                # 上段:从顶部到河道上边缘
                pygame.draw.line(screen, COLOR_LINE,
                                 (x, MARGIN_TOP),
                                 (x, MARGIN_TOP + 4 * GRID_SIZE), 2)
                # 下段:从河道下边缘到底部
                pygame.draw.line(screen, COLOR_LINE,
                                 (x, MARGIN_TOP + 5 * GRID_SIZE),
                                 (x, MARGIN_TOP + BOARD_HEIGHT), 2)
        # 绘制九宫斜线(坐标增加边距)
        palace_lines = [
            (3, 0, 5, 2), (5, 0, 3, 2),  # 红方九宫
            (3, 7, 5, 9), (5, 7, 3, 9)  # 黑方九宫
        ]
        for x1, y1, x2, y2 in palace_lines:
            start_x = MARGIN_LEFT + x1 * GRID_SIZE
            start_y = MARGIN_TOP + y1 * GRID_SIZE
            end_x = MARGIN_LEFT + x2 * GRID_SIZE
            end_y = MARGIN_TOP + y2 * GRID_SIZE
            pygame.draw.line(screen, COLOR_LINE, (start_x, start_y), (end_x, end_y), 2)

        # ---------- 绘制"楚河汉界"文字(居中)----------
        river_center_y = MARGIN_TOP + 4.5 * GRID_SIZE
        font = pygame.font.Font(r'C:\Windows\Fonts\msyh.ttc', 32)
        text = font.render("楚河  汉界", True, COLOR_LINE)
        text_rect = text.get_rect(center=(WINDOW_WIDTH // 2, river_center_y))
        screen.blit(text, text_rect)

        # 绘制棋子(位置增加边距)
        for row in range(BOARD_ROWS):
            for col in range(BOARD_COLS):
                piece = self.board[row][col]
                if piece:
                    x = MARGIN_LEFT + col * GRID_SIZE
                    y = MARGIN_TOP + row * GRID_SIZE
                    piece.draw(screen, (x, y))

4.4.2棋子移动展示

棋子移动主要伪代码:

bash 复制代码
    def is_valid_move(self, new_pos, board):
        """通用规则检查:边界、目标位置是否为己方棋子"""
        row, col = new_pos
        # 检查是否越界
        if row < 0 or row >= BOARD_ROWS or col < 0 or col >= BOARD_COLS:
            return False
        # 检查目标位置是否有己方棋子
        target_piece = board[row][col]
        if target_piece and target_piece.color == self.color:
            return False
        return True

4.4.3游戏胜利展示

判断一方胜利主要伪代码:

python 复制代码
    def check_victory(self, current_player_color):
        """判断当前是否分出胜负,返回胜方颜色(红/黑)或 None"""
        # 检测将帅是否被吃
        red_king = self.find_king("red")
        black_king = self.find_king("black")
        if not red_king:
            return "black"
        if not black_king:
            return "red"

        # 检测是否将帅照面(主动移动导致的一方判负)
        if self.kings_face_each_other():
            return "red" if current_player_color == "red" else "black"

        # 检测当前玩家是否被将死或困毙
        opponent_color = "black" if current_player_color == "red" else "red"
        if self.is_checkmate(opponent_color):
            return current_player_color
        if self.is_stalemate(opponent_color):
            return current_player_color

        return None

    def find_king(self, color):
        """查找指定颜色的将/帅位置"""
        for row in range(BOARD_ROWS):
            for col in range(BOARD_COLS):
                piece = self.board[row][col]
                if isinstance(piece, King) and piece.color == color:
                    return (row, col)
        return None

第五章 测试

您可以手动测试相关功能是否实现或者完整。本次单例测试发现鼠标相应较慢,且发现该游戏没有声音提示或者拿起棋子或者放下棋子的高亮显示,须要后续优化修改。

第六章 总结与展望

6.1 总结

本文设计并实现了一个简单的中国象棋的小游戏程序,主要功能包括:

基本棋盘绘制和棋子显示。

基本点击选择和移动功能。

中国象棋的基本游戏玩法设计,各棋子的详细走法规则。例如,

1.胜负判断逻辑

2.将军检查

3.炮的隔山打牛规则

4.马的蹩脚规则

5.象的田字走法和塞象眼规则

6.士的斜线走法限制

7.兵过河后的移动规则变化

8.将帅不能照面规则,以及其他相关规则。

6.2 展示

该项目程序,当前存在诸多问题,在未来的设计中希望在以下几个方面进行改进和优化:

1.添加游戏状态显示(当前玩家、胜负提示)。

2.增加悔棋功能。

3.添加音效。

4.增加投降功能,允许玩家主动认输。

5.建立用户信息数据库,实现棋谱记录、网络联机对战等其他复杂功能。

6.实现AI对战

参考文献

致谢

感谢CSDN官方的大力支持。

完整源程序代码

主要包括以下四个文件1.config.py - 全局配置文件;2.chessboard.py - 棋盘逻辑文件;3.pieces.py - 棋子逻辑文件;4.main.py - 主程序。

1.config.py

python 复制代码
# 棋盘与窗口尺寸


WINDOW_WIDTH = 720  # 8格宽度 + 左右边距
WINDOW_HEIGHT = 800  # 9格高度 + 上下边距
GRID_SIZE = 80       # 每格边长(交叉点间距)
BOARD_ROWS = 10      # 10行交叉点(实际9行格子)
BOARD_COLS = 9       # 9列交叉点(实际8列格子)


# 边距配置(确保棋盘四周有足够空间)
MARGIN_LEFT = 40    # 左侧边距
MARGIN_TOP = 40     # 顶部边距
MARGIN_RIGHT = 40   # 右侧边距
MARGIN_BOTTOM = 40  # 底部边距

# 窗口尺寸(根据边距和棋盘尺寸动态计算)
BOARD_WIDTH = (BOARD_COLS - 1) * GRID_SIZE   # 棋盘实际宽度(交叉点间距)
BOARD_HEIGHT = (BOARD_ROWS - 1) * GRID_SIZE  # 棋盘实际高度
WINDOW_WIDTH = MARGIN_LEFT + BOARD_WIDTH + MARGIN_RIGHT
WINDOW_HEIGHT = MARGIN_TOP + BOARD_HEIGHT + MARGIN_BOTTOM

# 颜色定义
COLOR_BG = (240, 217, 181)  # 背景色
COLOR_LINE = (0, 0, 0)       # 棋盘线条
COLOR_RED = (255, 0, 0)      # 红方棋子
COLOR_BLACK = (0, 0, 0)      # 黑方棋子

2.chessboard.py

python 复制代码
import pygame
from config import *
from pieces import *

class ChessBoard:
    def __init__(self):
        # 初始化10x9的棋盘矩阵(每个位置初始为None)
        self.board = [[None for _ in range(BOARD_COLS)] for _ in range(BOARD_ROWS)]
        self.init_pieces()  # 放置棋子
        self.selected_piece = None  # 当前选中的棋子

    def init_pieces(self):
        # 红方棋子(位于棋盘下方,行号0-3)
        red_pieces = [
            Rook("red", (0, 0)), Knight("red", (0, 1)), Elephant("red", (0, 2)),
            Guard("red", (0, 3)), King("red", (0, 4)), Guard("red", (0, 5)),
            Elephant("red", (0, 6)), Knight("red", (0, 7)), Rook("red", (0, 8)),
            Cannon("red", (2, 1)), Cannon("red", (2, 7)),
            Soldier("red", (3, 0)), Soldier("red", (3, 2)), Soldier("red", (3, 4)),
            Soldier("red", (3, 6)), Soldier("red", (3, 8))
        ]

        # 黑方棋子(位于棋盘上方,行号6-9)
        black_pieces = [
            Rook("black", (9, 0)), Knight("black", (9, 1)), Elephant("black", (9, 2)),
            Guard("black", (9, 3)), King("black", (9, 4)), Guard("black", (9, 5)),
            Elephant("black", (9, 6)), Knight("black", (9, 7)), Rook("black", (9, 8)),
            Cannon("black", (7, 1)), Cannon("black", (7, 7)),
            Soldier("black", (6, 0)), Soldier("black", (6, 2)), Soldier("black", (6, 4)),
            Soldier("black", (6, 6)), Soldier("black", (6, 8))
        ]

        # 将棋子放入棋盘矩阵
        for piece in red_pieces + black_pieces:
            row, col = piece.position
            self.board[row][col] = piece

    def draw(self, screen):
        screen.fill(COLOR_BG)
        # ---------- 绘制横线(完整保留)----------
        for row in range(BOARD_ROWS):
            y = MARGIN_TOP + row * GRID_SIZE
            pygame.draw.line(screen, COLOR_LINE,
                             (MARGIN_LEFT, y),
                             (MARGIN_LEFT + BOARD_WIDTH, y), 2)

        # ---------- 绘制竖线(特殊处理河道区域)----------
        for col in range(BOARD_COLS):
            x = MARGIN_LEFT + col * GRID_SIZE
            # 仅最左、最右列绘制完整竖线
            if col == 0 or col == BOARD_COLS - 1:
                pygame.draw.line(screen, COLOR_LINE,
                                 (x, MARGIN_TOP),
                                 (x, MARGIN_TOP + BOARD_HEIGHT), 2)
            else:
                # 中间竖线分两段绘制(跳过河道区域)
                # 上段:从顶部到河道上边缘
                pygame.draw.line(screen, COLOR_LINE,
                                 (x, MARGIN_TOP),
                                 (x, MARGIN_TOP + 4 * GRID_SIZE), 2)
                # 下段:从河道下边缘到底部
                pygame.draw.line(screen, COLOR_LINE,
                                 (x, MARGIN_TOP + 5 * GRID_SIZE),
                                 (x, MARGIN_TOP + BOARD_HEIGHT), 2)
        # 绘制九宫斜线(坐标增加边距)
        palace_lines = [
            (3, 0, 5, 2), (5, 0, 3, 2),  # 红方九宫
            (3, 7, 5, 9), (5, 7, 3, 9)  # 黑方九宫
        ]
        for x1, y1, x2, y2 in palace_lines:
            start_x = MARGIN_LEFT + x1 * GRID_SIZE
            start_y = MARGIN_TOP + y1 * GRID_SIZE
            end_x = MARGIN_LEFT + x2 * GRID_SIZE
            end_y = MARGIN_TOP + y2 * GRID_SIZE
            pygame.draw.line(screen, COLOR_LINE, (start_x, start_y), (end_x, end_y), 2)

        # ---------- 绘制"楚河汉界"文字(居中)----------
        river_center_y = MARGIN_TOP + 4.5 * GRID_SIZE
        font = pygame.font.Font(r'C:\Windows\Fonts\msyh.ttc', 32)
        text = font.render("楚河  汉界", True, COLOR_LINE)
        text_rect = text.get_rect(center=(WINDOW_WIDTH // 2, river_center_y))
        screen.blit(text, text_rect)

        # 绘制棋子(位置增加边距)
        for row in range(BOARD_ROWS):
            for col in range(BOARD_COLS):
                piece = self.board[row][col]
                if piece:
                    x = MARGIN_LEFT + col * GRID_SIZE
                    y = MARGIN_TOP + row * GRID_SIZE
                    piece.draw(screen, (x, y))
    def check_victory(self, current_player_color):
        """判断当前是否分出胜负,返回胜方颜色(红/黑)或 None"""
        # 检测将帅是否被吃
        red_king = self.find_king("red")
        black_king = self.find_king("black")
        if not red_king:
            return "black"
        if not black_king:
            return "red"

        # 检测是否将帅照面(主动移动导致的一方判负)
        if self.kings_face_each_other():
            return "red" if current_player_color == "red" else "black"

        # 检测当前玩家是否被将死或困毙
        opponent_color = "black" if current_player_color == "red" else "red"
        if self.is_checkmate(opponent_color):
            return current_player_color
        if self.is_stalemate(opponent_color):
            return current_player_color

        return None

    def find_king(self, color):
        """查找指定颜色的将/帅位置"""
        for row in range(BOARD_ROWS):
            for col in range(BOARD_COLS):
                piece = self.board[row][col]
                if isinstance(piece, King) and piece.color == color:
                    return (row, col)
        return None

    def kings_face_each_other(self):
        """检测将帅是否直接照面(中间无棋子)"""
        red_king = self.find_king("red")
        black_king = self.find_king("black")
        if red_king is None or black_king is None:
            return False
        red_row, red_col = red_king
        black_row, black_col = black_king
        if red_col != black_col:
            return False
        # 检查同一列中间是否有棋子
        start_row = min(red_row, black_row) + 1
        end_row = max(red_row, black_row)
        for row in range(start_row, end_row):
            if self.board[row][red_col] is not None:
                return False
        return True

    def is_in_check(self, color):
        """检测某方是否被将军"""
        king_pos = self.find_king(color)
        if not king_pos:
            return False
        # 遍历所有对方棋子,检查是否能攻击到将/帅
        opponent_color = "red" if color == "black" else "black"
        for row in range(BOARD_ROWS):
            for col in range(BOARD_COLS):
                piece = self.board[row][col]
                if piece and piece.color == opponent_color:
                    if piece.is_valid_move(king_pos, self.board):
                        return True
        return False

    def is_checkmate(self, color):
        """检测某方是否被将死(被将军且无路可走)"""
        if not self.is_in_check(color):
            return False
        # 遍历所有己方棋子,检查是否存在合法移动解除将军
        for row in range(BOARD_ROWS):
            for col in range(BOARD_COLS):
                piece = self.board[row][col]
                if piece and piece.color == color:
                    # 生成该棋子的所有可能移动位置
                    for new_row in range(BOARD_ROWS):
                        for new_col in range(BOARD_COLS):
                            if piece.is_valid_move((new_row, new_col), self.board):
                                # 模拟移动并检查是否仍被将军
                                original_piece = self.board[new_row][new_col]
                                self.board[row][col] = None
                                self.board[new_row][new_col] = piece
                                still_in_check = self.is_in_check(color)
                                self.board[row][col] = piece
                                self.board[new_row][new_col] = original_piece
                                if not still_in_check:
                                    return False
        return True

    def is_stalemate(self, color):
        """检测某方是否困毙(未被将军但无合法移动)"""
        if self.is_in_check(color):
            return False
        # 检查是否有任何合法移动
        for row in range(BOARD_ROWS):
            for col in range(BOARD_COLS):
                piece = self.board[row][col]
                if piece and piece.color == color:
                    for new_row in range(BOARD_ROWS):
                        for new_col in range(BOARD_COLS):
                            if piece.is_valid_move((new_row, new_col), self.board):
                                return False
        return True

3.pieces.py

python 复制代码
from config import *
import pygame

class Piece:
    """棋子基类,定义通用属性和方法"""

    def __init__(self, color, position):
        self.color = color  # "red" 或 "black"
        self.position = position  # 棋盘逻辑坐标 (row, col)
        self.name = "Piece"  # 棋子名称(子类需重写)

    def draw(self, screen, pos):
        """棋子圆心对齐交叉点"""
        fill_color = COLOR_RED if self.color == "red" else COLOR_BLACK
        text_color = COLOR_BLACK if self.color == "red" else COLOR_RED
        # 绘制圆形
        pygame.draw.circle(screen, fill_color, pos, GRID_SIZE//2 - 5)
        # 绘制文字
        font = pygame.font.Font(r'C:\Windows\Fonts\msyh.ttc', 32)
        text = font.render(self.name, True, text_color)
        text_rect = text.get_rect(center=pos)
        screen.blit(text, text_rect)

    def is_valid_move(self, new_pos, board):
        """通用规则检查:边界、目标位置是否为己方棋子"""
        row, col = new_pos
        # 检查是否越界
        if row < 0 or row >= BOARD_ROWS or col < 0 or col >= BOARD_COLS:
            return False
        # 检查目标位置是否有己方棋子
        target_piece = board[row][col]
        if target_piece and target_piece.color == self.color:
            return False
        return True

    def is_in_palace(self, pos):
        """判断位置是否在九宫内"""
        row, col = pos
        if self.color == "red":
            return 0 <= row <= 2 and 3 <= col <= 5
        else:
            return 7 <= row <= 9 and 3 <= col <= 5

    def is_over_river(self, pos):
        """判断是否过河(兵/卒专用)"""
        return (self.color == "red" and pos[0] >= 5) or (self.color == "black" and pos[0] <= 4)

    def path_clear(self, start, end, board, check_diagonal=False):
        """检查两点之间的直线路径是否畅通(用于车、炮移动)"""
        start_row, start_col = start
        end_row, end_col = end
        row_step = 1 if end_row > start_row else -1 if end_row < start_row else 0
        col_step = 1 if end_col > start_col else -1 if end_col < start_col else 0

        # 斜线移动时需检查步长
        if check_diagonal and abs(row_step) + abs(col_step) != 2:
            return False

        current_row, current_col = start_row + row_step, start_col + col_step
        while (current_row, current_col) != (end_row, end_col):
            if board[current_row][current_col] is not None:
                return False
            current_row += row_step
            current_col += col_step
        return True


# --------------------- 具体棋子类实现 ---------------------

class King(Piece):
    """将/帅"""

    def __init__(self, color, position):
        super().__init__(color, position)
        self.name = "帥" if color == "red" else "將"

    def is_valid_move(self, new_pos, board):
        if not super().is_valid_move(new_pos, board):
            return False
        # 仅限九宫内直线移动一格
        old_row, old_col = self.position
        new_row, new_col = new_pos
        if not self.is_in_palace(new_pos):
            return False
        # 移动是否为直线一格
        if (abs(new_row - old_row) + abs(new_col - old_col)) != 1:
            return False
        # 将帅不能直接照面(需在外部逻辑中判断)
        return True


class Guard(Piece):
    """士/仕"""

    def __init__(self, color, position):
        super().__init__(color, position)
        self.name = "仕" if color == "red" else "士"

    def is_valid_move(self, new_pos, board):
        if not super().is_valid_move(new_pos, board):
            return False
        # 仅限九宫内斜线移动一格
        old_row, old_col = self.position
        new_row, new_col = new_pos
        if not self.is_in_palace(new_pos):
            return False
        # 斜线移动且步长为1
        if abs(new_row - old_row) != 1 or abs(new_col - old_col) != 1:
            return False
        return True


class Elephant(Piece):
    """象/相"""

    def __init__(self, color, position):
        super().__init__(color, position)
        self.name = "相" if color == "red" else "象"

    def is_valid_move(self, new_pos, board):
        if not super().is_valid_move(new_pos, board):
            return False
        old_row, old_col = self.position
        new_row, new_col = new_pos
        # 检查是否过河
        if (self.color == "red" and new_row > 4) or (self.color == "black" and new_row < 5):
            return False
        # 移动是否为"田"字对角线
        if abs(new_row - old_row) != 2 or abs(new_col - old_col) != 2:
            return False
        # 检查"象眼"是否被堵
        mid_row = (old_row + new_row) // 2
        mid_col = (old_col + new_col) // 2
        if board[mid_row][mid_col] is not None:
            return False
        return True


class Knight(Piece):
    """马/馬"""

    def __init__(self, color, position):
        super().__init__(color, position)
        self.name = "馬" if color == "red" else "马"

    def is_valid_move(self, new_pos, board):
        if not super().is_valid_move(new_pos, board):
            return False
        old_row, old_col = self.position
        new_row, new_col = new_pos
        # 计算移动是否为"日"字
        dx = abs(new_col - old_col)
        dy = abs(new_row - old_row)
        if not ((dx == 1 and dy == 2) or (dx == 2 and dy == 1)):
            return False
        # 检查"蹩马腿"
        if dx == 2:  # 横向移动两列,检查中间列是否有阻挡
            mid_col = (old_col + new_col) // 2
            if board[old_row][mid_col] is not None:
                return False
        else:  # 纵向移动两行,检查中间行是否有阻挡
            mid_row = (old_row + new_row) // 2
            if board[mid_row][old_col] is not None:
                return False
        return True


class Rook(Piece):
    """车/車"""

    def __init__(self, color, position):
        super().__init__(color, position)
        self.name = "車" if color == "red" else "车"

    def is_valid_move(self, new_pos, board):
        if not super().is_valid_move(new_pos, board):
            return False
        old_row, old_col = self.position
        new_row, new_col = new_pos
        # 必须直线移动
        if old_row != new_row and old_col != new_col:
            return False
        # 路径必须畅通
        return self.path_clear((old_row, old_col), (new_row, new_col), board)


class Cannon(Piece):
    """炮/砲"""

    def __init__(self, color, position):
        super().__init__(color, position)
        self.name = "炮" if color == "red" else "砲"

    def is_valid_move(self, new_pos, board):
        if not super().is_valid_move(new_pos, board):
            return False
        old_row, old_col = self.position
        new_row, new_col = new_pos
        # 必须直线移动
        if old_row != new_row and old_col != new_col:
            return False
        # 计算路径中的棋子数
        obstacles = 0
        start, end = sorted([old_row, new_row]) if old_row != new_row else sorted([old_col, new_col])
        for i in range(start + 1, end):
            if old_row == new_row:  # 横向移动
                if board[old_row][i] is not None:
                    obstacles += 1
            else:  # 纵向移动
                if board[i][old_col] is not None:
                    obstacles += 1
        # 吃子需隔1子,移动则不能有障碍
        target_piece = board[new_row][new_col]
        if target_piece:  # 吃子
            return obstacles == 1
        else:  # 移动
            return obstacles == 0


class Soldier(Piece):
    """兵/卒"""
    def __init__(self, color, position):
        super().__init__(color, position)
        self.name = "兵" if color == "red" else "卒"

    def is_valid_move(self, new_pos, board):
        if not super().is_valid_move(new_pos, board):
            return False
        old_row, old_col = self.position
        new_row, new_col = new_pos

        # 计算行和列的变化量
        delta_row = new_row - old_row
        delta_col = new_col - old_col

        # 根据颜色确定前进方向
        if self.color == "red":
            forward = 1  # 红方向下移动(逻辑行号增大)
        else:
            forward = -1  # 黑方向上移动(逻辑行号减小)

        # 过河前只能直进一格
        if not self.is_over_river(self.position):
            # 必须前进一格且列不变
            if delta_row != forward or delta_col != 0:
                return False
        else:
            # 过河后可前进一格或横向移动一格
            if not ((delta_row == forward and delta_col == 0) or  # 前进
                    (delta_row == 0 and abs(delta_col) == 1)):     # 横向
                return False

        # 移动总步长不超过1格
        if abs(delta_row) > 1 or abs(delta_col) > 1:
            return False

        return True

4.main.py

python 复制代码
import pygame
from chessboard import ChessBoard
from config import *

def main():
    pygame.init()
    screen = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))
    pygame.display.set_caption("中国象棋")
    clock = pygame.time.Clock()
    chess_board = ChessBoard()

    running = True
    current_player = "red"  # 红方先手

    while running:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
            elif event.type == pygame.MOUSEBUTTONDOWN:
                x, y = pygame.mouse.get_pos()
                # 计算点击位置相对于棋盘的坐标(扣除边距)
                board_x = x - MARGIN_LEFT
                board_y = y - MARGIN_TOP
                # 边界保护:点击在棋盘外时忽略
                if board_x < 0 or board_x > BOARD_WIDTH or board_y < 0 or board_y > BOARD_HEIGHT:
                    continue
                # 映射到最近的交叉点
                col = round(board_x / GRID_SIZE)
                logic_row = round(board_y / GRID_SIZE)
                col = max(0, min(col, BOARD_COLS - 1))
                logic_row = max(0, min(logic_row, BOARD_ROWS - 1))
                selected_piece = chess_board.board[logic_row][col]

                # 选择棋子或移动
                if chess_board.selected_piece is None:
                    if selected_piece and selected_piece.color == current_player:
                        chess_board.selected_piece = selected_piece
                else:
                    if chess_board.selected_piece.is_valid_move((logic_row, col), chess_board.board):
                        # 执行移动
                        chess_board.board[chess_board.selected_piece.position[0]][chess_board.selected_piece.position[1]] = None
                        chess_board.board[logic_row][col] = chess_board.selected_piece
                        chess_board.selected_piece.position = (logic_row, col)
                        current_player = "black" if current_player == "red" else "red"
                    chess_board.selected_piece = None

                # 每次移动后检查胜负
                winner = chess_board.check_victory(current_player)
                if winner:
                    print(f"游戏结束!胜利方:{winner}")
                    # 显示胜利提示(可扩展为图形界面弹窗)
                    font = pygame.font.Font(r'C:\Windows\Fonts\msyh.ttc', 32)
                    text = font.render(f"{winner}方胜利!", True, COLOR_RED if winner == "red" else COLOR_BLACK)
                    text_rect = text.get_rect(center=(WINDOW_WIDTH // 2, WINDOW_HEIGHT // 2))
                    screen.blit(text, text_rect)
                    pygame.display.flip()
                    pygame.time.wait(3000)  # 显示3秒后退出
                    running = False

        chess_board.draw(screen)
        pygame.display.flip()
        clock.tick(60)

    pygame.quit()

if __name__ == "__main__":
    main()
相关推荐
ghost14330 分钟前
C#学习第17天:序列化和反序列化
开发语言·学习·c#
難釋懷1 小时前
bash的特性-bash中的引号
开发语言·chrome·bash
Hello eveybody2 小时前
C++按位与(&)、按位或(|)和按位异或(^)
开发语言·c++
6v6-博客2 小时前
2024年网站开发语言选择指南:PHP/Java/Node.js/Python如何选型?
java·开发语言·php
Baoing_2 小时前
Next.js项目生成sitemap.xml站点地图
xml·开发语言·javascript
被AI抢饭碗的人2 小时前
c++:c++中的输入输出(二)
开发语言·c++
lqqjuly2 小时前
C++ 面向对象关键语法详解:override、虚函数、转发调用和数组引用传参-策略模式
开发语言·c++
CPPAlien2 小时前
Python for MLOps - 第一阶段学习笔记
python
喵~来学编程啦3 小时前
【模块化编程】Python文件路径检查、跳转模块
开发语言·python
only-lucky3 小时前
QT日历控件重写美化
开发语言·qt