【问题标题】:Chess programming (no AI) - moves validation国际象棋编程(无 AI) - 移动验证
【发布时间】:2023-03-11 09:10:02
【问题描述】:

我正在尝试编写自己的国际象棋引擎(没有 AI)。 我知道有Chess Game Starter Kit,我看了它以获得开始的灵感。

但我没有明白的是,我的非国王棋子的有效移动 (here is moves validation) 在哪里阻止让自己过牌?

想象一下情况:
A5 - 对手车
A4 - 我的主教
A3 - 我的国王

我现在不能移动我的主教,因为我要检查一下。

或者您建议如何检查这种情况?

谢谢

【问题讨论】:

  • 你的意思是你如何验证移动是非法的,因为这样做会让你受到控制?
  • 哦,你的意思是你想弄清楚 linked 代码在哪里进行特定类型的验证?
  • 是的,因为我是阅读的链接代码,我没有抓住这将在任何地方解决。
  • 您的链接似乎指向一般信息页面,而不是移动验证的描述。
  • 好的,我明白你的意思了。那么,你实际测试过吗?那个类真的允许你把你的国王放在一个被发现的检查中吗?

标签: c# chess


【解决方案1】:

对于给定的棋盘位置,大多数国际象棋引擎仅从生成伪合法移动开始。通过伪法律,我的意思是即使它会产生一个动作:

  • 任由国王控制
  • 检查国王
  • 正在被攻击的方格中的城堡

这样做的原因是性能。由于 beta 修剪实际上不会搜索许多移动,因此您可以通过避免全面检查移动有效性来节省时间。

对于 搜索的每一步,您都需要检查它是否真的有效。这通常通过将国王的颜色和方格(以及国王旁边的方格用于易位移动)传递给 IsAttacked 方法来完成。如果该方法返回 true,则您知道该移动无效,因此不应将其包含在搜索中。

这是我自己的 C# 国际象棋引擎中的 IsAttacked 方法。请记住,我的引擎基于magic bitboard,因此代码不会直接适用于您链接到的国际象棋初学者工具包。除非您熟悉魔术位板,否则翻译不会是微不足道的。

// IsAttacked is primarily used as a move legality test to see if a set of 
// one or more squares is under attack from the side to move.
// It returns true as soon as an attack is detected, otherwise returns false.
// It can be used for check detection, castling legality, or simply to 
// detect whether a specific square is attacked.
internal bool IsAttacked(Board board, UInt64 targetSquares, bool whiteAttacking)
{
    UInt64 slidingAttackers; Int32 targetSquare;
    UInt64 remainingTargetSquares = targetSquares;

    // Test for attacks by WHITE on any of the target squares.
    if (whiteAttacking) 
    {
        // For the remaining target squares...
        while (remainingTargetSquares != 0)
        {
            // Find the next square in the list.
            targetSquare = BitOperations.BitScanForward(remainingTargetSquares);

            // Is this square attacked by a pawn, knight, or king?
            if ((board.WhitePawns & Constants.BLACK_PAWN_ATTACKS[targetSquare]) != 0) return true;
            if ((board.WhiteKnights & Constants.KNIGHT_ATTACKS[targetSquare]) != 0) return true;
            if ((board.WhiteKing & Constants.KING_ATTACKS[targetSquare]) != 0) return true;

            // Is this square attacked by a queen or rook along a file or rank?
            slidingAttackers = board.WhiteQueens | board.WhiteRooks;
            if (slidingAttackers != 0)
            {
                if (this.RankMoves(board.OccupiedSquares, slidingAttackers, targetSquare) != 0) return true;
                if (this.FileMoves(board.OccupiedSquares, slidingAttackers, targetSquare) != 0) return true;
            }

            // Is this square attacked by a queen or bishop along a diagonal?
            slidingAttackers = board.WhiteQueens | board.WhiteBishops;
            if (slidingAttackers != 0)
            {
                if (this.DiagonalA8H1Moves(board.OccupiedSquares, slidingAttackers, targetSquare) != 0) return true;
                if (this.DiagonalA1H8Moves(board.OccupiedSquares, slidingAttackers, targetSquare) != 0) return true;
            }

            // This square isn't attacked - remove and move on to next target square.
            remainingTargetSquares ^= Constants.BITSET[targetSquare];
        }
    }

    // Test for attacks by BLACK on any of the target squares.
    else
    {
        // For the remaining target squares...
        while (remainingTargetSquares != 0)
        {
            // Find the next square in the list.
            targetSquare = BitOperations.BitScanForward(remainingTargetSquares);

            // Is this square attacked by a pawn, knight, or king?
            if ((board.BlackPawns & Constants.WHITE_PAWN_ATTACKS[targetSquare]) != 0) return true;
            if ((board.BlackKnights & Constants.KNIGHT_ATTACKS[targetSquare]) != 0) return true;
            if ((board.BlackKing & Constants.KING_ATTACKS[targetSquare]) != 0) return true;

            // Is this square attacked by a queen or rook along a file or rank?
            slidingAttackers = board.BlackQueens | board.BlackRooks;
            if (slidingAttackers != 0)
            {
                if (this.RankMoves(board.OccupiedSquares, slidingAttackers, targetSquare) != 0) return true;
                if (this.FileMoves(board.OccupiedSquares, slidingAttackers, targetSquare) != 0) return true;
            }

            // Is this square attacked by a queen or bishop along a diagonal?
            slidingAttackers = board.BlackQueens | board.BlackBishops;
            if (slidingAttackers != 0)
            {
                if (this.DiagonalA8H1Moves(board.OccupiedSquares, slidingAttackers, targetSquare) != 0) return true;
                if (this.DiagonalA1H8Moves(board.OccupiedSquares, slidingAttackers, targetSquare) != 0) return true;
            }

            // This square isn't attacked - remove and move on to next target square.
            remainingTargetSquares ^= Constants.BITSET[targetSquare];
        }
    }

    // None of the target squares are attacked.
    return false;
}

这是为怀特生成伪合法易位动作的代码片段:

// If White can still castle kingside...
if ((board.WhiteCastlingStatus & Board.EnumCastlingStatus.CanCastleOO) != 0)
{
    // And the White kingside castling squares (F1/G1) aren't occupied...
    if ((Constants.MASK_FG[Constants.WHITE_MOVE] & board.OccupiedSquares) == 0)
    {
        board.MoveBuffer[moveIndex++] = Constants.WHITE_CASTLING_OO;
    }
}

// If White can still castle queenside...
if ((board.WhiteCastlingStatus & Board.EnumCastlingStatus.CanCastleOOO) != 0)
{
    // And the White queenside castling squares (D1/C1/B1) aren't occupied...
    if ((Constants.MASK_BD[Constants.WHITE_MOVE] & board.OccupiedSquares) == 0)
    {
        board.MoveBuffer[moveIndex++] = Constants.WHITE_CASTLING_OOO;
    }
}

下面是检查伪合法易位移动是否真正合法的代码:

// Checks whether the King is moving from or into check.
// Checks whether the King is moving across attacked squares.
internal bool IsCastlingMoveLegal(Board board, Move move)
{
    if (move.IsCastlingOO)
    {
        if (move.IsWhiteMove)
        {
            // Are any of the White kingside castling squares (E1/F1/G1) attacked?
            return !this.IsAttacked(board, Constants.MASK_EG[Constants.WHITE_MOVE], false);
        }
        else
        {
            // Are any of the Black kingside castling squares (E8/F8/G8) attacked?
            return !this.IsAttacked(board, Constants.MASK_EG[Constants.BLACK_MOVE], true);
        }
    }
    else if (move.IsCastlingOOO)
    {
        if (move.IsWhiteMove)
        {
            // Are any of the White queenside castling squares (E1/D1/C1) attacked?
            return !this.IsAttacked(board, Constants.MASK_CE[Constants.WHITE_MOVE], false);
        }
        else
        {
            // Are any of the Black queenside castling squares (E8/D8/C8) attacked?
            return !this.IsAttacked(board, Constants.MASK_CE[Constants.BLACK_MOVE], true);
        }
    }
    // Not a castling move!
    else
    {
        Debug.Assert(false, "Not a castling move!");
        return true;
    }
}

【讨论】:

  • 即使是点对点的国际象棋游戏,我们也需要像魔法位板这样的东西吗?还是只有当玩家与电脑对战时才需要这样的算法?
【解决方案2】:

我的国际象棋程序有一个方法可以检查一个领域是否受到威胁。在计算国王的移动时,它会检查国王可能移动到的每个领域,如果该领域受到威胁。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-13
    • 1970-01-01
    • 2017-05-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多