☰
awesome-low-level-design 之 Chess Game(Java):从需求到 8x8 棋盘双人对弈的完整 LLD 实现剖析
2026/10/2 1:59:12 网站建设 项目流程
  • 示例工程

【免费下载链接】awesome-low-level-design

Learn Low Level Design (LLD) and prepare for interviews using free resources.

项目地址:https://gitcode.com/GitHub_Trending/aw/awesome-low-level-design
点击查看免费下载

导读

本文围绕 solutions/java/src/chessgame/README.md 展开,深入讲解该开源仓库中象棋(Chess)系统的 Low Level Design(LLD)实战方案:如何在 8x8 标准棋盘上实现双人对弈、棋子移动规则校验、回合管理与对局状态判定。读完本文,你将掌握一套可复用的面向对象建模思路(Board/Cell/Piece 分层、策略化棋子移动逻辑、统一异常处理),并能直接阅读、运行、扩展仓库中的 Java 实现,为面试中的 LLD 题目与真实系统设计提供参考。

Chess Game 类图

一、问题陈述与核心需求

原文档给出的问题陈述是:设计并实现一个国际象棋游戏,支持两名玩家在标准 8x8 棋盘上对弈,强制遵守国际象棋规则、校验走法合法性,并判定对局状态(将军 check、将死 checkmate、逼和 stalemate)。

对应的需求清单(README 原文要点)如下:

  • 双人对弈:游戏在两名玩家(白方 White 与黑方 Black)之间进行;
  • 标准棋盘:使用标准 8x8 棋盘;
  • 全部标准棋子:王(King)、后(Queen)、车(Rook)、象(Bishop)、马(Knight)、兵(Pawn)及其各自的移动规则;
  • 移动校验:按国际象棋规则校验走法,阻止非法移动;
  • 回合管理:双方交替走棋;
  • 对局状态:检测 check、checkmate、stalemate;
  • 异常处理:对非法走法抛出异常;
  • 可扩展性:易于增加走法历史、悔棋、AI 对手等功能。

从源码角度看,上述需求中的「双人对弈」「标准棋盘」「全部棋子」「移动校验」「回合管理」均已落地;而 check/checkmate/stalemate 的检测逻辑在 Board.java 中仍以// TODO: Implement checkmate logic/// TODO: Implement stalemate logic标注,当前返回false——这是阅读源码时值得注意的实现边界(详见第五节)。

二、核心实体总览

原文档给出了系统的核心实体清单,与仓库源码一一对应(全部位于 solutions/java/src/chessgame):

实体文件职责
ChessGameChessGame.java主控类,管理游戏流程、玩家回合与对局状态
BoardBoard.java8x8 棋盘,维护 64 个 Cell 与棋子位置
CellCell.java棋盘上的一个格子,持有行列坐标与棋子
PlayerPlayer.java玩家,含姓名与颜色
ColorColor.java枚举:WHITE、BLACK
MoveMove.java一次走法:起点 Cell → 终点 Cell
Piece(抽象)pieces/Piece.java所有棋子的基类
King/Queen/Rook/Bishop/Knight/Pawnpieces/具体棋子类,各自实现移动逻辑
InvalidMoveExceptionInvalidMoveException.java非法走法异常

三、类设计详解(结合源码)

3.1 ChessGame:游戏主控与回合循环

ChessGame.java 是系统的「门面」,核心字段与逻辑如下:

  • 字段:Board board、Player whitePlayer/blackPlayer、Player currentPlayer;
  • 构造与开局:无参构造new ChessGame()会创建new Board();随后通过setPlayers(whiteName, blackName)创建两名玩家,并将currentPlayer初始化为白方;
  • 主循环start():只要isGameOver()不为真就持续执行——打印当前玩家、通过getPlayerMove()读取控制台输入(源行/列、目标行/列)、调用board.movePiece(move)落子、成功后switchTurn()切换玩家;若捕获到InvalidMoveException则打印错误信息并提示重试;
  • 回合切换switchTurn():currentPlayer = currentPlayer == whitePlayer ? blackPlayer : whitePlayer,实现简单的三元切换;
  • 结束判定isGameOver():组合board.isCheckmate(...)与board.isStalemate(...)四种情况;
  • 结果展示displayResult():按将死/逼和分别输出「Black/White wins by checkmate!」或「The game ends in a stalemate!」。

源码级细节值得注意:getPlayerMove()中会校验piece == null || piece.getColor() != player.getColor(),不满足则抛出IllegalArgumentException("Invalid piece selection!"),防止玩家移动对方棋子或空格——这是回合管理在输入层的体现。

3.2 Board:棋盘状态与落子

Board.java 的关键实现:

  • 初始化:Cell[][] board为 8x8;setupPieces()按标准开局布局放子——第 1 行(row=1)放 8 个白兵,第 6 行(row=6)放 8 个黑兵;白方主将棋子在 row=0(Rook Knight Bishop Queen King Bishop Knight Rook),黑方在 row=7;
  • movePiece(Move):声明为synchronized(线程安全的落子接口),先取起点棋子,若piece == null || !piece.canMove(this, from, to)则返回false,否则把棋子写入终点Cell并将起点置空;
  • 查询接口:getCell(row, col)、getPiece(row, col)、setPiece(row, col, piece);
  • 状态检测:isCheck(Color)、isCheckmate(Color)、isStalemate(Color)三个方法的签名已经设计好,但 checkmate/stalemate 的完整逻辑尚未填充(TODO)。

一个需要留意的实现差异:README 中描述Board.movePiece会抛出InvalidMoveException,而当前源码中movePiece直接返回boolean(非法走法返回false);ChessGame.start()的try/catch捕获的InvalidMoveException在本次落子链路中暂未实际抛出。阅读与扩展时需以 Board.java 的实际行为为准。

3.3 Cell、Move、Player、Color

  • Cell.java:不可变的行列坐标(row、colfinal),可变的Piece;提供isOccupied()、getPiece()、setPiece();
  • Move.java:持有起点与终点两个Cell引用,提供getStart()/getEnd();
  • Player.java:name与color均为 final,构造时一次性注入;
  • Color.java:极简枚举,仅WHITE、BLACK,作为「阵营」的类型安全标记贯穿所有棋子与玩家。

3.4 Piece 抽象基类与多态设计

pieces/Piece.java 是所有棋子的抽象基类:

public abstract class Piece { protected final Color color; public Piece(Color color) { this.color = color; } public abstract boolean canMove(Board board, Cell from, Cell to); public Color getColor() { return color; } }

设计要点是:把「该棋子能否从 A 走到 B」抽象为canMove(Board, Cell, Cell),由每个子类通过多态各自实现。Board.movePiece只依赖这个统一接口做校验,因此新增棋子类型无需改动棋盘层——这正是 LLD 面试中「开闭原则」的典型示范。注意抽象方法还额外接收Board参数,为后续实现「阻挡路径」「吃子」「将军检测」等需要查询棋盘上下文的规则预留了接口。

四、六种棋子的移动规则源码剖析

原文档只列出棋子类名,这里结合 pieces/ 源码把每类棋子的判定逻辑拆解清楚(rowDiff = |to.row - from.row|,colDiff = |to.col - from.col|):

棋子文件判定规则(源码逻辑)
兵 PawnPawn.java白方:前进 1 格(rowDiff==1 && colDiff==0)、起始行 row=1 可走 2 格(rowDiff==2)、斜吃子(rowDiff==1 && colDiff==1且目标格有子);黑方对称(方向取反、起始行为 row=6)。该实现已覆盖方向性移动与斜向吃子,但尚未处理「升变」「吃过路兵」
马 KnightKnight.java经典 L 形:(rowDiff==2 && colDiff==1) || (rowDiff==1 && colDiff==2),天然可越过棋子
象 BishopBishop.java仅对角线:rowDiff == colDiff(当前版本未校验路径上是否被阻挡)
车 RookRook.java仅直线:from.row == to.row || from.col == to.col(当前版本未校验路径阻挡)
后 QueenQueen.java车 + 象的组合:(rowDiff == colDiff) || (from.row == to.row || from.col == to.col)
王 KingKing.java任意方向 1 格:rowDiff <= 1 && colDiff <= 1(未实现王车易位 castling)

从源码结构可以推断:当前版本聚焦「棋子自身几何走法」这一核心校验;路径阻挡(sliding pieces 中间有子不可穿过)、将军约束等更完整的规则属于后续可扩展点,且canMove的Board参数已为这类规则留好了扩展入口。

五、示例用法(对照源码的可行版本)

README 给出了示例,但其中new ChessGame(white, black)的带参构造在 ChessGame.java 中并不存在——实际实现是无参构造 +setPlayers(whiteName, blackName)。以当前源码为准的可运行示例:

import chessgame.ChessGame; public class Main { public static void main(String[] args) { ChessGame game = new ChessGame(); game.setPlayers("Alice", "Bob"); // 白方 Alice,黑方 Bob game.start(); // 进入回合循环,控制台输入走法 } }

若希望像 README 那样构造一个显式的Move对象,可参照源码的 Cell/Move 接口:

// 假设:new ChessGame() + setPlayers 后拿到棋盘 Board board = game.getBoard(); // getBoard() 为示例示意,需按需补充访问器 Move move = new Move(board.getCell(6, 4), board.getCell(4, 4)); // 黑方 row=6 col=4 → row=4 col=4(类似 e2→e4 的下移一格概念)

说明:仓库当前ChessGame未暴露getBoard()访问器,README 中的game.getBoard()属于文档侧示意;实际控制台交互由ChessGame.getPlayerMove()读取 row/col 数字完成,上述 Move 直接构造更适合用于单元测试或程序化走棋。

六、Demo 运行方式

仓库提供了演示入口 ChessGameDemo.java:

public class ChessGameDemo { public static void run() { ChessGame chessGame = new ChessGame(); chessGame.setPlayers("Alice", "Bob"); chessGame.start(); } }

README 中说明「参见ChessGameDemo.java获取示例用法与对局模拟」。该 Demo 以控制台交互为核心:每回合提示当前玩家名、依次输入源行/列与目标行/列(范围 0–7),非法选择会收到Illegal piece selection!提示,非法走法则被start()循环内的异常捕获逻辑拦下并要求重试。玩家可通过 solutions/java/src/chessgame 目录下的ChessGameDemo入口在本地 Java 环境中运行体验。

七、扩展框架:下一步演进方向

README 在「Extending the Framework」中给出了三个官方建议方向,结合源码现状可进一步细化为:

  1. 走法历史 / 悔棋 / 回放:可在ChessGame中维护List<Move>或引入 Memento 风格的快照(仓库在 design-patterns 目录下提供多种语言的 Memento 模式参考实现);Move已封装起点/终点,天然适合入栈记录;
  2. AI 对手:实现一个实现同一Player抽象(或独立策略接口)的电脑玩家,用canMove枚举所有合法走法并配合评估函数选子;
  3. GUI:Board.printBoard()尚未出现在当前 Board.java 中(README 类设计里列有该方法),可将其实现为文本棋盘输出,或在此基础上对接 Swing/JavaFX 等图形界面。

此外,从源码缺失处可推断出更贴近「完整规则」的扩展清单:填充isCheck/isCheckmate/isStalemate的 TODO 逻辑、滑动棋子(车/象/后)的路径阻挡校验、兵升变、王车易位、吃过路兵,以及把Board.movePiece的false返回值与InvalidMoveException统一起来,形成 README 所描述的「非法走法抛异常」语义。

八、快速索引

  • 需求与设计文档:solutions/java/src/chessgame/README.md
  • 主控与流程:ChessGame.java
  • 棋盘与落子:Board.java
  • 格子 / 走法 / 玩家 / 颜色:Cell.java · Move.java · Player.java · Color.java
  • 棋子体系:pieces/Piece.java 及 pieces/ 下六种棋子
  • 演示入口:ChessGameDemo.java
  • 类图:class-diagrams/chessgame-class-diagram.png
  • 示例工程

【免费下载链接】awesome-low-level-design

Learn Low Level Design (LLD) and prepare for interviews using free resources.

项目地址:https://gitcode.com/GitHub_Trending/aw/awesome-low-level-design
点击查看免费下载
上一篇:UnityOSGB终极指南:5分钟掌握OSGB格式在Unity中的高效加载
下一篇:如何快速部署Horilla开源HR系统:从零到精通的完整指南

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询