Java国际象棋机器人开发:如何判断棋子能否移动阻挡将军?
国际象棋机器人开发:将军阻挡判断问题
项目架构
- Board:存储Square二维数组、所有Square和Piece实例,所有字段设为静态以减少getter方法;包含多个ArrayList:白方合法移动、黑方合法移动、白方所有移动、黑方所有移动、白方所有棋子、黑方所有棋子。
- Square:存储Piece对象。
- Piece及其子类:包含两个ArrayList:
moveset(空棋盘下当前位置的所有理论可移动格子,用于处理牵制)和seen squares(不碰到己方棋子时的所有可达格子);King类包含boolean类型的inCheck字段。 - Move:接收Piece和Square参数,通过
play()方法处理实际移动逻辑、更新格子上的棋子等。
当前逻辑流程
每次移动后调用Board的vision()方法:
- 更新所有棋子的
moveset和seen squares,设置King的inCheck状态; - 将所有理论可行移动加入all moves集合;
- 筛选符合将军规则的合法移动,加入legal moves集合。
核心难点
将军状态下的合法移动判断:
- 已实现逻辑:若King处于将军状态,King自身的移动合法;
- 未解决问题:如何判断其他棋子的移动能否阻挡将军(需同时处理棋子牵制、双将等场景)。
已尝试方案
- 尝试判断己方棋子是否能看到将军方棋子所在格子(方向正确,但未找到具体实现方式);
- 尝试编写方法返回造成将军的棋子列表,但无实质性进展。
现有代码
vision()方法
public static void vision() { // updateBoardVision是所有Piece子类的重写方法,重新评估当前位置的所有理论可行移动及可达格子 for (Piece p : whitePieces) { p.updateBoardVision(); } for (Piece p : blackPieces) { p.updateBoardVision(); } // 若白方棋子能看到黑王所在格子,标记黑王处于将军状态 for (Piece p : whitePieces) { if (p.seenSquares.contains(Board.bK.square)) { Board.bK.setInCheck(true); } } // 反之,标记白王的将军状态 for (Piece p : blackPieces) { if (p.seenSquares.contains(Board.wK.square)) { Board.wK.setInCheck(true); } } // 收集所有理论可行移动(暂不考虑将军规则) for (Piece p : whitePieces) { for (Square s : p.seenSquares) { Move m = new Move(p, s); allWhiteMoves.add(m); } } for (Piece p : blackPieces) { for (Square s : p.seenSquares) { Move m = new Move(p, s); allBlackMoves.add(m); } } // 先将所有移动标记为非法 for (Move wm : allWhiteMoves) { wm.setValid(false); } for (Move bm : allBlackMoves) { bm.setValid(false); } for (Move aWhiteMove : allWhiteMoves) { // 白王处于将军状态时 if (wK.isInCheck()) { // 王的移动合法 if (aWhiteMove.getPiece().equals(wK)) { aWhiteMove.setValid(true); } // 此处未实现:判断己方棋子移动能否阻挡将军,及处理双将逻辑 // 后续需为黑方实现同样逻辑 } } // 收集最终合法移动 for (Move r : allWhiteMoves) { if (r.isValid()) { whiteLegalMoves.add(r); } } for (Move s : allBlackMoves) { if (s.isValid()) { blackLegalMoves.add(s); } } }
查找将军棋子的方法
// 返回造成白王将军的黑方棋子列表(支持多子同时将军) public static ArrayList<Piece> findCheckPieceWhite() { ArrayList<Piece> checkPieces = new ArrayList(); for (Piece p : blackPieces) { if (p.seenSquares.contains(wK.square)) { checkPieces.add(p); } } return checkPieces; } // 返回造成黑王将军的白方棋子列表 public static ArrayList<Piece> findCheckPieceBlack() { ArrayList<Piece> checkPieces = new ArrayList(); for (Piece p : whitePieces) { if (p.seenSquares.contains(bK.square)) { checkPieces.add(p); } } return checkPieces; }
解决思路与代码优化
1. 明确将军场景的合法应对规则
- 单将:三种合法解法:王移动到安全位置、吃掉将军棋子、移动棋子阻挡将军(仅针对车、象、后这类远程棋子);
- 双将:仅有一种合法解法:王移动到安全位置(无法同时阻挡或吃掉两个将军棋子)。
2. 核心逻辑实现
在vision()方法的将军处理部分,加入以下逻辑:
// 获取造成白王将军的黑方棋子列表 ArrayList<Piece> checkingPieces = findCheckPieceWhite(); // 处理单将场景 if (checkingPieces.size() == 1) { Piece checker = checkingPieces.get(0); Square kingSquare = wK.square; Square checkerSquare = checker.square; // 获取将军棋子与王之间的路径格子(仅远程棋子有可阻挡路径) List<Square> checkPath = getCheckPath(checkerSquare, kingSquare); for (Move aWhiteMove : allWhiteMoves) { Square targetSquare = aWhiteMove.getTargetSquare(); // 情况1:移动棋子吃掉将军棋子 if (targetSquare.equals(checkerSquare)) { if (isMoveSafeForKing(aWhiteMove)) { aWhiteMove.setValid(true); } } // 情况2:移动棋子阻挡将军(仅远程将军且路径存在) else if (!checkPath.isEmpty() && checkPath.contains(targetSquare)) { if (isMoveSafeForKing(aWhiteMove)) { aWhiteMove.setValid(true); } } } } // 双将场景:仅王的移动可能合法,已在上文处理 else if (checkingPieces.size() > 1) { // 无需额外操作,仅保留王的移动合法性 }
3. 辅助方法实现
获取将军路径的方法
// 获取远程将军棋子与被将军王之间的所有中间格子 public static List<Square> getCheckPath(Square from, Square to) { List<Square> path = new ArrayList<>(); Piece checker = from.getPiece(); // 非远程棋子(马、兵)无阻挡路径 if (!(checker instanceof Rook || checker instanceof Bishop || checker instanceof Queen)) { return path; } int fromX = from.getX(); int fromY = from.getY(); int toX = to.getX(); int toY = to.getY(); // 横向路径(车/后) if (fromX == toX) { int step = (toY > fromY) ? 1 : -1; for (int y = fromY + step; y != toY; y += step) { path.add(Board.squares[fromX][y]); } } // 纵向路径(车/后) else if (fromY == toY) { int step = (toX > fromX) ? 1 : -1; for (int x = fromX + step; x != toX; x += step) { path.add(Board.squares[x][fromY]); } } // 斜线路径(象/后) else if (Math.abs(fromX - toX) == Math.abs(fromY - toY)) { int xStep = (toX > fromX) ? 1 : -1; int yStep = (toY > fromY) ? 1 : -1; int x = fromX + xStep; int y = fromY + yStep; while (x != toX && y != toY) { path.add(Board.squares[x][y]); x += xStep; y += yStep; } } return path; }
验证移动是否让王脱离将军的方法
// 模拟移动后检查王是否处于安全状态 public static boolean isMoveSafeForKing(Move move) { // 保存当前棋盘状态 Piece originalTargetPiece = move.getTargetSquare().getPiece(); Square originalPieceSquare = move.getPiece().getSquare(); // 模拟执行移动 move.play(); // 检查王是否仍处于将军状态 boolean isSafe = !wK.isInCheck(); // 恢复原棋盘状态 move.getPiece().setSquare(originalPieceSquare); move.getTargetSquare().setPiece(originalTargetPiece); // 重新更新视野以恢复状态 vision(); return isSafe; }
内容的提问来源于stack exchange,提问作者deprexit
相关产品推荐
相关产品推荐

