public Bitboard[] GetPinLimitations(int valuablePieceSquareIndex, GameSide attackingSide) { var result = DefaultPinLimitations.Copy(); var enemyPieces = PiecePosition[attackingSide]; var ownPieces = PiecePosition[attackingSide.Invert()]; var queens = PiecePosition[attackingSide.ToPiece(PieceType.Queen)]; var bishops = PiecePosition[attackingSide.ToPiece(PieceType.Bishop)]; var rooks = PiecePosition[attackingSide.ToPiece(PieceType.Rook)]; PopulatePinLimitations( result, enemyPieces, valuablePieceSquareIndex, ownPieces, DiagonallySlidingAttacks, queens | bishops); PopulatePinLimitations( result, enemyPieces, valuablePieceSquareIndex, ownPieces, StraightSlidingAttacks, queens | rooks); return(result); }
public bool IsInCheck(GameSide side) { var king = side.ToPiece(PieceType.King); var oppositeSide = side.Invert(); var kingSquares = PiecePosition[king].GetSquares(); return(kingSquares.Length != 0 && IsAnyUnderAttack(kingSquares, oppositeSide)); }
protected void GeneratePotentialKingMoves( [NotNull] ICollection <GameMoveData2> resultMoves, GameSide side, GeneratedMoveTypes moveTypes, Bitboard target, CastlingOptions allowedCastlingOptions) { if (resultMoves is null) { throw new ArgumentNullException(nameof(resultMoves)); } var kingPiece = side.ToPiece(PieceType.King); var kings = PiecePosition[kingPiece]; while (kings.IsAny) { var kingSquareIndex = Bitboard.PopFirstSquareIndex(ref kings); var sourceSquare = new Square(kingSquareIndex); var moves = KingAttacksOrMoves[kingSquareIndex]; var movesOnTarget = moves & target; if (moveTypes.IsAnySet(GeneratedMoveTypes.Capture)) { var enemies = PiecePosition[side.Invert()]; var captures = movesOnTarget & enemies; PopulateSimpleMoves(resultMoves, sourceSquare, captures, GameMoveFlags.IsRegularCapture); } //// ReSharper disable once InvertIf if (moveTypes.IsAnySet(GeneratedMoveTypes.Quiet)) { var emptySquares = PiecePosition[Piece.None]; var nonCaptures = movesOnTarget & emptySquares; PopulateSimpleMoves(resultMoves, sourceSquare, nonCaptures, GameMoveFlags.None); var nonEmptySquares = ~emptySquares; PopulateKingCastlingMoves( resultMoves, sourceSquare, target, allowedCastlingOptions, nonEmptySquares, CastlingSide.KingSide.ToCastlingType(side)); PopulateKingCastlingMoves( resultMoves, sourceSquare, target, allowedCastlingOptions, nonEmptySquares, CastlingSide.QueenSide.ToCastlingType(side)); } } }
private void GenerateSlidingPieceMoves( [NotNull] ICollection <GameMoveData2> resultMoves, GameSide side, GeneratedMoveTypes moveTypes, PieceType pieceType, [NotNull] ShiftDirection[] directions) { var piece = pieceType.ToPiece(side); var pieces = PiecePosition[piece]; var emptySquares = PiecePosition[Piece.None]; var enemies = PiecePosition[side.Invert()]; var shouldGenerateQuiets = moveTypes.IsAnySet(GeneratedMoveTypes.Quiet); var shouldGenerateCaptures = moveTypes.IsAnySet(GeneratedMoveTypes.Capture); //// TODO [HarinezumiSama] NEW-DESIGN: IDEA: Generate for all pieces rather for one by one while (pieces.IsAny) { var sourceSquareIndex = Bitboard.PopFirstSquareIndex(ref pieces); var sourceBitboard = Bitboard.FromSquareIndex(sourceSquareIndex); var sourceSquare = new Square(sourceSquareIndex); foreach (var direction in directions) { var current = sourceBitboard; while ((current = current.Shift(direction)).IsAny) { if ((current & emptySquares).IsAny) { if (shouldGenerateQuiets) { var move = new GameMove2(sourceSquare, current.GetFirstSquare()); resultMoves.Add(new GameMoveData2(move, GameMoveFlags.None)); } continue; } if ((current & enemies).IsAny) { if (shouldGenerateCaptures) { var move = new GameMove2(sourceSquare, current.GetFirstSquare()); resultMoves.Add( new GameMoveData2(move, GameMoveFlags.IsRegularCapture)); } } break; } } } }
public void GenerateKingMoves( [NotNull] ICollection <GameMoveData> resultMoves, GameSide side, CastlingOptions allowedCastlingOptions, Bitboard target) { if (resultMoves is null) { throw new ArgumentNullException(nameof(resultMoves)); } var kingPiece = side.ToPiece(PieceType.King); var king = PiecePosition[kingPiece]; if (king.IsNone) { return; } if (!king.IsExactlyOneSquare()) { throw new ChessPlatformException( $@"There are multiple {kingPiece.GetDescription()} pieces ({king.GetSquareCount()}) on the board."); } var kingSquareIndex = king.FindFirstSquareIndex(); var sourceSquare = new Square(kingSquareIndex); var directTargets = KingAttacksOrMoves[kingSquareIndex] & target; var emptySquares = PiecePosition[Piece.None]; var nonCaptures = directTargets & emptySquares; PopulateSimpleMoves(resultMoves, sourceSquare, nonCaptures, GameMoveFlags.None); var enemies = PiecePosition[side.Invert()]; var captures = directTargets & enemies; PopulateSimpleMoves(resultMoves, sourceSquare, captures, GameMoveFlags.IsRegularCapture); var nonEmptySquares = ~emptySquares; PopulateKingCastlingMoves( resultMoves, sourceSquare, allowedCastlingOptions, nonEmptySquares, CastlingSide.KingSide.ToCastlingType(side)); PopulateKingCastlingMoves( resultMoves, sourceSquare, allowedCastlingOptions, nonEmptySquares, CastlingSide.QueenSide.ToCastlingType(side)); }
public static bool IsInCheck([NotNull] this GamePosition gamePosition, GameSide side) { if (gamePosition is null) { throw new ArgumentNullException(nameof(gamePosition)); } var king = side.ToPiece(PieceType.King); var attackingSide = side.Invert(); var kingSquares = gamePosition.PiecePosition[king].GetSquares(); return(gamePosition.IsAnyUnderAttack(kingSquares, attackingSide)); }
private static int EvaluateKingTropism([NotNull] GameBoard board, GameSide kingSide) { var king = kingSide.ToPiece(PieceType.King); var kingSquare = board.GetBitboard(king).GetFirstSquare(); var allAttackersBitboard = board.GetBitboard(kingSide.Invert()); var result = 0; var remainingAttackers = allAttackersBitboard; int attackerSquareIndex; while ((attackerSquareIndex = Bitboard.PopFirstSquareIndex(ref remainingAttackers)) >= 0) { var attackerSquare = new Square(attackerSquareIndex); var score = GetKingTropismScore(board, attackerSquare, kingSquare); result -= score; } return(result / KingTropismRelativeFactor); }
protected void GeneratePotentialPawnMoves( [NotNull] ICollection <GameMoveData2> resultMoves, GameSide side, GeneratedMoveTypes moveTypes, Bitboard target, Bitboard enPassantCaptureTarget) { if (resultMoves is null) { throw new ArgumentNullException(nameof(resultMoves)); } var pawnPiece = side.ToPiece(PieceType.Pawn); var pawns = PiecePosition[pawnPiece]; if (pawns.IsNone) { return; } var rank8 = side == GameSide.White ? Bitboards.Rank8 : Bitboards.Rank1; if (moveTypes.IsAnySet(GeneratedMoveTypes.Quiet)) { var forwardDirection = side == GameSide.White ? ShiftDirection.North : ShiftDirection.South; var emptySquares = PiecePosition[Piece.None]; var pushes = pawns.Shift(forwardDirection) & emptySquares; var targetPushes = pushes & target; if (targetPushes.IsAny) { var nonPromotionPushes = targetPushes & ~rank8; PopulatePawnMoves(resultMoves, nonPromotionPushes, (int)forwardDirection, GameMoveFlags.None); var promotionPushes = targetPushes & rank8; PopulatePawnMoves( resultMoves, promotionPushes, (int)forwardDirection, GameMoveFlags.IsPawnPromotion); } if (pushes.IsAny) { var rank3 = side == GameSide.White ? Bitboards.Rank3 : Bitboards.Rank6; var doublePushes = (pushes & rank3).Shift(forwardDirection) & emptySquares & target; PopulatePawnMoves( resultMoves, doublePushes, (int)forwardDirection << 1, GameMoveFlags.None); } } //// ReSharper disable once InvertIf if (moveTypes.IsAnySet(GeneratedMoveTypes.Capture)) { var enemies = PiecePosition[side.Invert()]; var enemyTargets = enemies & target; var leftCaptureOffset = side == GameSide.White ? ShiftDirection.NorthWest : ShiftDirection.SouthEast; PopulatePawnCaptures(resultMoves, pawns, enemyTargets, leftCaptureOffset, rank8, enPassantCaptureTarget); var rightCaptureOffset = side == GameSide.White ? ShiftDirection.NorthEast : ShiftDirection.SouthWest; PopulatePawnCaptures(resultMoves, pawns, enemyTargets, rightCaptureOffset, rank8, enPassantCaptureTarget); } }
protected void GeneratePotentialKnightMoves( [NotNull] ICollection <GameMoveData2> resultMoves, GameSide side, GeneratedMoveTypes moveTypes, Bitboard target) { if (resultMoves is null) { throw new ArgumentNullException(nameof(resultMoves)); } var emptySquares = PiecePosition[Piece.None]; var enemies = PiecePosition[side.Invert()]; var internalTarget = Bitboard.None; if (moveTypes.IsAnySet(GeneratedMoveTypes.Quiet)) { internalTarget |= emptySquares; } if (moveTypes.IsAnySet(GeneratedMoveTypes.Capture)) { internalTarget |= enemies; } var actualTarget = target & internalTarget; if (actualTarget.IsNone) { return; } var knightPiece = side.ToPiece(PieceType.Knight); var knights = PiecePosition[knightPiece]; while (knights.IsAny) { var sourceSquareIndex = Bitboard.PopFirstSquareIndex(ref knights); var moves = KnightAttacksOrMoves[sourceSquareIndex]; var movesOnTarget = moves & actualTarget; if (movesOnTarget.IsNone) { continue; } var sourceSquare = new Square(sourceSquareIndex); if (moveTypes.IsAnySet(GeneratedMoveTypes.Capture)) { var captures = movesOnTarget & enemies; PopulateSimpleMoves(resultMoves, sourceSquare, captures, GameMoveFlags.IsRegularCapture); } //// ReSharper disable once InvertIf if (moveTypes.IsAnySet(GeneratedMoveTypes.Quiet)) { var nonCaptures = movesOnTarget & emptySquares; PopulateSimpleMoves(resultMoves, sourceSquare, nonCaptures, GameMoveFlags.None); } } }
internal MakeMoveData MakeMove( [NotNull] GameMove move, GameSide movingSide, [CanBeNull] EnPassantCaptureInfo enPassantCaptureInfo, ref CastlingOptions castlingOptions) { if (move is null) { throw new ArgumentNullException(nameof(move)); } var piece = PiecePosition[move.From]; if (piece == Piece.None || piece.GetSide() != movingSide) { throw new ArgumentException($@"Invalid move '{move}' in the position.", nameof(move)); } GameMove castlingRookMove = null; Square? enPassantCapturedPieceSquare = null; var movingSideAllCastlingOptions = ChessHelper.GameSideToCastlingOptionsMap[movingSide]; // Performing checks before actual move! var castlingInfo = CheckCastlingMove(move); var isEnPassantCapture = IsEnPassantCapture(move.From, move.To, enPassantCaptureInfo); var isPawnPromotion = IsPawnPromotion(move.From, move.To); var moveData = MovePieceInternal(move); var capturedPiece = moveData.CapturedPiece; if (isEnPassantCapture) { if (enPassantCaptureInfo is null) { throw ChessPlatformException.CreateInconsistentStateError(); } enPassantCapturedPieceSquare = enPassantCaptureInfo.TargetPieceSquare; capturedPiece = PiecePosition.SetPiece(enPassantCaptureInfo.TargetPieceSquare, Piece.None); if (capturedPiece.GetPieceType() != PieceType.Pawn) { throw ChessPlatformException.CreateInconsistentStateError(); } } else if (isPawnPromotion) { if (move.PromotionResult == PieceType.None) { throw new ChessPlatformException($@"Promoted piece type is not specified ({move})."); } var previousPiece = PiecePosition.SetPiece(move.To, move.PromotionResult.ToPiece(movingSide)); if (previousPiece.GetPieceType() != PieceType.Pawn) { throw ChessPlatformException.CreateInconsistentStateError(); } } else if (castlingInfo != null) { if (!castlingOptions.IsAllSet(castlingInfo.Option)) { throw new ChessPlatformException( $@"The castling {{{move}}} ({castlingInfo.CastlingType.GetName()}) is not allowed."); } castlingRookMove = castlingInfo.RookMove; var rookMoveData = MovePieceInternal(castlingRookMove); if (rookMoveData.CapturedPiece != Piece.None) { throw ChessPlatformException.CreateInconsistentStateError(); } castlingOptions &= ~movingSideAllCastlingOptions; } var movingSideCurrentCastlingOptions = castlingOptions & movingSideAllCastlingOptions; if (movingSideCurrentCastlingOptions != CastlingOptions.None) { switch (piece.GetPieceType()) { case PieceType.King: castlingOptions &= ~movingSideAllCastlingOptions; break; case PieceType.Rook: { var castlingInfoByRook = ChessConstants.AllCastlingInfos.SingleOrDefault(obj => obj.RookMove.From == move.From); if (castlingInfoByRook != null) { castlingOptions &= ~castlingInfoByRook.Option; } } break; } } var oppositeSide = movingSide.Invert(); var oppositeSideAllCastlingOptions = ChessHelper.GameSideToCastlingOptionsMap[oppositeSide]; var oppositeSideCurrentCastlingOptions = castlingOptions & oppositeSideAllCastlingOptions; if (oppositeSideCurrentCastlingOptions != CastlingOptions.None && capturedPiece.GetPieceType() == PieceType.Rook) { var oppositeCastlingInfo = ChessConstants.AllCastlingInfos.SingleOrDefault(obj => obj.RookMove.From == move.To); if (oppositeCastlingInfo != null) { castlingOptions &= ~oppositeCastlingInfo.Option; } } var undoMoveData = new MakeMoveData( move, moveData.MovedPiece, capturedPiece, castlingRookMove, enPassantCapturedPieceSquare); _undoMoveDatas.Push(undoMoveData); PiecePosition.EnsureConsistency(); return(undoMoveData); }