我应该如何过滤掉被阻止的国际象棋动作?

How should I filter out blocked chess moves?

正如标题所述,我想知道如何过滤掉棋子的无效走法。

棋盘用 Map<Position, BaseChessman> 表示 其中 Position 是具有棋盘位置 (A1 - H8) 的枚举, BaseChessman 是一个抽象 class,具体 class 像 RookBishopKing 等继承自。

现在就手头的事情而言,如果我想移动棋子,我需要检查移动是否对棋子类型有效。

目前我正在尝试获得棋子的所有正确着法"Rook"。假设 "A1" 的 Rook 现在正站在蓝色圆圈所在的位置,我可以过滤掉除 "D8" 处的黑皇后之外的所有无效动作。我的问题是应该如何过滤掉被另一个棋子阻挡的移动,就像在这种情况下 "D7" 阻挡 "D8"。我可以将 som 字段添加到枚举中,我可以从中过滤掉被另一块阻挡的移动吗? (请参阅下图进行说明)

PS:我知道我的实现有缺陷,因为我现在没有检查我当前想要移动的部分是否被阻止。

用枚举表示的棋盘(从该枚举创建哈希图。 Key:Position,值:BaseChessman)

(什么是 Ghost?它是一个 "dummy" class,它充当 "None" 而不是使用 null)

public enum Position {

    A8(new Rook(BLACK)), B8(new Knight(BLACK)), C8(new Bishop(BLACK)), D8(new King(BLACK)), E8(new Queen(BLACK)), F8(new Bishop(BLACK)), G8(new Knight(BLACK)), H8(new Rook(BLACK)),
    A7(new Pawn(BLACK)), B7(new Pawn(BLACK)), C7(new Pawn(BLACK)), D7(new Pawn(BLACK)), E7(new Pawn(BLACK)), F7(new Pawn(BLACK)), G7(new Pawn(BLACK)), H7(new Pawn(BLACK)),
    A6(new Ghost(TRANSPARENT)), B6(new Ghost(TRANSPARENT)), C6(new Ghost(TRANSPARENT)), D6(new Ghost(TRANSPARENT)), E6(new Ghost(TRANSPARENT)), F6(new Ghost(TRANSPARENT)), G6(new Ghost(TRANSPARENT)), H6(new Ghost(TRANSPARENT)),
    A5(new Ghost(TRANSPARENT)), B5(new Ghost(TRANSPARENT)), C5(new Ghost(TRANSPARENT)), D5(new Ghost(TRANSPARENT)), E5(new Ghost(TRANSPARENT)), F5(new Ghost(TRANSPARENT)), G5(new Ghost(TRANSPARENT)), H5(new Ghost(TRANSPARENT)),
    A4(new Ghost(TRANSPARENT)), B4(new Ghost(TRANSPARENT)), C4(new Ghost(TRANSPARENT)), D4(new Ghost(TRANSPARENT)), E4(new Ghost(TRANSPARENT)), F4(new Ghost(TRANSPARENT)), G4(new Ghost(TRANSPARENT)), H4(new Ghost(TRANSPARENT)),
    A3(new Ghost(TRANSPARENT)), B3(new Ghost(TRANSPARENT)), C3(new Ghost(TRANSPARENT)), D3(new Ghost(TRANSPARENT)), E3(new Ghost(TRANSPARENT)), F3(new Ghost(TRANSPARENT)), G3(new Ghost(TRANSPARENT)), H3(new Ghost(TRANSPARENT)),
    A2(new Pawn(WHITE)), B2(new Pawn(WHITE)), C2(new Pawn(WHITE)), D2(new Pawn(WHITE)), E2(new Pawn(WHITE)), F2(new Pawn(WHITE)), G2(new Pawn(WHITE)), H2(new Pawn(WHITE)),
    A1(new Rook(WHITE)), B1(new Knight(WHITE)), C1(new Bishop(WHITE)), D1(new King(WHITE)), E1(new Queen(WHITE)), F1(new Bishop(WHITE)), G1(new Knight(WHITE)), H1(new Rook(WHITE));  

    private BaseChessman chessman;

    private Position(BaseChessman chessman) {
        this.chessman = chessman;
    }

    public BaseChessman getChessman(){
        return this.chessman;
    }
}

我的函数应该 return 该位置的可能移动列表。 (nextPosition目前没有使用)

private List<Position> getPossibleRookMoves(Color playerColor, Map<Position, BaseChessman> mapOfChessboard, Position currentPosition, Position nextPosition){
        String position = currentPosition.toString();
        String pos1 = position.substring(0, 1);
        String pos2 = position.substring(1, 2);

        return mapOfChessboard.keySet()
                .stream()
                .filter(pos -> (pos.toString().contains(pos1)) || pos.toString().contains(pos2))//Filter out any row and col that does not match "currentPosition"
                .filter(pos -> !(pos.toString().equals(position))) //Filter out the spot the piece stands on
                .filter(pos -> (pos.getChessman().getColor() != playerColor)) //Filter out spots where same color pieces stands on
                .sorted()
                .collect(Collectors.toList());

    }

你会如何解决这个问题?您会切换到二维数组而不是枚举和地图吗?

我认为您的数据模型对于问题域是有缺陷的。在您的代码中有许多迹象表明:必须通过位置名称解码列和行,将真正独立的概念存储在您的位置枚举中,必须人为地表示一个 'empty' 片段,没有简单的方法来获取两个位置之间的位置。

我建议使用以下型号:

public enum Position {
    A1(1, 1), A2(2, 1) ....

    private final int column;
    private final int row;
}

public class Move {
    private final List<Position> path;
}

public enum PieceType {
    PAWN, KNIGHT, BISHOP ...

    private final Function<Position,Stream<Move>> moveGenerator;

    public Stream<Move> getMoves(Position origin) { 
        return moveGenerator.apply(origin); 
    }
}

public enum Colour {
    WHITE, BLACK;
}

public class Piece {
    private final PieceType type;
    private final Colour colour;
}

public class Board {
    private final EnumMap<Position,Piece> pieces;

    public Stream<Move> getLegalMoves() {
        return pieces.entrySet().stream()
            .flatMap(e -> e.getValue().getType().getMoves(e.getKey()))
            .filter(this::isLegal);
    }

    private boolean isLegal(Move move) {
        Piece piece = pieces.get(move.getOrigin());
        return (!pieces.containsKey(move.getDestination()) 
            || pieces.get(move.getDestination()).getColour() != piece.getColour()))
            && move.getIntermediatePositions().noneMatch(pieces::containsKey))
    }
}

使用此模型,您无需为每种类型的棋子单独设置 类,并且您可以对每一步都一视同仁。为了简单起见,我省略了吸气剂,并且可能需要其他方法来获取同一行、同一列等中的所有位置,以帮助生成移动。