Пример #1
0
        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);
        }
Пример #2
0
        public static bool HasNonPawnMaterial([NotNull] this GameBoard board, GameSide side)
        {
            if (board is null)
            {
                throw new ArgumentNullException(nameof(board));
            }

            var nonPawnBitboard = board.GetBitboard(side)
                                  & ~board.GetBitboard(side.ToPiece(PieceType.King))
                                  & ~board.GetBitboard(side.ToPiece(PieceType.Pawn));

            return(nonPawnBitboard.IsAny);
        }
Пример #3
0
        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));
        }
Пример #4
0
        private bool IsKingLeftOnly(GameSide side)
        {
            var sideBitboard = PiecePosition[side];
            var kingBitboard = PiecePosition[side.ToPiece(PieceType.King)];
            var otherPieces  = sideBitboard & ~kingBitboard;

            return(otherPieces.IsNone);
        }
Пример #5
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));
                }
            }
        }
Пример #6
0
        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));
        }
Пример #8
0
        private static int EvaluatePawnStructureBySide(GameBoard board, GameSide side, GamePhase gamePhase)
        {
            var pawnPiece = side.ToPiece(PieceType.Pawn);
            var pawns     = board.GetBitboard(pawnPiece);

            if (pawns.IsNone)
            {
                return(0);
            }

            int[] extraPawnPenalties;
            int[] isolatedPawnPenalties;
            if (gamePhase == GamePhase.Endgame)
            {
                extraPawnPenalties    = EndgameExtraPawnPenalties;
                isolatedPawnPenalties = EndgameIsolatedPawnPenalties;
            }
            else
            {
                extraPawnPenalties    = MiddlegameExtraPawnPenalties;
                isolatedPawnPenalties = MiddlegameIsolatedPawnPenalties;
            }

            var result = 0;

            for (var fileIndex = 0; fileIndex < ChessConstants.FileCount; fileIndex++)
            {
                var file        = Bitboards.Files[fileIndex];
                var pawnsOnFile = pawns & file;
                if (pawnsOnFile.IsNone)
                {
                    continue;
                }

                var count = pawnsOnFile.GetSquareCount();

                //// Extra pawns on files (double/triple/etc)
                var extraCount = Math.Max(0, count - 1);
                result -= extraCount * extraPawnPenalties[fileIndex];

                var adjacentFiles      = AdjacentFiles[fileIndex];
                var adjacentFilesPawns = pawns & adjacentFiles;
                if (adjacentFilesPawns.IsNone)
                {
                    //// Isolated pawns on file
                    result -= count * isolatedPawnPenalties[fileIndex];
                }
            }

            return(result);
        }
Пример #9
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);
        }
Пример #10
0
        public void TestToPiece(GameSide side, PieceType pieceType, Piece expectedPiece)
        {
            var piece = side.ToPiece(pieceType);

            Assert.That(piece, Is.EqualTo(expectedPiece));
        }
Пример #11
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);
            }
        }
Пример #12
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);
                }
            }
        }
Пример #13
0
        private Bitboard GetAttackersInternal(
            Square targetSquare,
            GameSide attackingSide,
            bool findFirstAttackOnly)
        {
            var result = new Bitboard();

            var targetBitboard    = targetSquare.Bitboard;
            var targetSquareIndex = targetSquare.SquareIndex;

            var opponentPawns = PiecePosition[attackingSide.ToPiece(PieceType.Pawn)];

            if (opponentPawns.IsAny)
            {
                ShiftDirection left;
                ShiftDirection right;
                if (attackingSide == GameSide.White)
                {
                    left  = ShiftDirection.SouthEast;
                    right = ShiftDirection.SouthWest;
                }
                else
                {
                    left  = ShiftDirection.NorthWest;
                    right = ShiftDirection.NorthEast;
                }

                var attackingPawns = (targetBitboard.Shift(left) | targetBitboard.Shift(right)) & opponentPawns;
                result |= attackingPawns;
                if (findFirstAttackOnly && result.IsAny)
                {
                    return(result);
                }
            }

            var opponentKnights = PiecePosition[attackingSide.ToPiece(PieceType.Knight)];

            if (opponentKnights.IsAny)
            {
                var knightAttacks    = KnightAttacksOrMoves[targetSquareIndex];
                var attackingKnights = knightAttacks & opponentKnights;
                result |= attackingKnights;
                if (findFirstAttackOnly && result.IsAny)
                {
                    return(result);
                }
            }

            var opponentKings = PiecePosition[attackingSide.ToPiece(PieceType.King)];

            if (opponentKings.IsAny)
            {
                var kingAttacks    = KingAttacksOrMoves[targetSquareIndex];
                var attackingKings = kingAttacks & opponentKings;
                result |= attackingKings;
                if (findFirstAttackOnly && result.IsAny)
                {
                    return(result);
                }
            }

            var emptySquareBitboard = PiecePosition[Piece.None];

            var opponentQueens = PiecePosition[attackingSide.ToPiece(PieceType.Queen)];
            var opponentRooks  = PiecePosition[attackingSide.ToPiece(PieceType.Rook)];

            var opponentSlidingStraightPieces = opponentQueens | opponentRooks;
            var slidingStraightAttackers      =
                GetSlidingAttackers(
                    targetSquareIndex,
                    opponentSlidingStraightPieces,
                    StraightSlidingAttacks,
                    emptySquareBitboard,
                    findFirstAttackOnly);

            result |= slidingStraightAttackers;
            if (findFirstAttackOnly && result.IsAny)
            {
                return(result);
            }

            var opponentBishops = PiecePosition[attackingSide.ToPiece(PieceType.Bishop)];

            var opponentSlidingDiagonallyPieces = opponentQueens | opponentBishops;
            var slidingDiagonallyAttackers      =
                GetSlidingAttackers(
                    targetSquareIndex,
                    opponentSlidingDiagonallyPieces,
                    DiagonallySlidingAttacks,
                    emptySquareBitboard,
                    findFirstAttackOnly);

            result |= slidingDiagonallyAttackers;

            return(result);
        }