Для данной позиции на доске большинство шахматных движков начинают с генерации только псевдоправильных ходов. Под псевдолегальным я подразумеваю, что ход будет сгенерирован, даже если он:
- Оставляет короля под шахом
- Ставит короля под шах
- Замки на площадях, на которые нападают
Причиной этого является производительность. Поскольку многие ходы на самом деле не будут искаться из-за бета-сокращения, вы экономите время, избегая полной проверки правильности ходов.
Для каждого хода, который искомый ищется, вам нужно убедиться, что он действительно действителен. Обычно это делается путем передачи цвета и клетки короля (и клеток рядом с королем для рокировки) в метод IsAttacked. Если этот метод возвращает значение true, вы знаете, что перемещение недопустимо, и поэтому вам не следует включать его в поиск.
Это метод IsAttacked из моего собственного шахматного движка C#. Имейте в виду, что мой движок основан на 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;
}
}
person
HTTP 410
schedule
21.12.2011