国际象棋编程(非人工智能)- 移动验证

9
我正在尝试编写自己的国际象棋引擎(无人工智能)。 我知道有国际象棋游戏起始套件,我看了一下以获取启发。
但我没有明白的是我的非王棋子的合法移动(这里是移动验证)在哪里,以防止将自己置于将军之中?
想象一下这种情况: A5-对手的车 A4-我的象 A3-我的国王
现在我不能移动我的象,因为那样就会被将军了。
或者您如何建议检查此情况?
谢谢。

你的意思是如何验证一步棋是否非法,因为这样做会将你置于将军的状态? - Kevin
哦,你的意思是想找出那个链接代码执行特定类型验证的位置? - AakashM
是的,当我阅读链接代码时,我没有注意到这个问题会在任何地方得到解决。 - o..o
1
好的,我明白你的意思了。那么,你实际上测试过了吗?那个类真的允许你将国王置于被发现的将军状态吗? - Konrad Morawski
描述棋盘位置的最佳方式是使用FENPGN也是必须的。我已经下载了国际象棋游戏入门套件,以便对其进行评估。分享您的发现或详细阐述您的问题,以保持讨论的持续进行。 - menjaraz
显示剩余5条评论
2个回答

19
对于给定的棋盘位置,大多数国际象棋引擎都会从生成伪合法着手。所谓伪合法,是指即使走法:
  • 将国王置于被将军状态
  • 将国王移动到被将军状态
  • 在正在受到攻击的方格上进行王车易位
也会生成。
这样做的原因是为了提高性能。由于许多走法实际上不会被搜索到(由于贝塔剪枝),通过避免完全检查走法的有效性,可以节省时间。
对于每个被搜索的走法,您需要检查它是否真正有效。通常,这是通过将国王的颜色和位置(以及王车易位的情况下国王旁边的方格)传递到一个IsAttacked方法中来完成的。如果该方法返回true,则表示该走法无效,因此您不应将其包含在搜索中。
以下是我自己的C#国际象棋引擎中的IsAttacked方法。请注意,我的引擎基于魔术位板,因此该代码不会直接适用于您链接的国际象棋入门套件。除非您熟悉魔术位板,否则翻译将不是一件简单的事情。
// 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;
    }
}

即使是点对点的国际象棋游戏,我们是否仍需要像魔术位棋盘这样的东西?或者这些算法只有在玩家与计算机对战时才需要? - kuldeep

0
我的国际象棋程序有一个检查棋盘上某个位置是否受到威胁的方法。在计算国王的可行走步数时,程序会检查国王可能移动到的每个位置是否受到威胁。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接