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));
        }
示例#3
0
        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));
                }
            }
        }
示例#4
0
        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));
        }
示例#7
0
        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);
        }
示例#8
0
        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);
            }
        }
示例#9
0
        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);
        }