public void FindPinnedPieces() { var ownKingSquare = Bitwise.FirstSetSquare(GetKing(ColorToMove)); var ownPieces = ColorOccupancy[(int)ColorToMove]; var enemyRankFileAttackers = GetRooks(ColorLastMoved) | GetQueens(ColorLastMoved); var enemyDiagonalAttackers = GetBishops(ColorLastMoved) | GetQueens(ColorLastMoved); var enemyPieces = ColorOccupancy[(int)ColorLastMoved]; // Find pieces pinned to own king by enemy rank / file attackers. PinnedPieces = 0; Square attackerSquare; while ((attackerSquare = Bitwise.PopFirstSetSquare(ref enemyRankFileAttackers)) != Square.Illegal) { var betweenSquares = Board.RankFileBetweenSquares[(int)attackerSquare][(int)ownKingSquare]; if (betweenSquares == 0) { continue; } if ((betweenSquares & enemyPieces) == 0) { // No enemy pieces between enemy attacker and own king. var pinnedPieces = betweenSquares & ownPieces; if (Bitwise.CountSetBits(pinnedPieces) == 1) { // Exactly one own piece between enemy attacker and own king. // Piece is pinned to own king. PinnedPieces |= pinnedPieces; } } } // Find pieces pinned to own king by enemy diagonal attackers. while ((attackerSquare = Bitwise.PopFirstSetSquare(ref enemyDiagonalAttackers)) != Square.Illegal) { var betweenSquares = Board.DiagonalBetweenSquares[(int)attackerSquare][(int)ownKingSquare]; if (betweenSquares == 0) { continue; } if ((betweenSquares & enemyPieces) == 0) { // No enemy pieces between enemy attacker and own king. var pinnedPieces = betweenSquares & ownPieces; if (Bitwise.CountSetBits(pinnedPieces) == 1) { // Exactly one own piece between enemy attacker and own king. // Piece is pinned to own king. PinnedPieces |= pinnedPieces; } } } }
private void GeneratePieceMoves(MoveGeneration moveGeneration, ulong fromSquareMask, ulong toSquareMask) { for (var colorlessPiece = ColorlessPiece.Knight; colorlessPiece <= ColorlessPiece.Queen; colorlessPiece++) { var attacker = PieceHelper.GetPieceOfColor(colorlessPiece, ColorToMove); var pieces = PieceBitboards[(int)attacker] & fromSquareMask; if (pieces == 0) { continue; } var getPieceMovesMask = Board.PieceMoveMaskDelegates[(int)colorlessPiece]; var unOrEnemyOccupiedSquares = ~ColorOccupancy[(int)ColorToMove]; var enemyOccupiedSquares = ColorOccupancy[(int)ColorLastMoved]; Square fromSquare; while ((fromSquare = Bitwise.PopFirstSetSquare(ref pieces)) != Square.Illegal) { var pieceDestinations = moveGeneration switch { MoveGeneration.AllMoves => getPieceMovesMask(fromSquare, Occupancy) & unOrEnemyOccupiedSquares & toSquareMask, MoveGeneration.OnlyCaptures => getPieceMovesMask(fromSquare, Occupancy) & enemyOccupiedSquares & toSquareMask, MoveGeneration.OnlyNonCaptures => getPieceMovesMask(fromSquare, Occupancy) & ~Occupancy & toSquareMask, _ => throw new Exception($"{moveGeneration} move generation not supported.") }; Square toSquare; while ((toSquare = Bitwise.PopFirstSetSquare(ref pieceDestinations)) != Square.Illegal) { var victim = GetPiece(toSquare); var move = Move.Null; Move.SetPiece(ref move, attacker); Move.SetFrom(ref move, fromSquare); Move.SetTo(ref move, toSquare); if (victim != Piece.None) { Move.SetCaptureAttacker(ref move, attacker); } Move.SetCaptureVictim(ref move, victim); Moves[MoveIndex] = move; MoveIndex++; } } } }
private void GenerateKingMoves(MoveGeneration moveGeneration, ulong fromSquareMask, ulong toSquareMask) { var king = GetKing(ColorToMove) & fromSquareMask; if (king == 0) { return; } var unOrEnemyOccupiedSquares = ~ColorOccupancy[(int)ColorToMove]; var enemyOccupiedSquares = ColorOccupancy[(int)ColorLastMoved]; var attacker = PieceHelper.GetPieceOfColor(ColorlessPiece.King, ColorToMove); ulong move; var fromSquare = Bitwise.FirstSetSquare(king); if (fromSquare == Square.Illegal) { return; } var kingDestinations = moveGeneration switch { MoveGeneration.AllMoves => Board.KingMoveMasks[(int)fromSquare] & unOrEnemyOccupiedSquares & toSquareMask, MoveGeneration.OnlyCaptures => Board.KingMoveMasks[(int)fromSquare] & enemyOccupiedSquares & toSquareMask, MoveGeneration.OnlyNonCaptures => Board.KingMoveMasks[(int)fromSquare] & ~Occupancy & toSquareMask, _ => throw new Exception($"{moveGeneration} move generation not supported.") }; Square toSquare; while ((toSquare = Bitwise.PopFirstSetSquare(ref kingDestinations)) != Square.Illegal) { var victim = GetPiece(toSquare); move = Move.Null; Move.SetPiece(ref move, attacker); Move.SetFrom(ref move, fromSquare); Move.SetTo(ref move, toSquare); if (victim != Piece.None) { Move.SetCaptureAttacker(ref move, attacker); } Move.SetCaptureVictim(ref move, victim); Move.SetIsKingMove(ref move, true); Moves[MoveIndex] = move; MoveIndex++; } if (moveGeneration != MoveGeneration.OnlyCaptures) { for (var boardSide = BoardSide.Queen; boardSide <= BoardSide.King; boardSide++) { var castleEmptySquaresMask = Board.CastleEmptySquaresMask[(int)ColorToMove][(int)boardSide]; if (!KingInCheck && Game.Castling.Permitted(Castling, ColorToMove, boardSide) && ((Occupancy & castleEmptySquaresMask) == 0)) { // Castle toSquare = Board.CastleToSquares[(int)ColorToMove][(int)boardSide]; if ((Board.SquareMasks[(int)toSquare] & toSquareMask) > 0) { move = Move.Null; Move.SetPiece(ref move, attacker); Move.SetFrom(ref move, fromSquare); Move.SetTo(ref move, toSquare); Move.SetIsCastling(ref move, true); Move.SetIsKingMove(ref move, true); Moves[MoveIndex] = move; MoveIndex++; } } } } }
private void GeneratePawnMoves(MoveGeneration moveGeneration, ulong fromSquareMask, ulong toSquareMask) { var pawns = GetPawns(ColorToMove) & fromSquareMask; if (pawns == 0) { return; } var pawnMoveMasks = Board.PawnMoveMasks[(int)ColorToMove]; var pawnDoubleMoveMasks = Board.PawnDoubleMoveMasks[(int)ColorToMove]; var pawnAttackMasks = Board.PawnAttackMasks[(int)ColorToMove]; var enemyOccupiedSquares = ColorOccupancy[(int)ColorLastMoved]; var unoccupiedSquares = ~Occupancy; var ranks = Board.Ranks[(int)ColorToMove]; var attacker = PieceHelper.GetPieceOfColor(ColorlessPiece.Pawn, ColorToMove); var queen = PieceHelper.GetPieceOfColor(ColorlessPiece.Queen, ColorToMove); var knight = PieceHelper.GetPieceOfColor(ColorlessPiece.Knight, ColorToMove); var enPassantVictim = PieceHelper.GetPieceOfColor(ColorlessPiece.Pawn, ColorLastMoved); Square fromSquare; ulong move; if ((EnPassantSquare != Square.Illegal) && ((Board.SquareMasks[(int)EnPassantSquare] & toSquareMask) > 0) && (moveGeneration != MoveGeneration.OnlyNonCaptures)) { var enPassantAttackers = Board.EnPassantAttackerMasks[(int)EnPassantSquare] & pawns; while ((fromSquare = Bitwise.PopFirstSetSquare(ref enPassantAttackers)) != Square.Illegal) { // Capture pawn en passant. move = Move.Null; Move.SetPiece(ref move, attacker); Move.SetFrom(ref move, fromSquare); Move.SetTo(ref move, EnPassantSquare); Move.SetCaptureAttacker(ref move, attacker); Move.SetCaptureVictim(ref move, enPassantVictim); Move.SetIsEnPassantCapture(ref move, true); Move.SetIsPawnMove(ref move, true); Moves[MoveIndex] = move; MoveIndex++; } } while ((fromSquare = Bitwise.PopFirstSetSquare(ref pawns)) != Square.Illegal) { ulong pawnDestinations; Square toSquare; int toSquareRank; if (moveGeneration != MoveGeneration.OnlyCaptures) { // Pawns may move forward one square (or two if on initial square) if forward squares are unoccupied. pawnDestinations = pawnMoveMasks[(int)fromSquare] & unoccupiedSquares & toSquareMask; while ((toSquare = Bitwise.PopFirstSetSquare(ref pawnDestinations)) != Square.Illegal) { var doubleMove = Board.SquareDistances[(int)fromSquare][(int)toSquare] == 2; if (doubleMove && ((Occupancy & pawnDoubleMoveMasks[(int)fromSquare]) > 0)) { continue; // Double move is blocked. } toSquareRank = ranks[(int)toSquare]; if (toSquareRank < 7) { move = Move.Null; Move.SetPiece(ref move, attacker); Move.SetFrom(ref move, fromSquare); Move.SetTo(ref move, toSquare); Move.SetIsDoublePawnMove(ref move, doubleMove); Move.SetIsPawnMove(ref move, true); Moves[MoveIndex] = move; MoveIndex++; } else { for (var promotedPiece = queen; promotedPiece >= knight; promotedPiece--) { // Promote pawn. move = Move.Null; Move.SetPiece(ref move, attacker); Move.SetFrom(ref move, fromSquare); Move.SetTo(ref move, toSquare); Move.SetPromotedPiece(ref move, promotedPiece); Move.SetIsPawnMove(ref move, true); Moves[MoveIndex] = move; MoveIndex++; } } } } if (moveGeneration != MoveGeneration.OnlyNonCaptures) { // Pawns may attack diagonally forward one square if occupied by enemy. pawnDestinations = pawnAttackMasks[(int)fromSquare] & enemyOccupiedSquares & toSquareMask; while ((toSquare = Bitwise.PopFirstSetSquare(ref pawnDestinations)) != Square.Illegal) { toSquareRank = ranks[(int)toSquare]; var victim = GetPiece(toSquare); if (toSquareRank < 7) { move = Move.Null; Move.SetPiece(ref move, attacker); Move.SetFrom(ref move, fromSquare); Move.SetTo(ref move, toSquare); Move.SetCaptureAttacker(ref move, attacker); Move.SetCaptureVictim(ref move, victim); Move.SetIsPawnMove(ref move, true); Moves[MoveIndex] = move; MoveIndex++; } else { for (var promotedPiece = queen; promotedPiece >= knight; promotedPiece--) { // Promote pawn. move = Move.Null; Move.SetPiece(ref move, attacker); Move.SetFrom(ref move, fromSquare); Move.SetTo(ref move, toSquare); Move.SetCaptureAttacker(ref move, attacker); Move.SetPromotedPiece(ref move, promotedPiece); Move.SetCaptureVictim(ref move, victim); Move.SetIsPawnMove(ref move, true); Moves[MoveIndex] = move; MoveIndex++; } } } } } }