Пример #1
0
        internal void CreateCheckInfo(Position pos)
        {
            Color them = pos.sideToMove ^ 1;
            ksq = pos.pieceList[them][PieceTypeC.KING][0];

            pinned = pos.pinned_pieces();
            dcCandidates = pos.discovered_check_candidates();

            checkSq[PieceTypeC.PAWN] = Utils.StepAttacksBB[((them << 3) | PieceTypeC.PAWN)][ksq];
            checkSq[PieceTypeC.KNIGHT] = Utils.StepAttacksBB_KNIGHT[ksq];
#if X64
            checkSq[PieceTypeC.BISHOP] = Utils.BAttacks[ksq][(((pos.occupied_squares & Utils.BMasks[ksq]) * Utils.BMagics[ksq]) >> Utils.BShifts[ksq])];
            checkSq[PieceTypeC.ROOK] = Utils.RAttacks[ksq][(((pos.occupied_squares & Utils.RMasks[ksq]) * Utils.RMagics[ksq]) >> Utils.RShifts[ksq])];
#else
            checkSq[PieceTypeC.BISHOP] = pos.attacks_from_BISHOP(ksq);
            checkSq[PieceTypeC.ROOK] = pos.attacks_from_ROOK(ksq);
#endif
            checkSq[PieceTypeC.QUEEN] = checkSq[PieceTypeC.BISHOP] | checkSq[PieceTypeC.ROOK];
            checkSq[PieceTypeC.KING] = 0;
        }
Пример #2
0
        // evaluate_king<>() assigns bonuses and penalties to a king of a given color
        private static int evaluate_king(
            int Us,
            bool Trace,
            Position pos,
            EvalInfo ei,
            ref Value marginsWHITE,
            ref Value marginsBLACK)
        {
            var Them = (Us == ColorC.WHITE ? ColorC.BLACK : ColorC.WHITE);

            ulong undefended, b, b1, b2, safe;
            int attackUnits;
            int kingScore;
            var ksq = pos.pieceList[Us][PieceTypeC.KING][0];

            // King shelter and enemy pawns storm
            var score = ei.pi.king_safety(Us, pos, ksq);

            // King safety. This is quite complicated, and is almost certainly far
            // from optimally tuned.
            if (ei.kingAttackersCount[Them] >= 2 && (ei.kingAdjacentZoneAttacksCount[Them] != 0))
            {
                // Find the attacked squares around the king which has no defenders
                // apart from the king itself
                undefended = ei.attackedBy[Them][0] & ei.attackedBy[Us][PieceTypeC.KING];
                undefended &=
                    ~(ei.attackedBy[Us][PieceTypeC.PAWN] | ei.attackedBy[Us][PieceTypeC.KNIGHT]
                      | ei.attackedBy[Us][PieceTypeC.BISHOP] | ei.attackedBy[Us][PieceTypeC.ROOK]
                      | ei.attackedBy[Us][PieceTypeC.QUEEN]);

#if X64
    // Initialize the 'attackUnits' variable, which is used later on as an
    // index to the KingDangerTable[] array. The initial value is based on
    // the number and types of the enemy's attacking pieces, the number of
    // attacked and undefended squares around our king, the square of the
    // king, and the quality of the pawn shelter.
                b = undefended - ((undefended >> 1) & 0x5555555555555555UL);
                b = ((b >> 2) & 0x3333333333333333UL) + (b & 0x3333333333333333UL);
                attackUnits = Math.Min(25, (ei.kingAttackersCount[Them] * ei.kingAttackersWeight[Them]) / 2)
                             + 3 * (ei.kingAdjacentZoneAttacksCount[Them] + ((int)((b * 0x1111111111111111UL) >> 60)))
                             + InitKingDanger[(ksq ^ (Us * 56))]
                             - ((((score) + 32768) & ~0xffff) / 0x10000) / 32;

                // Analyse enemy's safe queen contact checks. First find undefended
                // squares around the king attacked by enemy queen...
                b = undefended & ei.attackedBy[Them][PieceTypeC.QUEEN] & ~(pos.byColorBB[Them]);
                if (b != 0)
                {
                    // ...then remove squares not supported by another enemy piece
                    b &= (ei.attackedBy[Them][PieceTypeC.PAWN] | ei.attackedBy[Them][PieceTypeC.KNIGHT]
                          | ei.attackedBy[Them][PieceTypeC.BISHOP] | ei.attackedBy[Them][PieceTypeC.ROOK]);
                    if (b != 0)
                    {
                        b -= (b >> 1) & 0x5555555555555555UL;
                        b = ((b >> 2) & 0x3333333333333333UL) + (b & 0x3333333333333333UL);
                        attackUnits += QueenContactCheckBonus
                                      * ((int)((b * 0x1111111111111111UL) >> 60))
                                      * (Them == pos.sideToMove ? 2 : 1);
                    }
                }

                // Analyse enemy's safe rook contact checks. First find undefended
                // squares around the king attacked by enemy rooks...
                b = undefended & ei.attackedBy[Them][PieceTypeC.ROOK] & ~pos.byColorBB[Them];

                // Consider only squares where the enemy rook gives check
                b &= Utils.PseudoAttacks_ROOK[ksq];

                if (b != 0)
                {
                    // ...then remove squares not supported by another enemy piece
                    b &= (ei.attackedBy[Them][PieceTypeC.PAWN] | ei.attackedBy[Them][PieceTypeC.KNIGHT]
                          | ei.attackedBy[Them][PieceTypeC.BISHOP] | ei.attackedBy[Them][PieceTypeC.QUEEN]);
                    if (b != 0)
                    {
                        b -= (b >> 1) & 0x5555555555555555UL;
                        b = ((b >> 2) & 0x3333333333333333UL) + (b & 0x3333333333333333UL);
                        attackUnits += RookContactCheckBonus
                                      * ((int)((b * 0x1111111111111111UL) >> 60))
                                      * (Them == pos.sideToMove ? 2 : 1);
                    }
                }

                // Analyse enemy's safe distance checks for sliders and knights
                safe = ~(pos.byColorBB[Them] | ei.attackedBy[Us][0]);

                b1 = (Utils.RAttacks[ksq][(((pos.occupied_squares & Utils.RMasks[ksq]) * Utils.RMagics[ksq]) >> Utils.RShifts[ksq])]) & safe;
                b2 = (Utils.BAttacks[ksq][(((pos.occupied_squares & Utils.BMasks[ksq]) * Utils.BMagics[ksq]) >> Utils.BShifts[ksq])]) & safe;

                // Enemy queen safe checks
                b = (b1 | b2) & ei.attackedBy[Them][PieceTypeC.QUEEN];
                if (b != 0)
                {
                    b -= (b >> 1) & 0x5555555555555555UL;
                    b = ((b >> 2) & 0x3333333333333333UL) + (b & 0x3333333333333333UL);
                    attackUnits += QueenCheckBonus * ((int)((b * 0x1111111111111111UL) >> 60));
                }

                // Enemy rooks safe checks
                b = b1 & ei.attackedBy[Them][PieceTypeC.ROOK];
                if (b != 0)
                {
                    b -= (b >> 1) & 0x5555555555555555UL;
                    b = ((b >> 2) & 0x3333333333333333UL) + (b & 0x3333333333333333UL);
                    attackUnits += RookCheckBonus * ((int)((b * 0x1111111111111111UL) >> 60));
                }

                // Enemy bishops safe checks
                b = b2 & ei.attackedBy[Them][PieceTypeC.BISHOP];
                if (b != 0)
                {
                    b -= (b >> 1) & 0x5555555555555555UL;
                    b = ((b >> 2) & 0x3333333333333333UL) + (b & 0x3333333333333333UL);
                    attackUnits += BishopCheckBonus * ((int)((b * 0x1111111111111111UL) >> 60));
                }

                // Enemy knights safe checks
                b = Utils.StepAttacksBB_KNIGHT[ksq] & ei.attackedBy[Them][PieceTypeC.KNIGHT] & safe;
                if (b != 0)
                {
                    b -= (b >> 1) & 0x5555555555555555UL;
                    b = ((b >> 2) & 0x3333333333333333UL) + (b & 0x3333333333333333UL);
                    attackUnits += KnightCheckBonus * ((int)((b * 0x1111111111111111UL) >> 60));
                }
#else
                // Initialize the 'attackUnits' variable, which is used later on as an
                // index to the KingDangerTable[] array. The initial value is based on
                // the number and types of the enemy's attacking pieces, the number of
                // attacked and undefended squares around our king, the square of the
                // king, and the quality of the pawn shelter.
                attackUnits = Math.Min(25, (ei.kingAttackersCount[Them] * ei.kingAttackersWeight[Them]) / 2)
                              + 3 * (ei.kingAdjacentZoneAttacksCount[Them] + Bitcount.popcount_1s_Max15(undefended))
                              + InitKingDanger[(ksq ^ (Us * 56))] - ((((score) + 32768) & ~0xffff) / 0x10000) / 32;

                // Analyse enemy's safe queen contact checks. First find undefended
                // squares around the king attacked by enemy queen...
                b = undefended & ei.attackedBy[Them][PieceTypeC.QUEEN] & ~(pos.byColorBB[Them]);
                if (b != 0)
                {
                    // ...then remove squares not supported by another enemy piece
                    b &= (ei.attackedBy[Them][PieceTypeC.PAWN] | ei.attackedBy[Them][PieceTypeC.KNIGHT]
                          | ei.attackedBy[Them][PieceTypeC.BISHOP] | ei.attackedBy[Them][PieceTypeC.ROOK]);
                    if (b != 0)
                    {
                        attackUnits += QueenContactCheckBonus * Bitcount.popcount_1s_Max15(b)
                                       * (Them == pos.sideToMove ? 2 : 1);
                    }
                }

                // Analyse enemy's safe rook contact checks. First find undefended
                // squares around the king attacked by enemy rooks...
                b = undefended & ei.attackedBy[Them][PieceTypeC.ROOK] & ~pos.byColorBB[Them];

                // Consider only squares where the enemy rook gives check
                b &= Utils.PseudoAttacks_ROOK[ksq];

                if (b != 0)
                {
                    // ...then remove squares not supported by another enemy piece
                    b &= (ei.attackedBy[Them][PieceTypeC.PAWN] | ei.attackedBy[Them][PieceTypeC.KNIGHT]
                          | ei.attackedBy[Them][PieceTypeC.BISHOP] | ei.attackedBy[Them][PieceTypeC.QUEEN]);
                    if (b != 0)
                    {
                        attackUnits += RookContactCheckBonus * Bitcount.popcount_1s_Max15(b)
                                       * (Them == pos.sideToMove ? 2 : 1);
                    }
                }

                // Analyse enemy's safe distance checks for sliders and knights
                safe = ~(pos.byColorBB[Them] | ei.attackedBy[Us][0]);

                b1 = pos.attacks_from_ROOK(ksq) & safe;
                b2 = pos.attacks_from_BISHOP(ksq) & safe;

                // Enemy queen safe checks
                b = (b1 | b2) & ei.attackedBy[Them][PieceTypeC.QUEEN];
                if (b != 0)
                {
                    attackUnits += QueenCheckBonus * Bitcount.popcount_1s_Max15(b);
                }

                // Enemy rooks safe checks
                b = b1 & ei.attackedBy[Them][PieceTypeC.ROOK];
                if (b != 0)
                {
                    attackUnits += RookCheckBonus * Bitcount.popcount_1s_Max15(b);
                }

                // Enemy bishops safe checks
                b = b2 & ei.attackedBy[Them][PieceTypeC.BISHOP];
                if (b != 0)
                {
                    attackUnits += BishopCheckBonus * Bitcount.popcount_1s_Max15(b);
                }

                // Enemy knights safe checks
                b = Utils.StepAttacksBB_KNIGHT[ksq] & ei.attackedBy[Them][PieceTypeC.KNIGHT] & safe;
                if (b != 0)
                {
                    attackUnits += KnightCheckBonus * Bitcount.popcount_1s_Max15(b);
                }
#endif

                // To index KingDangerTable[] attackUnits must be in [0, 99] range
                attackUnits = Math.Min(99, Math.Max(0, attackUnits));

                // Finally, extract the king danger score from the KingDangerTable[]
                // array and subtract the score from evaluation. Set also margins[]
                // value that will be used for pruning because this value can sometimes
                // be very big, and so capturing a single attacking piece can therefore
                // result in a score change far bigger than the value of the captured piece.
                kingScore = KingDangerTable[Us == Search.RootColor ? 1 : 0][attackUnits];
                score -= kingScore;
                if (Us == ColorC.WHITE)
                {
                    marginsWHITE += (((kingScore + 32768) & ~0xffff) / 0x10000);
                }
                else
                {
                    marginsBLACK += (((kingScore + 32768) & ~0xffff) / 0x10000);
                }
            }

            if (Trace)
            {
                TracedScores[Us][PieceTypeC.KING] = score;
            }

            return score;
        }
Пример #3
0
        /// K, bishop and two pawns vs K and bishop. It detects a few basic draws with
        /// opposite-colored bishops.
        internal static ScaleFactor Endgame_KBPPKB(Color strongerSide, Position pos)
        {
            Color weakerSide = strongerSide ^ 1;

            Debug.Assert(pos.non_pawn_material(strongerSide) == Constants.BishopValueMidgame);
            Debug.Assert(pos.piece_count(strongerSide, PieceTypeC.BISHOP) == 1);
            Debug.Assert(pos.piece_count(strongerSide, PieceTypeC.PAWN) == 2);
            Debug.Assert(pos.non_pawn_material(weakerSide) == Constants.BishopValueMidgame);
            Debug.Assert(pos.piece_count(weakerSide, PieceTypeC.BISHOP) == 1);
            Debug.Assert(pos.piece_count(weakerSide, PieceTypeC.PAWN) == 0);

            Square wbsq = pos.pieceList[strongerSide][PieceTypeC.BISHOP][0];
            Square bbsq = pos.pieceList[weakerSide][PieceTypeC.BISHOP][0];

            if (!Utils.opposite_colors(wbsq, bbsq))
                return ScaleFactorC.SCALE_FACTOR_NONE;

            Square ksq = pos.king_square(weakerSide);
            Square psq1 = pos.pieceList[strongerSide][PieceTypeC.PAWN][0];
            Square psq2 = pos.pieceList[strongerSide][PieceTypeC.PAWN][1];
            Rank r1 = Utils.rank_of(psq1);
            Rank r2 = Utils.rank_of(psq2);
            Square blockSq1, blockSq2;

            if (Utils.relative_rank_CS(strongerSide, psq1) > Utils.relative_rank_CS(strongerSide, psq2))
            {
                blockSq1 = psq1 + Utils.pawn_push(strongerSide);
                blockSq2 = Utils.make_square(Utils.file_of(psq2), Utils.rank_of(psq1));
            }
            else
            {
                blockSq1 = psq2 + Utils.pawn_push(strongerSide);
                blockSq2 = Utils.make_square(Utils.file_of(psq1), Utils.rank_of(psq2));
            }

            switch (Utils.file_distance(psq1, psq2))
            {
                case 0:
                    // Both pawns are on the same file. Easy draw if defender firmly controls
                    // some square in the frontmost pawn's path.
                    if (Utils.file_of(ksq) == Utils.file_of(blockSq1)
                  && Utils.relative_rank_CS(strongerSide, ksq) >= Utils.relative_rank_CS(strongerSide, blockSq1)
                  && Utils.opposite_colors(ksq, wbsq))
                        return ScaleFactorC.SCALE_FACTOR_DRAW;
                    else
                        return ScaleFactorC.SCALE_FACTOR_NONE;

                case 1:
                    // Pawns on adjacent files. Draw if defender firmly controls the square
                    // in front of the frontmost pawn's path, and the square diagonally behind
                    // this square on the file of the other pawn.
                    if (ksq == blockSq1
                        && Utils.opposite_colors(ksq, wbsq)
                        && (bbsq == blockSq2
                            || (((pos.attacks_from_BISHOP(blockSq2) & pos.pieces_PTC(PieceTypeC.BISHOP, weakerSide))) != 0)
                            || Math.Abs(r1 - r2) >= 2))
                        return ScaleFactorC.SCALE_FACTOR_DRAW;

                    else if (ksq == blockSq2
                             && Utils.opposite_colors(ksq, wbsq)
                             && (bbsq == blockSq1
                                 || (((pos.attacks_from_BISHOP(blockSq1) & pos.pieces_PTC(PieceTypeC.BISHOP, weakerSide)))) != 0))
                        return ScaleFactorC.SCALE_FACTOR_DRAW;
                    else
                        return ScaleFactorC.SCALE_FACTOR_NONE;

                default:
                    // The pawns are not on the same file or adjacent files. No scaling.
                    return ScaleFactorC.SCALE_FACTOR_NONE;
            }
        }
Пример #4
0
        /// K, bishop and a pawn vs K and a bishop. There are two rules: If the defending
        /// king is somewhere along the path of the pawn, and the square of the king is
        /// not of the same color as the stronger side's bishop, it's a draw. If the two
        /// bishops have opposite color, it's almost always a draw.
        internal static ScaleFactor Endgame_KBPKB(Color strongerSide, Position pos)
        {
            Color weakerSide = strongerSide ^ 1;

            Debug.Assert(pos.non_pawn_material(strongerSide) == Constants.BishopValueMidgame);
            Debug.Assert(pos.piece_count(strongerSide, PieceTypeC.BISHOP) == 1);
            Debug.Assert(pos.piece_count(strongerSide, PieceTypeC.PAWN) == 1);
            Debug.Assert(pos.non_pawn_material(weakerSide) == Constants.BishopValueMidgame);
            Debug.Assert(pos.piece_count(weakerSide, PieceTypeC.BISHOP) == 1);
            Debug.Assert(pos.piece_count(weakerSide, PieceTypeC.PAWN) == 0);

            Square pawnSq = pos.pieceList[strongerSide][PieceTypeC.PAWN][0];
            Square strongerBishopSq = pos.pieceList[strongerSide][PieceTypeC.BISHOP][0];
            Square weakerBishopSq = pos.pieceList[weakerSide][PieceTypeC.BISHOP][0];
            Square weakerKingSq = pos.king_square(weakerSide);

            // Case 1: Defending king blocks the pawn, and cannot be driven away
            if (Utils.file_of(weakerKingSq) == Utils.file_of(pawnSq)
                && Utils.relative_rank_CS(strongerSide, pawnSq) < Utils.relative_rank_CS(strongerSide, weakerKingSq)
                && (Utils.opposite_colors(weakerKingSq, strongerBishopSq)
                    || Utils.relative_rank_CS(strongerSide, weakerKingSq) <= RankC.RANK_6))
                return ScaleFactorC.SCALE_FACTOR_DRAW;

            // Case 2: Opposite colored bishops
            if (Utils.opposite_colors(strongerBishopSq, weakerBishopSq))
            {
                // We assume that the position is drawn in the following three situations:
                //
                //   a. The pawn is on rank 5 or further back.
                //   b. The defending king is somewhere in the pawn's path.
                //   c. The defending bishop attacks some square along the pawn's path,
                //      and is at least three squares away from the pawn.
                //
                // These rules are probably not perfect, but in practice they work
                // reasonably well.

                if (Utils.relative_rank_CS(strongerSide, pawnSq) <= RankC.RANK_5)
                    return ScaleFactorC.SCALE_FACTOR_DRAW;
                else
                {
                    Bitboard path = Utils.forward_bb(strongerSide, pawnSq);

                    if ((path & pos.pieces_PTC(PieceTypeC.KING, weakerSide)) != 0)
                        return ScaleFactorC.SCALE_FACTOR_DRAW;

                    if (((pos.attacks_from_BISHOP(weakerBishopSq) & path) != 0)
                        && Utils.square_distance(weakerBishopSq, pawnSq) >= 3)
                        return ScaleFactorC.SCALE_FACTOR_DRAW;
                }
            }
            return ScaleFactorC.SCALE_FACTOR_NONE;
        }