Esempio n. 1
0
        /// <summary>
        /// Returns whether the given side is attacked on the given square.
        /// </summary>
        /// <param name="colour">The side to test for being attacked.</param>
        /// <param name="square">The square to test for attacks.</param>
        /// <returns>Whether the given side is attacked on the given square</returns>
        public Boolean IsAttacked(Int32 colour, Int32 square)
        {
            Int32 enemy = 1 - colour;

            if ((Bitboard[enemy | Piece.Knight] & Attack.Knight(square)) != 0 ||
                (Bitboard[enemy | Piece.Pawn] & Attack.Pawn(square, colour)) != 0 ||
                (Bitboard[enemy | Piece.King] & Attack.King(square)) != 0)
            {
                return(true);
            }

            UInt64 bishopQueenBitboard = Bitboard[enemy | Piece.Bishop] | Bitboard[enemy | Piece.Queen];

            if ((bishopQueenBitboard & Bit.Diagonals[square]) != 0 &&
                (bishopQueenBitboard & Attack.Bishop(square, OccupiedBitboard)) != 0)
            {
                return(true);
            }

            UInt64 rookQueenBitboard = Bitboard[enemy | Piece.Rook] | Bitboard[enemy | Piece.Queen];

            if ((rookQueenBitboard & Bit.Axes[square]) != 0 &&
                (rookQueenBitboard & Attack.Rook(square, OccupiedBitboard)) != 0)
            {
                return(true);
            }

            return(false);
        }
Esempio n. 2
0
        /// <summary>
        /// Populates the given array with the pseudo-legal capturing and queen
        /// promotion moves for the position and returns the number of moves.
        /// </summary>
        /// <param name="moves">The array to populate with the pseudo-legal moves.</param>
        /// <returns>The number of moves generated for the position.</returns>
        public Int32 PseudoQuiescenceMoves(Int32[] moves)
        {
            UInt64 targetBitboard = Bitboard[(1 - SideToMove)];
            Int32  index          = 0;

            // Consider king moves.
            UInt64 pieceBitboard = Bitboard[SideToMove | Piece.King];
            Int32  from          = Bit.Read(pieceBitboard);
            UInt64 moveBitboard  = targetBitboard & Attack.King(from);

            while (moveBitboard != 0)
            {
                Int32 to = Bit.Pop(ref moveBitboard);
                moves[index++] = Move.Create(this, from, to);
            }


            // Consider queen moves.
            pieceBitboard = Bitboard[SideToMove | Piece.Queen];
            while (pieceBitboard != 0)
            {
                from         = Bit.Pop(ref pieceBitboard);
                moveBitboard = targetBitboard & Attack.Queen(from, OccupiedBitboard);
                while (moveBitboard != 0)
                {
                    Int32 to = Bit.Pop(ref moveBitboard);
                    moves[index++] = Move.Create(this, from, to);
                }
            }

            // Consider rook moves.
            pieceBitboard = Bitboard[SideToMove | Piece.Rook];
            while (pieceBitboard != 0)
            {
                from         = Bit.Pop(ref pieceBitboard);
                moveBitboard = targetBitboard & Attack.Rook(from, OccupiedBitboard);
                while (moveBitboard != 0)
                {
                    Int32 to = Bit.Pop(ref moveBitboard);
                    moves[index++] = Move.Create(this, from, to);
                }
            }

            // Consider knight moves.
            pieceBitboard = Bitboard[SideToMove | Piece.Knight];
            while (pieceBitboard != 0)
            {
                from         = Bit.Pop(ref pieceBitboard);
                moveBitboard = targetBitboard & Attack.Knight(from);
                while (moveBitboard != 0)
                {
                    Int32 to = Bit.Pop(ref moveBitboard);
                    moves[index++] = Move.Create(this, from, to);
                }
            }

            // Consider bishop moves.
            pieceBitboard = Bitboard[SideToMove | Piece.Bishop];
            while (pieceBitboard != 0)
            {
                from         = Bit.Pop(ref pieceBitboard);
                moveBitboard = targetBitboard & Attack.Bishop(from, OccupiedBitboard);
                while (moveBitboard != 0)
                {
                    Int32 to = Bit.Pop(ref moveBitboard);
                    moves[index++] = Move.Create(this, from, to);
                }
            }

            // Consider pawn moves.
            pieceBitboard = Bitboard[SideToMove | Piece.Pawn];
            while (pieceBitboard != 0)
            {
                from         = Bit.Pop(ref pieceBitboard);
                moveBitboard = targetBitboard & Attack.Pawn(from, SideToMove);
                Int32   to        = from + 16 * SideToMove - 8;
                Boolean promotion = (to - 8) * (to - 55) > 0;
                if (promotion)
                {
                    moveBitboard |= ~OccupiedBitboard & (1UL << to);
                }
                while (moveBitboard != 0)
                {
                    to = Bit.Pop(ref moveBitboard);
                    if (promotion)
                    {
                        moves[index++] = Move.Create(this, from, to, SideToMove | Piece.Queen);
                    }
                    else
                    {
                        moves[index++] = Move.Create(this, from, to);
                    }
                }
            }
            return(index);
        }
Esempio n. 3
0
        /// <summary>
        /// Populates the given array with the legal moves for the position and
        /// returns the number of legal moves.
        /// </summary>
        /// <param name="moves">The array to populate with the legal moves.</param>
        /// <returns>The number of legal moves for the position.</returns>
        public Int32 LegalMoves(Int32[] moves)
        {
            // Initialize bitboards and squares that describe the position.
            Int32 enemy      = 1 - SideToMove;
            Int32 kingSquare = Bit.Read(Bitboard[SideToMove | Piece.King]);

            UInt64 selfBitboard   = Bitboard[SideToMove];
            UInt64 enemyBitboard  = Bitboard[enemy];
            UInt64 targetBitboard = ~selfBitboard;

            UInt64 enemyBishopQueenBitboard = Bitboard[enemy | Piece.Bishop] | Bitboard[enemy | Piece.Queen];
            UInt64 enemyRookQueenBitboard   = Bitboard[enemy | Piece.Rook] | Bitboard[enemy | Piece.Queen];

            // Initialize variables for move generation.
            UInt64 checkingBitboard = 0;
            UInt64 pinningBitboard  = 0;
            Int32  index            = 0;

            // Consider knight and pawn checks.
            checkingBitboard |= Bitboard[enemy | Piece.Knight] & Attack.Knight(kingSquare);
            checkingBitboard |= Bitboard[enemy | Piece.Pawn] & Attack.Pawn(kingSquare, SideToMove);

            // Consider bishop and queen checks and pins.
            if ((enemyBishopQueenBitboard & Bit.Diagonals[kingSquare]) != 0)
            {
                checkingBitboard |= enemyBishopQueenBitboard & Attack.Bishop(kingSquare, OccupiedBitboard);

                // Determine pinning pieces by removing the first line of defence around the
                // the king, then seeing which pieces are able to attack.
                UInt64 defenceRemovedBitboard = OccupiedBitboard;
                UInt64 defenceBitboard        = Bit.RayNE[kingSquare] & selfBitboard;
                if (defenceBitboard != 0)
                {
                    defenceRemovedBitboard ^= Bit.IsolateReverse(defenceBitboard);
                }
                defenceBitboard = Bit.RayNW[kingSquare] & selfBitboard;
                if (defenceBitboard != 0)
                {
                    defenceRemovedBitboard ^= Bit.IsolateReverse(defenceBitboard);
                }
                defenceBitboard = Bit.RaySE[kingSquare] & selfBitboard;
                if (defenceBitboard != 0)
                {
                    defenceRemovedBitboard ^= Bit.Isolate(defenceBitboard);
                }
                defenceBitboard = Bit.RaySW[kingSquare] & selfBitboard;
                if (defenceBitboard != 0)
                {
                    defenceRemovedBitboard ^= Bit.Isolate(defenceBitboard);
                }

                if (defenceRemovedBitboard != OccupiedBitboard)
                {
                    pinningBitboard |= enemyBishopQueenBitboard & Attack.Bishop(kingSquare, defenceRemovedBitboard);
                }
            }

            // Consider rook and queen checks and pins.
            if ((enemyRookQueenBitboard & Bit.Axes[kingSquare]) != 0)
            {
                checkingBitboard |= enemyRookQueenBitboard & Attack.Rook(kingSquare, OccupiedBitboard);

                // Determine pinning pieces by removing the first line of defence around the
                // the king, then seeing which pieces are able to attack.
                UInt64 defenceRemovedBitboard = OccupiedBitboard;
                UInt64 defenceBitboard        = Bit.RayN[kingSquare] & selfBitboard;
                if (defenceBitboard != 0)
                {
                    defenceRemovedBitboard ^= Bit.IsolateReverse(defenceBitboard);
                }
                defenceBitboard = Bit.RayE[kingSquare] & selfBitboard;
                if (defenceBitboard != 0)
                {
                    defenceRemovedBitboard ^= Bit.Isolate(defenceBitboard);
                }
                defenceBitboard = Bit.RayS[kingSquare] & selfBitboard;
                if (defenceBitboard != 0)
                {
                    defenceRemovedBitboard ^= Bit.Isolate(defenceBitboard);
                }
                defenceBitboard = Bit.RayW[kingSquare] & selfBitboard;
                if (defenceBitboard != 0)
                {
                    defenceRemovedBitboard ^= Bit.IsolateReverse(defenceBitboard);
                }

                if (defenceRemovedBitboard != OccupiedBitboard)
                {
                    pinningBitboard |= enemyRookQueenBitboard & Attack.Rook(kingSquare, defenceRemovedBitboard);
                }
            }

            // Consider castling. This is always fully tested for legality.
            if (checkingBitboard == 0)
            {
                Int32 rank = -56 * SideToMove + 56;

                if (CastleQueenside[SideToMove] > 0 && (Square[1 + rank] | Square[2 + rank] | Square[3 + rank]) == Piece.Empty)
                {
                    if (!IsAttacked(SideToMove, 3 + rank) && !IsAttacked(SideToMove, 2 + rank))
                    {
                        moves[index++] = Move.Create(this, kingSquare, 2 + rank, SideToMove | Piece.King);
                    }
                }

                if (CastleKingside[SideToMove] > 0 && (Square[5 + rank] | Square[6 + rank]) == Piece.Empty)
                {
                    if (!IsAttacked(SideToMove, 5 + rank) && !IsAttacked(SideToMove, 6 + rank))
                    {
                        moves[index++] = Move.Create(this, kingSquare, 6 + rank, SideToMove | Piece.King);
                    }
                }
            }

            // Consider en passant. This is always fully tested for legality.
            if (EnPassantSquare != InvalidSquare)
            {
                UInt64 enPassantPawnBitboard   = Bitboard[SideToMove | Piece.Pawn] & Attack.Pawn(EnPassantSquare, enemy);
                UInt64 enPassantVictimBitboard = Move.Pawn(EnPassantSquare, enemy);
                while (enPassantPawnBitboard != 0)
                {
                    // Perform minimal state changes to mimick en passant and check for
                    // legality.
                    Int32 from = Bit.Pop(ref enPassantPawnBitboard);
                    Bitboard[enemy | Piece.Pawn] ^= enPassantVictimBitboard;
                    OccupiedBitboard             ^= enPassantVictimBitboard;
                    OccupiedBitboard             ^= (1UL << from) | (1UL << EnPassantSquare);

                    // Check for legality and add move.
                    if (!IsAttacked(SideToMove, kingSquare))
                    {
                        moves[index++] = Move.Create(this, from, EnPassantSquare, enemy | Piece.Pawn);
                    }

                    // Revert state changes.
                    Bitboard[enemy | Piece.Pawn] ^= enPassantVictimBitboard;
                    OccupiedBitboard             ^= enPassantVictimBitboard;
                    OccupiedBitboard             ^= (1UL << from) | (1UL << EnPassantSquare);
                }
            }

            // Consider king moves. This is always fully tested for legality.
            {
                Int32  from         = kingSquare;
                UInt64 moveBitboard = targetBitboard & Attack.King(from);
                while (moveBitboard != 0)
                {
                    // Perform minimal state changes to mimick real move and check for legality.
                    Int32  to = Bit.Pop(ref moveBitboard);
                    UInt64 occupiedBitboardCopy = OccupiedBitboard;
                    Int32  capture = Square[to];
                    Bitboard[capture] ^= 1UL << to;
                    OccupiedBitboard  ^= 1UL << from;
                    OccupiedBitboard  |= 1UL << to;

                    // Check for legality and add move.
                    if (!IsAttacked(SideToMove, to))
                    {
                        moves[index++] = Move.Create(this, from, to);
                    }

                    // Revert state changes.
                    Bitboard[capture] ^= 1UL << to;
                    OccupiedBitboard   = occupiedBitboardCopy;
                }
            }

            // Case 1. If we are not in check and there are no pinned pieces, we don't
            //         need to test normal moves for legality.
            if (checkingBitboard == 0 & pinningBitboard == 0)
            {
                // Consider normal pawn moves.
                UInt64 pieceBitboard = Bitboard[SideToMove | Piece.Pawn];
                while (pieceBitboard != 0)
                {
                    // Consider single square advance.
                    Int32  from         = Bit.Pop(ref pieceBitboard);
                    Int32  to           = from + 16 * SideToMove - 8;
                    UInt64 moveBitboard = ~OccupiedBitboard & (1UL << to);

                    // Consider two square advance.
                    if (moveBitboard != 0 && (from - 16) * (from - 47) > 0 && (to - 8) * (to - 55) < 0)
                    {
                        moveBitboard |= ~OccupiedBitboard & (1UL << (from + 32 * SideToMove - 16));
                    }

                    // Consider captures.
                    UInt64 attackBitboard = Attack.Pawn(from, SideToMove);
                    moveBitboard |= enemyBitboard & attackBitboard;

                    // Populate pawn moves.
                    while (moveBitboard != 0)
                    {
                        to = Bit.Pop(ref moveBitboard);
                        if ((to - 8) * (to - 55) > 0)
                        {
                            moves[index++] = Move.Create(this, from, to, SideToMove | Piece.Queen);
                            moves[index++] = Move.Create(this, from, to, SideToMove | Piece.Knight);
                            moves[index++] = Move.Create(this, from, to, SideToMove | Piece.Rook);
                            moves[index++] = Move.Create(this, from, to, SideToMove | Piece.Bishop);
                        }
                        else
                        {
                            moves[index++] = Move.Create(this, from, to);
                        }
                    }
                }

                // Consider knight moves.
                pieceBitboard = Bitboard[SideToMove | Piece.Knight];
                while (pieceBitboard != 0)
                {
                    Int32  from         = Bit.Pop(ref pieceBitboard);
                    UInt64 moveBitboard = targetBitboard & Attack.Knight(from);
                    while (moveBitboard != 0)
                    {
                        Int32 to = Bit.Pop(ref moveBitboard);
                        moves[index++] = Move.Create(this, from, to);
                    }
                }

                // Consider bishop moves.
                pieceBitboard = Bitboard[SideToMove | Piece.Bishop];
                while (pieceBitboard != 0)
                {
                    Int32  from         = Bit.Pop(ref pieceBitboard);
                    UInt64 moveBitboard = targetBitboard & Attack.Bishop(from, OccupiedBitboard);
                    while (moveBitboard != 0)
                    {
                        Int32 to = Bit.Pop(ref moveBitboard);
                        moves[index++] = Move.Create(this, from, to);
                    }
                }

                // Consider queen moves.
                pieceBitboard = Bitboard[SideToMove | Piece.Queen];
                while (pieceBitboard != 0)
                {
                    Int32  from         = Bit.Pop(ref pieceBitboard);
                    UInt64 moveBitboard = targetBitboard & Attack.Queen(from, OccupiedBitboard);
                    while (moveBitboard != 0)
                    {
                        Int32 to = Bit.Pop(ref moveBitboard);
                        moves[index++] = Move.Create(this, from, to);
                    }
                }

                // Consider rook moves.
                pieceBitboard = Bitboard[SideToMove | Piece.Rook];
                while (pieceBitboard != 0)
                {
                    Int32  from         = Bit.Pop(ref pieceBitboard);
                    UInt64 moveBitboard = targetBitboard & Attack.Rook(from, OccupiedBitboard);
                    while (moveBitboard != 0)
                    {
                        Int32 to = Bit.Pop(ref moveBitboard);
                        moves[index++] = Move.Create(this, from, to);
                    }
                }
            }

            // Case 2. There are pinned pieces or a single check. We can still move but
            //         all moves are tested for legality.
            else if ((checkingBitboard & (checkingBitboard - 1)) == 0)
            {
                // Consider pawn moves.
                UInt64 pieceBitboard = Bitboard[SideToMove | Piece.Pawn];
                while (pieceBitboard != 0)
                {
                    // Consider single square advance.
                    Int32  from         = Bit.Pop(ref pieceBitboard);
                    Int32  to           = from + 16 * SideToMove - 8;
                    UInt64 moveBitboard = ~OccupiedBitboard & (1UL << to);

                    // Consider two square advance.
                    if (moveBitboard != 0 && (from - 16) * (from - 47) > 0 && (to - 8) * (to - 55) < 0)
                    {
                        moveBitboard |= ~OccupiedBitboard & (1UL << (from + 32 * SideToMove - 16));
                    }

                    // Consider captures.
                    UInt64 attackBitboard = Attack.Pawn(from, SideToMove);
                    moveBitboard |= enemyBitboard & attackBitboard;

                    // Populate pawn moves.
                    while (moveBitboard != 0)
                    {
                        // Perform minimal state changes to mimick real move and check for legality.
                        to = Bit.Pop(ref moveBitboard);
                        UInt64 occupiedBitboardCopy = OccupiedBitboard;
                        Int32  capture = Square[to];
                        Bitboard[capture] ^= 1UL << to;
                        OccupiedBitboard  ^= 1UL << from;
                        OccupiedBitboard  |= 1UL << to;

                        // Check for legality and add moves.
                        if (!IsAttacked(SideToMove, kingSquare))
                        {
                            if ((to - 8) * (to - 55) > 0)
                            {
                                moves[index++] = Move.Create(this, from, to, SideToMove | Piece.Queen);
                                moves[index++] = Move.Create(this, from, to, SideToMove | Piece.Knight);
                                moves[index++] = Move.Create(this, from, to, SideToMove | Piece.Rook);
                                moves[index++] = Move.Create(this, from, to, SideToMove | Piece.Bishop);
                            }
                            else
                            {
                                moves[index++] = Move.Create(this, from, to);
                            }
                        }

                        // Revert state changes.
                        Bitboard[capture] ^= 1UL << to;
                        OccupiedBitboard   = occupiedBitboardCopy;
                    }
                }

                // Consider knight moves.
                pieceBitboard = Bitboard[SideToMove | Piece.Knight];
                while (pieceBitboard != 0)
                {
                    Int32  from         = Bit.Pop(ref pieceBitboard);
                    UInt64 moveBitboard = targetBitboard & Attack.Knight(from);
                    while (moveBitboard != 0)
                    {
                        // Perform minimal state changes to mimick real move and check for legality.
                        Int32  to = Bit.Pop(ref moveBitboard);
                        UInt64 occupiedBitboardCopy = OccupiedBitboard;
                        Int32  capture = Square[to];
                        Bitboard[capture] ^= 1UL << to;
                        OccupiedBitboard  ^= 1UL << from;
                        OccupiedBitboard  |= 1UL << to;

                        // Check for legality and add move.
                        if (!IsAttacked(SideToMove, kingSquare))
                        {
                            moves[index++] = Move.Create(this, from, to);
                        }

                        // Revert state changes.
                        Bitboard[capture] ^= 1UL << to;
                        OccupiedBitboard   = occupiedBitboardCopy;
                    }
                }

                // Consider bishop moves.
                pieceBitboard = Bitboard[SideToMove | Piece.Bishop];
                while (pieceBitboard != 0)
                {
                    Int32  from         = Bit.Pop(ref pieceBitboard);
                    UInt64 moveBitboard = targetBitboard & Attack.Bishop(from, OccupiedBitboard);
                    while (moveBitboard != 0)
                    {
                        // Perform minimal state changes to mimick real move and check for legality.
                        Int32  to = Bit.Pop(ref moveBitboard);
                        UInt64 occupiedBitboardCopy = OccupiedBitboard;
                        Int32  capture = Square[to];
                        Bitboard[capture] ^= 1UL << to;
                        OccupiedBitboard  ^= 1UL << from;
                        OccupiedBitboard  |= 1UL << to;

                        // Check for legality and add move.
                        if (!IsAttacked(SideToMove, kingSquare))
                        {
                            moves[index++] = Move.Create(this, from, to);
                        }

                        // Revert state changes.
                        Bitboard[capture] ^= 1UL << to;
                        OccupiedBitboard   = occupiedBitboardCopy;
                    }
                }

                // Consider queen moves.
                pieceBitboard = Bitboard[SideToMove | Piece.Queen];
                while (pieceBitboard != 0)
                {
                    Int32  from         = Bit.Pop(ref pieceBitboard);
                    UInt64 moveBitboard = targetBitboard & Attack.Queen(from, OccupiedBitboard);
                    while (moveBitboard != 0)
                    {
                        // Perform minimal state changes to mimick real move and check for legality.
                        Int32  to = Bit.Pop(ref moveBitboard);
                        UInt64 occupiedBitboardCopy = OccupiedBitboard;
                        Int32  capture = Square[to];
                        Bitboard[capture] ^= 1UL << to;
                        OccupiedBitboard  ^= 1UL << from;
                        OccupiedBitboard  |= 1UL << to;

                        // Check for legality and add move.
                        if (!IsAttacked(SideToMove, kingSquare))
                        {
                            moves[index++] = Move.Create(this, from, to);
                        }

                        // Revert state changes.
                        Bitboard[capture] ^= 1UL << to;
                        OccupiedBitboard   = occupiedBitboardCopy;
                    }
                }

                // Consider rook moves.
                pieceBitboard = Bitboard[SideToMove | Piece.Rook];
                while (pieceBitboard != 0)
                {
                    Int32  from         = Bit.Pop(ref pieceBitboard);
                    UInt64 moveBitboard = targetBitboard & Attack.Rook(from, OccupiedBitboard);
                    while (moveBitboard != 0)
                    {
                        // Perform minimal state changes to mimick real move and check for legality.
                        Int32  to = Bit.Pop(ref moveBitboard);
                        UInt64 occupiedBitboardCopy = OccupiedBitboard;
                        Int32  capture = Square[to];
                        Bitboard[capture] ^= 1UL << to;
                        OccupiedBitboard  ^= 1UL << from;
                        OccupiedBitboard  |= 1UL << to;

                        // Check for legality and add move.
                        if (!IsAttacked(SideToMove, kingSquare))
                        {
                            moves[index++] = Move.Create(this, from, to);
                        }

                        // Revert state changes.
                        Bitboard[capture] ^= 1UL << to;
                        OccupiedBitboard   = occupiedBitboardCopy;
                    }
                }
            }
            return(index);
        }
Esempio n. 4
0
        /// <summary>
        /// Returns the square of the piece with the lowest material value that can
        /// move to the given square.
        /// </summary>
        /// <param name="position">The position to find the square for.</param>
        /// <param name="colour">The side to find the square for.</param>
        /// <param name="square">The square to move to.</param>
        /// <returns>The square of the piece with the lowest material value that can move to the given square.</returns>
        private static Int32 SmallestAttackerSquare(Position position, Int32 colour, Int32 square)
        {
            // Try pawns.
            UInt64 sourceBitboard = position.Bitboard[colour | Piece.Pawn] & Attack.Pawn(square, 1 - colour);

            if (sourceBitboard != 0)
            {
                return(Bit.Scan(sourceBitboard));
            }

            // Try knights.
            sourceBitboard = position.Bitboard[colour | Piece.Knight] & Attack.Knight(square);
            if (sourceBitboard != 0)
            {
                return(Bit.Scan(sourceBitboard));
            }

            // Try bishops.
            UInt64 bishopAttackBitboard = UInt64.MaxValue;

            if ((position.Bitboard[colour | Piece.Bishop] & Bit.Diagonals[square]) != 0)
            {
                bishopAttackBitboard = Attack.Bishop(square, position.OccupiedBitboard);
                sourceBitboard       = position.Bitboard[colour | Piece.Bishop] & bishopAttackBitboard;
                if (sourceBitboard != 0)
                {
                    return(Bit.Scan(sourceBitboard));
                }
            }

            // Try rooks.
            UInt64 rookAttackBitboard = UInt64.MaxValue;

            if ((position.Bitboard[colour | Piece.Rook] & Bit.Axes[square]) != 0)
            {
                rookAttackBitboard = Attack.Rook(square, position.OccupiedBitboard);
                sourceBitboard     = position.Bitboard[colour | Piece.Rook] & rookAttackBitboard;
                if (sourceBitboard != 0)
                {
                    return(Bit.Scan(sourceBitboard));
                }
            }

            // Try queens.
            if ((position.Bitboard[colour | Piece.Queen] & (Bit.Diagonals[square] | Bit.Axes[square])) != 0)
            {
                if (bishopAttackBitboard == UInt64.MaxValue)
                {
                    bishopAttackBitboard = Attack.Bishop(square, position.OccupiedBitboard);
                }
                if (rookAttackBitboard == UInt64.MaxValue)
                {
                    rookAttackBitboard = Attack.Rook(square, position.OccupiedBitboard);
                }

                sourceBitboard = position.Bitboard[colour | Piece.Queen] & (bishopAttackBitboard | rookAttackBitboard);
                if (sourceBitboard != 0)
                {
                    return(Bit.Scan(sourceBitboard));
                }
            }

            // Try king.
            sourceBitboard = position.Bitboard[colour | Piece.King] & Attack.King(square);
            if (sourceBitboard != 0)
            {
                return(Bit.Read(sourceBitboard));
            }

            return(Position.InvalidSquare);
        }
Esempio n. 5
0
        /// <summary>
        /// Returns the estimated value of the given position as determined by static
        /// analysis.
        /// </summary>
        /// <param name="position">The position to evaluate.</param>
        /// <returns>The estimated value of the position.</returns>
        private Int32 Evaluate(Position position)
        {
            UInt64[] bitboard = position.Bitboard;
            Single   opening  = PhaseCoefficient * Math.Min(position.Material[Colour.White], position.Material[Colour.Black]);
            Single   endgame  = 1 - opening;

            _pawnAttackBitboard[Colour.White] = (bitboard[Colour.White | Piece.Pawn] & NotAFileBitboard) >> 9
                                                | (bitboard[Colour.White | Piece.Pawn] & NotHFileBitboard) >> 7;
            _pawnAttackBitboard[Colour.Black] = (bitboard[Colour.Black | Piece.Pawn] & NotAFileBitboard) << 7
                                                | (bitboard[Colour.Black | Piece.Pawn] & NotHFileBitboard) << 9;
            Single totalValue = TempoValue;

            // Evaluate symmetric features (material, position, etc).
            for (Int32 colour = Colour.White; colour <= Colour.Black; colour++)
            {
                UInt64 targetBitboard    = ~bitboard[colour] & ~_pawnAttackBitboard[1 - colour];
                UInt64 pawnBitboard      = bitboard[colour | Piece.Pawn];
                UInt64 enemyPawnBitboard = bitboard[(1 - colour) | Piece.Pawn];
                UInt64 allPawnBitboard   = pawnBitboard | enemyPawnBitboard;
                Int32  enemyKingSquare   = Bit.Read(bitboard[(1 - colour) | Piece.King]);
                Single value             = position.Material[colour];

                // Evaluate king.
                Int32 square = Bit.Read(bitboard[colour | Piece.King]);
                value += opening * KingOpeningPositionValue[colour][square] + endgame * KingEndgamePositionValue[colour][square];
                value += opening * PawnNearKingValue * Bit.Count(PawnShieldBitboard[square] & pawnBitboard);

                if ((allPawnBitboard & Bit.File[square]) == 0)
                {
                    value += opening * KingOnOpenFileValue;
                }

                if (Position.File(square) > 0 && (allPawnBitboard & Bit.File[square - 1]) == 0)
                {
                    value += opening * KingAdjacentToOpenFileValue;
                }

                if (Position.File(square) < 7 && (allPawnBitboard & Bit.File[square + 1]) == 0)
                {
                    value += opening * KingAdjacentToOpenFileValue;
                }

                // Evaluate bishops.
                UInt64 pieceBitboard = bitboard[colour | Piece.Bishop];
                _minorAttackBitboard[colour] = 0;

                if ((pieceBitboard & (pieceBitboard - 1)) != 0)
                {
                    value += BishopPairValue;
                }

                while (pieceBitboard != 0)
                {
                    square = Bit.Pop(ref pieceBitboard);
                    value += BishopPositionValue[colour][square];

                    UInt64 pseudoMoveBitboard = Attack.Bishop(square, position.OccupiedBitboard);
                    value += BishopMobilityValue[Bit.Count(targetBitboard & pseudoMoveBitboard)];
                    _minorAttackBitboard[colour] |= pseudoMoveBitboard;
                }

                // Evaluate knights.
                pieceBitboard = bitboard[colour | Piece.Knight];
                while (pieceBitboard != 0)
                {
                    square = Bit.Pop(ref pieceBitboard);
                    value += opening * KnightOpeningPositionValue[colour][square];
                    value += endgame * KnightToEnemyKingSpatialValue[square][enemyKingSquare];

                    UInt64 pseudoMoveBitboard = Attack.Knight(square);
                    value += KnightMobilityValue[Bit.Count(targetBitboard & pseudoMoveBitboard)];
                    _minorAttackBitboard[colour] |= pseudoMoveBitboard;
                }

                // Evaluate queens.
                pieceBitboard = bitboard[colour | Piece.Queen];
                while (pieceBitboard != 0)
                {
                    square = Bit.Pop(ref pieceBitboard);
                    value += opening * QueenOpeningPositionValue[colour][square];
                    value += endgame * QueenToEnemyKingSpatialValue[square][enemyKingSquare];
                }

                // Evaluate rooks.
                pieceBitboard = bitboard[colour | Piece.Rook];
                while (pieceBitboard != 0)
                {
                    square = Bit.Pop(ref pieceBitboard);
                    value += RookPositionValue[colour][square];
                }

                // Evaluate pawns.
                Int32 pawns = 0;
                pieceBitboard = bitboard[colour | Piece.Pawn];
                while (pieceBitboard != 0)
                {
                    square = Bit.Pop(ref pieceBitboard);
                    value += PawnPositionValue[colour][square];
                    pawns++;

                    if ((ShortForwardFileBitboard[colour][square] & pawnBitboard) != 0)
                    {
                        value += DoubledPawnValue;
                    }

                    else if ((PawnBlockadeBitboard[colour][square] & enemyPawnBitboard) == 0)
                    {
                        value += PassedPawnValue + endgame * PassedPawnEndgamePositionValue[colour][square];
                    }

                    if ((ShortAdjacentFilesBitboard[square] & pawnBitboard) == 0)
                    {
                        value += IsolatedPawnValue;
                    }
                }
                value += (pawns == 0) ? PawnDeficiencyValue : pawns * endgame * PawnEndgameGainValue;

                // Evaluate pawn threat to enemy minor pieces.
                UInt64 victimBitboard = bitboard[(1 - colour)] ^ enemyPawnBitboard;
                value += PawnAttackValue * Bit.CountSparse(_pawnAttackBitboard[colour] & victimBitboard);

                // Evaluate pawn defence to friendly minor pieces.
                UInt64 lowValueBitboard = bitboard[colour | Piece.Bishop] | bitboard[colour | Piece.Knight] | bitboard[colour | Piece.Pawn];
                value += PawnDefenceValue * Bit.Count(_pawnAttackBitboard[colour] & lowValueBitboard);

                if (colour == position.SideToMove)
                {
                    totalValue += value;
                }
                else
                {
                    totalValue -= value;
                }
            }

            // Evaluate asymetric features (immediate captures).
            {
                Int32 colour = position.SideToMove;

                // Pawn takes queen.
                if ((_pawnAttackBitboard[colour] & bitboard[(1 - colour) | Piece.Queen]) != 0)
                {
                    totalValue += PieceValue[Piece.Queen] - PieceValue[Piece.Pawn];
                }

                // Minor takes queen.
                else if ((_minorAttackBitboard[colour] & bitboard[(1 - colour) | Piece.Queen]) != 0)
                {
                    totalValue += PieceValue[Piece.Queen] - PieceValue[Piece.Bishop];
                }

                // Pawn takes rook.
                else if ((_pawnAttackBitboard[colour] & bitboard[(1 - colour) | Piece.Rook]) != 0)
                {
                    totalValue += PieceValue[Piece.Rook] - PieceValue[Piece.Pawn];
                }

                // Pawn takes bishop.
                else if ((_pawnAttackBitboard[colour] & bitboard[(1 - colour) | Piece.Bishop]) != 0)
                {
                    totalValue += PieceValue[Piece.Bishop] - PieceValue[Piece.Pawn];
                }

                // Pawn takes knight.
                else if ((_pawnAttackBitboard[colour] & bitboard[(1 - colour) | Piece.Knight]) != 0)
                {
                    totalValue += PieceValue[Piece.Knight] - PieceValue[Piece.Pawn];
                }

                // Minor takes rook.
                else if ((_minorAttackBitboard[colour] & bitboard[(1 - colour) | Piece.Rook]) != 0)
                {
                    totalValue += PieceValue[Piece.Rook] - PieceValue[Piece.Bishop];
                }
            }

            return((Int32)totalValue);
        }