当前位置: 首页 > 知识库问答 >
问题:

我该如何过滤被屏蔽的国际象棋动作?

黄宏大
2023-03-14

正如标题所描述的,我想知道我应该如何过滤掉棋子的无效移动。

电路板用地图表示

现在说到手头的事情,如果我想移动一个棋子,我需要检查该棋子的移动是否有效。

目前,我正在努力获得棋子“Rook”的所有正确动作。假设“A1”的那辆车不知怎么地站在蓝色圆圈的位置,我可以过滤掉所有无效的动作,除了“D8”的黑皇后。我的问题是,应该如何过滤掉被另一个棋子阻挡的棋步,比如在这个例子中,“D7”阻挡了“D8”。我是否可以将som字段添加到枚举中,从中筛选出被另一个片段阻止的移动?(请参见下图以了解更多信息)

用枚举表示的电路板(从该枚举创建哈希映射。键:位置,值:BaseChessman)

(鬼是什么?它应该是一个虚拟类,充当无,而不是使用空)

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;
    }
}

我的函数应该返回该位置可能的移动列表。(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());

    }

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


共有1个答案

温源
2023-03-14

我相信你的数据模型在问题领域是有缺陷的。代码中有很多这样的迹象:必须通过位置名称解码列和行,在位置枚举中存储真正独立的概念,必须人工表示一个“空”块,无法轻松获得两个位置之间的位置。

我建议采用以下模式:

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))
    }
}

有了这个模型,你不需要为每种类型的棋子单独设置类,你可以对每一步都一视同仁。为了保持简单,我省略了getter,并且可能需要额外的方法来获得同一行、同一列中的所有位置,以帮助生成移动。

 类似资料:
  • 上面的代码显示了一个可以上下移动的部分的示例。这不是一个有效的棋步。所以,如果我要移动一个皇后,我该怎么做呢?我们只是假设我们已经有了一个矩阵(x,y)8×8的板。

  • 我正在下国际象棋,除了一件事,我几乎得到了所有的东西:我需要使棋手不可能将棋子移动到棋盘上。我很难解决这个问题。 我现在用伪代码生成的有效移动是:类getMoveLocations(我定义了一个位置为国际象棋中的一个方块):如果这个位置在边界内,这个位置的棋子是敌人的棋子,并且模拟的移动不会导致棋盘被检查,然后将该位置添加到工件可以移动到的可能位置。 问题是我如何检查棋盘是否“在检查中”。在我的代

  • DreamChess 是一款开放源码、跨平台(可在 Windows、Mac OS X 及 Linux 上运行)的 3D 国际象棋游戏。该游戏包含自身的引擎 Dreamer,提供各种国际象棋棋盘,并具有背景音乐及声效等其他附属功能。

  • 我是编程的新手,我正在尝试实现一个小的象棋游戏。 我目前正在为每件作品的验证移动而挣扎。 字典是: 我在每个子类中都创建了一个函数(Pawn,Rook,Queen...)这应该能证明这次行动是正确的。语法类似于: 目前,我可以移动任何白色树懒或树懒上有一个黑色的部分(但我不能吃我自己),反之亦然。 我想我使用的是而不是列表列表这一事实使事情变得更加困难。我真的迷路了。这将是惊人的,如果你可以帮助我

  • 我已经有一个Board对象,包含一个碎片列表。Piece是一个抽象类,有一个位置(x,y)和一个颜色(黑色或白色)。然后是King、Queen、Knight这三个类,实现了Piece类。 谢谢