Ejemplo n.º 1
0
 internal static EvalInfo GetObject()
 {
     int slotID = System.Threading.Thread.CurrentThread.ManagedThreadId & Constants.BROKER_SLOT_MASK;
     if (_cnt[slotID] == _pool[slotID].Length)
     {
         int poolLength = _pool[slotID].Length;
         EvalInfo[] temp = new EvalInfo[poolLength + Constants.BrokerCapacity];
         Array.Copy(_pool[slotID], temp, poolLength);
         for (int i = 0; i < Constants.BrokerCapacity; i++)
         {
             temp[poolLength + i] = new EvalInfo();
         }
         _pool[slotID] = temp;
     }
     return _pool[slotID][_cnt[slotID]++];
 }
Ejemplo n.º 2
0
 internal static void init()
 {
     for (int i = 0; i < Constants.BROKER_SLOTS; i++)
     {
         _pool[i] = new EvalInfo[0];
     }
 }
Ejemplo n.º 3
0
        // evaluate_pieces_of_color<>() assigns bonuses and penalties to all the
        // pieces of a given color.
        private static int evaluate_pieces_of_color(int Us, bool Trace, Position pos, EvalInfo ei, ref int mobility)
        {
            var Them = (Us == ColorC.WHITE ? ColorC.BLACK : ColorC.WHITE);
            mobility = ScoreC.SCORE_ZERO;

            // Do not include in mobility squares protected by enemy pawns or occupied by our pieces
            var mobilityArea = ~(ei.attackedBy[Them][PieceTypeC.PAWN] | pos.byColorBB[Us]);

            #region Evaluate pieces

            ulong between = 0;
            var plPos = 0;
            int s, ksq;
            int mob;
            int f;
            int score, scores = ScoreC.SCORE_ZERO;

            var attackedByThemKing = ei.attackedBy[Them][PieceTypeC.KING];
            var attackedByThemPawn = ei.attackedBy[Them][PieceTypeC.PAWN];
            var kingRingThem = ei.kingRing[Them];

            for (var Piece = PieceTypeC.KNIGHT; Piece < PieceTypeC.KING; Piece++)
            {
                score = ScoreC.SCORE_ZERO;
                ei.attackedBy[Us][Piece] = 0;
                var pl = pos.pieceList[Us][Piece];
                plPos = 0;
                while ((s = pl[plPos++]) != SquareC.SQ_NONE)
                {
                    // Find attacked squares, including x-ray attacks for bishops and rooks
                    if (Piece == PieceTypeC.KNIGHT)
                    {
                        between = Utils.StepAttacksBB_KNIGHT[s];
                    }
                    else if (Piece == PieceTypeC.QUEEN)
                    {
#if X64
                        b = Utils.BAttacks[s][(((pos.occupied_squares & Utils.BMasks[s]) * Utils.BMagics[s]) >> Utils.BShifts[s])] | Utils.RAttacks[s][(((pos.occupied_squares & Utils.RMasks[s]) * Utils.RMagics[s]) >> Utils.RShifts[s])];
#else
                        between = Utils.bishop_attacks_bb(s, pos.occupied_squares)
                            | Utils.rook_attacks_bb(s, pos.occupied_squares);
#endif
                    }
                    else if (Piece == PieceTypeC.BISHOP)
                    {
#if X64
                        b = Utils.BAttacks[s][(((
                              (pos.occupied_squares ^ (pos.byTypeBB[PieceTypeC.QUEEN] & pos.byColorBB[Us]))
                            & Utils.BMasks[s]) * Utils.BMagics[s]) >> Utils.BShifts[s])];
#else
                        between = Utils.bishop_attacks_bb(s, pos.occupied_squares ^ pos.pieces_PTC(PieceTypeC.QUEEN, Us));
#endif
                    }
                    else if (Piece == PieceTypeC.ROOK)
                    {
#if X64
                        b = Utils.RAttacks[s][(((
                              (pos.occupied_squares ^ ((pos.byTypeBB[PieceTypeC.ROOK] | pos.byTypeBB[PieceTypeC.QUEEN]) & pos.byColorBB[Us]))
                            & Utils.RMasks[s]) * Utils.RMagics[s]) >> Utils.RShifts[s])];
#else
                        between = Utils.rook_attacks_bb(
                            s,
                            pos.occupied_squares ^ pos.pieces(PieceTypeC.ROOK, PieceTypeC.QUEEN, Us));
#endif
                    }

                    // Update attack info
                    ei.attackedBy[Us][Piece] |= between;

                    // King attacks
                    if ((between & kingRingThem) != 0)
                    {
                        ei.kingAttackersCount[Us]++;
                        ei.kingAttackersWeight[Us] += KingAttackWeights[Piece];
                        var bb = (between & attackedByThemKing); //ei.attackedBy[Them][PieceTypeC.KING]);
                        if (bb != 0)
                        {
#if X64
                            bb -= (bb >> 1) & 0x5555555555555555UL;
                            bb = ((bb >> 2) & 0x3333333333333333UL) + (bb & 0x3333333333333333UL);
                            ei.kingAdjacentZoneAttacksCount[Us] += (int)((bb * 0x1111111111111111UL) >> 60);
#else
                            ei.kingAdjacentZoneAttacksCount[Us] += Bitcount.popcount_1s_Max15(bb);
#endif
                        }
                    }

                    // Mobility
#if X64
                    Bitboard bmob = b & mobilityArea;
                    if (Piece != PieceTypeC.QUEEN)
                    {
                        bmob -= (bmob >> 1) & 0x5555555555555555UL;
                        bmob = ((bmob >> 2) & 0x3333333333333333UL) + (bmob & 0x3333333333333333UL);
                        mob = (int)((bmob * 0x1111111111111111UL) >> 60);
                    }
                    else
                    {
                        bmob -= ((bmob >> 1) & 0x5555555555555555UL);
                        bmob = ((bmob >> 2) & 0x3333333333333333UL) + (bmob & 0x3333333333333333UL);
                        bmob = ((bmob >> 4) + bmob) & 0x0F0F0F0F0F0F0F0FUL;
                        mob = (int)((bmob * 0x0101010101010101UL) >> 56);
                    }
#else
                    mob = (Piece != PieceTypeC.QUEEN
                               ? Bitcount.popcount_1s_Max15(between & mobilityArea)
                               : Bitcount.popcount_1s_Full(between & mobilityArea));
#endif
                    mobility += MobilityBonus[Piece][mob];

                    // Decrease score if we are attacked by an enemy pawn. Remaining part
                    // of threat evaluation must be done later when we have full attack info.
                    if ((attackedByThemPawn & Utils.SquareBB[s]) != 0)
                    {
                        score -= ThreatenedByPawnPenalty[Piece];
                    }
                    else if ((Piece == PieceTypeC.BISHOP)
                        && ((Utils.PseudoAttacks[Piece][pos.pieceList[Them][PieceTypeC.KING][0]] & Utils.SquareBB[s])
                            != 0))
                    {
                        between = Utils.BetweenBB[s][pos.pieceList[Them][PieceTypeC.KING][0]] & pos.occupied_squares;

                        if (!Utils.more_than_one(between))
                        {
                            score += Utils.make_score(15, 25);
                        }
                    }

                    // Bishop and knight outposts squares
                    if ((Piece == PieceTypeC.BISHOP || Piece == PieceTypeC.KNIGHT)
                        && (((pos.byTypeBB[PieceTypeC.PAWN] & pos.byColorBB[Them]) & Utils.AttackSpanMask[Us][s]) == 0))
                    {
                        #region Evaluate outposts inlined

                        // evaluate_outposts() evaluates bishop and knight outposts squares

                        // Initial bonus based on square
                        var bonus = OutpostBonus[Piece == PieceTypeC.BISHOP ? 1 : 0][s ^ (Us * 56)];

                        // Increase bonus if supported by pawn, especially if the opponent has
                        // no minor piece which can exchange the outpost piece.
                        if ((bonus != 0) && ((ei.attackedBy[Us][PieceTypeC.PAWN] & Utils.SquareBB[s]) != 0))
                        {
                            if (((pos.byTypeBB[PieceTypeC.KNIGHT] & pos.byColorBB[Them]) == 0)
                                && (((((0xAA55AA55AA55AA55UL & Utils.SquareBB[s]) != 0)
                                          ? 0xAA55AA55AA55AA55UL
                                          : ~0xAA55AA55AA55AA55UL)
                                     & (pos.byTypeBB[PieceTypeC.BISHOP] & pos.byColorBB[Them])) == 0))
                            {
                                bonus += bonus + bonus / 2;
                            }
                            else
                            {
                                bonus += bonus / 2;
                            }
                        }
                        score += ((bonus << 16) + bonus); // Utils.make_score(bonus, bonus);

                        #endregion
                    }

                    if ((Piece == PieceTypeC.ROOK || Piece == PieceTypeC.QUEEN) && Utils.relative_rank_CS(Us, s) >= RankC.RANK_5)
                    {
                        // Major piece on 7th rank
                        if (Utils.relative_rank_CS(Us, s) == RankC.RANK_7
                            && Utils.relative_rank_CS(Us, pos.king_square(Them)) == RankC.RANK_8)
                            score += (Piece == PieceTypeC.ROOK ? RookOn7thBonus : QueenOn7thBonus);

                        // Major piece attacking pawns on the same rank
                        Bitboard pawns = pos.pieces_PTC(PieceTypeC.PAWN, Them) & Utils.rank_bb_S(s);
                        if (pawns != 0)
                        {
                            score += (Piece == PieceTypeC.ROOK ? RookOnPawnBonus : QueenOnPawnBonus) * Bitcount.popcount_1s_Max15(pawns);
                        }
                    }

                    // Special extra evaluation for bishops
                    if (pos.chess960 && (Piece == PieceTypeC.BISHOP))
                    {
                        // An important Chess960 pattern: A cornered bishop blocked by
                        // a friendly pawn diagonally in front of it is a very serious
                        // problem, especially when that pawn is also blocked.
                        if (s == Utils.relative_square(Us, SquareC.SQ_A1)
                            || s == Utils.relative_square(Us, SquareC.SQ_H1))
                        {
                            var d = Utils.pawn_push(Us)
                                    + (Utils.file_of(s) == FileC.FILE_A ? SquareC.DELTA_E : SquareC.DELTA_W);
                            if (pos.piece_on(s + d) == Utils.make_piece(Us, PieceTypeC.PAWN))
                            {
                                if (!pos.is_empty(s + d + Utils.pawn_push(Us)))
                                {
                                    score -= 2 * TrappedBishopA1H1Penalty;
                                }
                                else if (pos.piece_on(s + 2 * d) == Utils.make_piece(Us, PieceTypeC.PAWN))
                                {
                                    score -= TrappedBishopA1H1Penalty;
                                }
                                else
                                {
                                    score -= TrappedBishopA1H1Penalty / 2;
                                }
                            }
                        }
                    }

                    // Special extra evaluation for rooks
                    if (Piece == PieceTypeC.ROOK)
                    {
                        // Open and half-open files
                        f = (s & 7);

                        var halfOpenUs = ((Us == ColorC.WHITE)
                                              ? (ei.pi.halfOpenFilesWHITE & (1 << f))
                                              : (ei.pi.halfOpenFilesBLACK & (1 << f))) != 0;

                        if (halfOpenUs)
                        {
                            if (((Them == ColorC.WHITE)
                                     ? (ei.pi.halfOpenFilesWHITE & (1 << f))
                                     : (ei.pi.halfOpenFilesBLACK & (1 << f))) != 0)
                            {
                                score += RookOpenFileBonus;
                            }
                            else
                            {
                                score += RookHalfOpenFileBonus;
                            }
                        }

                        // Penalize rooks which are trapped inside a king. Penalize more if
                        // king has lost right to castle.
                        if (mob > 6 || halfOpenUs)
                        {
                            continue;
                        }

                        ksq = pos.pieceList[Us][PieceTypeC.KING][0];

                        if (((ksq >> 3) ^ (Us * 7)) == RankC.RANK_1 || (ksq >> 3) == (s >> 3))
                        {
                            if ((ksq & 7) >= FileC.FILE_E)
                            {
                                if (f > (ksq & 7))
                                {
                                    // Is there a half-open file between the king and the edge of the board?
                                    if (((Us == ColorC.WHITE)
                                             ? (ei.pi.halfOpenFilesWHITE & ~((1 << ((ksq & 7) + 1)) - 1))
                                             : (ei.pi.halfOpenFilesBLACK & ~((1 << ((ksq & 7) + 1)) - 1))) == 0)
                                    {
                                        score -= ((((pos.st.castleRights & (CastleRightC.WHITE_ANY << (Us << 1))) != 0)
                                                       ? (TrappedRookPenalty - mob * 16) / 2
                                                       : (TrappedRookPenalty - mob * 16)) << 16);
                                    }
                                }
                            }
                            else
                            {
                                if (f < (ksq & 7))
                                {
                                    // Is there a half-open file between the king and the edge of the board?
                                    if (((Us == ColorC.WHITE)
                                             ? (ei.pi.halfOpenFilesWHITE & ((1 << (ksq & 7)) - 1))
                                             : (ei.pi.halfOpenFilesBLACK & ((1 << (ksq & 7)) - 1))) == 0)
                                    {
                                        score -= ((((pos.st.castleRights & (CastleRightC.WHITE_ANY << (Us << 1))) != 0)
                                                       ? (TrappedRookPenalty - mob * 16) / 2
                                                       : (TrappedRookPenalty - mob * 16)) << 16);
                                    }
                                }
                            }
                        }
                    }
                }

                scores += score;

                if (Trace)
                {
                    TracedScores[Us][Piece] = score;
                }
            }

            #endregion

            // Sum up all attacked squares
            ei.attackedBy[Us][0] = 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] | ei.attackedBy[Us][PieceTypeC.KING];

            return scores;
        }
Ejemplo n.º 4
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;
        }
Ejemplo n.º 5
0
        // evaluate_threats<>() assigns bonuses according to the type of attacking piece
        // and the type of attacked one.
        private static int evaluate_threats(int Us, Position pos, EvalInfo ei)
        {
            var Them = (Us == ColorC.WHITE ? ColorC.BLACK : ColorC.WHITE);

            ulong b, undefendedMinors, weakEnemies;
            var score = ScoreC.SCORE_ZERO;

            // Undefended minors get penalized even if not under attack
            undefendedMinors = pos.byColorBB[Them] & (pos.byTypeBB[PieceTypeC.BISHOP] | pos.byTypeBB[PieceTypeC.KNIGHT])
                               & ~ei.attackedBy[Them][0];

            if (undefendedMinors != 0)
            {
                score += (Utils.more_than_one(undefendedMinors))
                             ? UndefendedMinorPenalty * 2
                             : UndefendedMinorPenalty;
            }

            // Enemy pieces not defended by a pawn and under our attack
            weakEnemies = pos.byColorBB[Them] & ~ei.attackedBy[Them][PieceTypeC.PAWN] & ei.attackedBy[Us][0];

            if (weakEnemies == 0)
            {
                return score;
            }

            // Add bonus according to type of attacked enemy piece and to the
            // type of attacking piece, from knights to queens. Kings are not
            // considered because are already handled in king evaluation.
            for (var pt1 = PieceTypeC.KNIGHT; pt1 < PieceTypeC.KING; pt1++)
            {
                b = ei.attackedBy[Us][pt1] & weakEnemies;
                if (b != 0)
                {
                    for (var pt2 = PieceTypeC.PAWN; pt2 < PieceTypeC.KING; pt2++)
                    {
                        if ((b & pos.byTypeBB[pt2]) != 0)
                        {
                            score += ThreatBonus[pt1][pt2];
                        }
                    }
                }
            }

            return score;
        }
Ejemplo n.º 6
0
        // init_eval_info() initializes king bitboards for given color adding
        // pawn attacks. To be done at the beginning of the evaluation.
        private static void init_eval_info(int Us, Position pos, EvalInfo ei)
        {
            var Them = (Us == ColorC.WHITE ? ColorC.BLACK : ColorC.WHITE);

            var b =
                ei.attackedBy[Them][PieceTypeC.KING] = Utils.StepAttacksBB_KING[pos.pieceList[Them][PieceTypeC.KING][0]];
            ei.attackedBy[Us][PieceTypeC.PAWN] = (Us == ColorC.WHITE) ? ei.pi.pawnAttacksWHITE : ei.pi.pawnAttacksBLACK;

            // Init king safety tables only if we are going to use them
            if ((pos.pieceCount[Us][PieceTypeC.QUEEN] != 0)
                && (Us == 0 ? pos.st.npMaterialWHITE : pos.st.npMaterialBLACK)
                > Constants.QueenValueMidgame + Constants.RookValueMidgame)
            {
                ei.kingRing[Them] = (b | (Us == ColorC.WHITE ? b >> 8 : b << 8));
                b &= ei.attackedBy[Us][PieceTypeC.PAWN];
                ei.kingAttackersCount[Us] = (b != 0) ? Bitcount.popcount_1s_Max15(b) / 2 : 0;
                ei.kingAdjacentZoneAttacksCount[Us] = ei.kingAttackersWeight[Us] = 0;
            }
            else
            {
                ei.kingRing[Them] = 0;
                ei.kingAttackersCount[Us] = 0;
            }
        }
Ejemplo n.º 7
0
        // evaluate_space() computes the space evaluation for a given side. The
        // space evaluation is a simple bonus based on the number of safe squares
        // available for minor pieces on the central four files on ranks 2--4. Safe
        // squares one, two or three squares behind a friendly pawn are counted
        // twice. Finally, the space bonus is scaled by a weight taken from the
        // material hash table. The aim is to improve play on game opening.
        private static int evaluate_space(int Us, Position pos, EvalInfo ei)
        {
            var Them = (Us == ColorC.WHITE ? ColorC.BLACK : ColorC.WHITE);

            // Find the safe squares for our pieces inside the area defined by
            // SpaceMask[]. A square is unsafe if it is attacked by an enemy
            // pawn, or if it is undefended and attacked by an enemy piece.
            var behind = pos.byTypeBB[PieceTypeC.PAWN] & pos.byColorBB[Us];
            var safe = SpaceMask[Us] & ~behind & ~ei.attackedBy[Them][PieceTypeC.PAWN]
                       & (ei.attackedBy[Us][0] | ~ei.attackedBy[Them][0]);

            // Find all squares which are at most three squares behind some friendly pawn
            behind |= (Us == ColorC.WHITE ? behind >> 8 : behind << 8);
            behind |= (Us == ColorC.WHITE ? behind >> 16 : behind << 16);

            return Bitcount.popcount_1s_Max15(safe) + Bitcount.popcount_1s_Max15(behind & safe);
        }
Ejemplo n.º 8
0
        // evaluate_unstoppable_pawns() evaluates the unstoppable passed pawns for both sides, this is quite
        // conservative and returns a winning score only when we are very sure that the pawn is winning.
        private static int evaluate_unstoppable_pawns(Position pos, EvalInfo ei)
        {
            ulong b, b2, blockers, supporters, queeningPath, candidates;
            int s, blockSq, queeningSquare;
            int c, winnerSide, loserSide;
            bool pathDefended, opposed;
            int pliesToGo = 0, movesToGo, oppMovesToGo = 0, sacptg, blockersCount, minKingDist, kingptg, d;
            int pliesToQueenWHITE = 256, pliesToQueenBLACK = 256, pliesToQueenWinner = 256;

            // Step 1. Hunt for unstoppable passed pawns. If we find at least one,
            // record how many plies are required for promotion.
            for (c = ColorC.WHITE; c <= ColorC.BLACK; c++)
            {
                // Skip if other side has non-pawn pieces
                if (pos.non_pawn_material(Utils.flip_C(c)) != 0)
                {
                    continue;
                }

                b = ei.pi.passed_pawns(c);

                while (b != 0)
                {
                    s = Utils.pop_lsb(ref b);
                    queeningSquare = Utils.relative_square(c, Utils.make_square(Utils.file_of(s), RankC.RANK_8));
                    queeningPath = Utils.forward_bb(c, s);

                    // Compute plies to queening and check direct advancement
                    movesToGo = Utils.rank_distance(s, queeningSquare)
                                - (Utils.relative_rank_CS(c, s) == RankC.RANK_2 ? 1 : 0);
                    oppMovesToGo = Utils.square_distance(pos.king_square(Utils.flip_C(c)), queeningSquare)
                                   - ((c != pos.sideToMove) ? 1 : 0);
                    pathDefended = ((ei.attackedBy[c][0] & queeningPath) == queeningPath);

                    if (movesToGo >= oppMovesToGo && !pathDefended)
                    {
                        continue;
                    }

                    // Opponent king cannot block because path is defended and position
                    // is not in check. So only friendly pieces can be blockers.
                    Debug.Assert(!pos.in_check());
                    Debug.Assert((queeningPath & pos.occupied_squares) == (queeningPath & pos.pieces_C(c)));

                    // Add moves needed to free the path from friendly pieces and retest condition
                    movesToGo += Bitcount.popcount_1s_Max15(queeningPath & pos.pieces_C(c));

                    if (movesToGo >= oppMovesToGo && !pathDefended)
                    {
                        continue;
                    }

                    pliesToGo = 2 * movesToGo - ((c == pos.sideToMove) ? 1 : 0);

                    if (c == ColorC.WHITE)
                    {
                        pliesToQueenWHITE = Math.Min(pliesToQueenWHITE, pliesToGo);
                    }
                    else
                    {
                        pliesToQueenBLACK = Math.Min(pliesToQueenBLACK, pliesToGo);
                    }
                }
            }

            // Step 2. If either side cannot promote at least three plies before the other side then situation
            // becomes too complex and we give up. Otherwise we determine the possibly "winning side"
            if (Math.Abs(pliesToQueenWHITE - pliesToQueenBLACK) < 3)
            {
                return ScoreC.SCORE_ZERO;
            }

            winnerSide = (pliesToQueenWHITE < pliesToQueenBLACK ? ColorC.WHITE : ColorC.BLACK);
            pliesToQueenWinner = (winnerSide == ColorC.WHITE) ? pliesToQueenWHITE : pliesToQueenBLACK;
            loserSide = Utils.flip_C(winnerSide);

            // Step 3. Can the losing side possibly create a new passed pawn and thus prevent the loss?
            b = candidates = pos.pieces_PTC(PieceTypeC.PAWN, loserSide);

            while (b != 0)
            {
                s = Utils.pop_lsb(ref b);

                // Compute plies from queening
                queeningSquare = Utils.relative_square(loserSide, Utils.make_square(Utils.file_of(s), RankC.RANK_8));
                movesToGo = Utils.rank_distance(s, queeningSquare)
                            - ((Utils.relative_rank_CS(loserSide, s) == RankC.RANK_2) ? 1 : 0);
                pliesToGo = 2 * movesToGo - ((loserSide == pos.sideToMove) ? 1 : 0);

                // Check if (without even considering any obstacles) we're too far away or doubled
                if ((pliesToQueenWinner + 3 <= pliesToGo)
                    || ((Utils.forward_bb(loserSide, s) & pos.pieces_PTC(PieceTypeC.PAWN, loserSide)) != 0))
                {
                    Utils.xor_bit(ref candidates, s);
                }
            }

            // If any candidate is already a passed pawn it _may_ promote in time. We give up.
            if ((candidates & ei.pi.passed_pawns(loserSide)) != 0)
            {
                return ScoreC.SCORE_ZERO;
            }

            // Step 4. Check new passed pawn creation through king capturing and pawn sacrifices
            b = candidates;

            while (b != 0)
            {
                s = Utils.pop_lsb(ref b);
                sacptg = blockersCount = 0;
                minKingDist = kingptg = 256;

                // Compute plies from queening
                queeningSquare = Utils.relative_square(loserSide, Utils.make_square(Utils.file_of(s), RankC.RANK_8));
                movesToGo = Utils.rank_distance(s, queeningSquare)
                            - ((Utils.relative_rank_CS(loserSide, s) == RankC.RANK_2) ? 1 : 0);
                pliesToGo = 2 * movesToGo - ((loserSide == pos.sideToMove) ? 1 : 0);

                // Generate list of blocking pawns and supporters
                supporters = Utils.adjacent_files_bb(Utils.file_of(s)) & candidates;
                opposed = (Utils.forward_bb(loserSide, s) & pos.pieces_PTC(PieceTypeC.PAWN, winnerSide)) != 0;
                blockers = Utils.passed_pawn_mask(loserSide, s) & pos.pieces_PTC(PieceTypeC.PAWN, winnerSide);

                Debug.Assert(blockers != 0);

                // How many plies does it take to remove all the blocking pawns?
                while (blockers != 0)
                {
                    blockSq = Utils.pop_lsb(ref blockers);
                    movesToGo = 256;

                    // Check pawns that can give support to overcome obstacle, for instance
                    // black pawns: a4, b4 white: b2 then pawn in b4 is giving support.
                    if (!opposed)
                    {
                        b2 = supporters & Utils.in_front_bb_CS(winnerSide, blockSq + Utils.pawn_push(winnerSide));

                        while (b2 != 0) // This while-loop could be replaced with LSB/MSB (depending on color)
                        {
                            d = Utils.square_distance(blockSq, Utils.pop_lsb(ref b2)) - 2;
                            movesToGo = Math.Min(movesToGo, d);
                        }
                    }

                    // Check pawns that can be sacrificed against the blocking pawn
                    b2 = Utils.attack_span_mask(winnerSide, blockSq) & candidates & ~(1UL << s);

                    while (b2 != 0) // This while-loop could be replaced with LSB/MSB (depending on color)
                    {
                        d = Utils.square_distance(blockSq, Utils.pop_lsb(ref b2)) - 2;
                        movesToGo = Math.Min(movesToGo, d);
                    }

                    // If obstacle can be destroyed with an immediate pawn exchange / sacrifice,
                    // it's not a real obstacle and we have nothing to add to pliesToGo.
                    if (movesToGo <= 0)
                    {
                        continue;
                    }

                    // Plies needed to sacrifice against all the blocking pawns
                    sacptg += movesToGo * 2;
                    blockersCount++;

                    // Plies needed for the king to capture all the blocking pawns
                    d = Utils.square_distance(pos.king_square(loserSide), blockSq);
                    minKingDist = Math.Min(minKingDist, d);
                    kingptg = (minKingDist + blockersCount) * 2;
                }

                // Check if pawn sacrifice plan _may_ save the day
                if (pliesToQueenWinner + 3 > pliesToGo + sacptg)
                {
                    return ScoreC.SCORE_ZERO;
                }

                // Check if king capture plan _may_ save the day (contains some false positives)
                if (pliesToQueenWinner + 3 > pliesToGo + kingptg)
                {
                    return ScoreC.SCORE_ZERO;
                }
            }

            // Winning pawn is unstoppable and will promote as first, return big score
            var score = Utils.make_score(0, 0x500 - 0x20 * pliesToQueenWinner);
            return winnerSide == ColorC.WHITE ? score : -score;
        }
Ejemplo n.º 9
0
        // evaluate_passed_pawns<>() evaluates the passed pawns of the given color
        private static int evaluate_passed_pawns(int Us, Position pos, EvalInfo ei)
        {
            var Them = (Us == ColorC.WHITE ? ColorC.BLACK : ColorC.WHITE);

            ulong b, squaresToQueen, defendedSquares, unsafeSquares, supportingPawns;
            var score = ScoreC.SCORE_ZERO;

            b = (Us == ColorC.WHITE) ? ei.pi.passedPawnsWHITE : ei.pi.passedPawnsBLACK;

            if (b == 0)
            {
                return ScoreC.SCORE_ZERO;
            }

            do
            {
#if X64
                Bitboard bb = b;
                b &= (b - 1);
                Square s = (Utils.BSFTable[((bb & (0xffffffffffffffff - bb + 1)) * DeBruijn_64) >> 58]);
#else
                var s = Utils.pop_lsb(ref b);
#endif
                Debug.Assert(pos.pawn_is_passed(Us, s));

                var r = ((s >> 3) ^ (Us * 7)) - RankC.RANK_2;
                var rr = r * (r - 1);

                // Base bonus based on rank
                var mbonus = (20 * rr);
                var ebonus = (10 * (rr + r + 1));

                if (rr != 0)
                {
                    var blockSq = s + (Us == ColorC.WHITE ? SquareC.DELTA_N : SquareC.DELTA_S);

                    // Adjust bonus based on kings proximity
                    ebonus += (Utils.SquareDistance[pos.pieceList[Them][PieceTypeC.KING][0]][blockSq] * 5 * rr);
                    ebonus -= (Utils.SquareDistance[pos.pieceList[Us][PieceTypeC.KING][0]][blockSq] * 2 * rr);

                    // If blockSq is not the queening square then consider also a second push
                    if ((blockSq >> 3) != (Us == ColorC.WHITE ? RankC.RANK_8 : RankC.RANK_1))
                    {
                        ebonus -=
                            (Utils.SquareDistance[pos.pieceList[Us][PieceTypeC.KING][0]][
                                blockSq + (Us == ColorC.WHITE ? SquareC.DELTA_N : SquareC.DELTA_S)] * rr);
                    }

                    // If the pawn is free to advance, increase bonus
                    if (pos.board[blockSq] == PieceC.NO_PIECE)
                    {
                        squaresToQueen = Utils.ForwardBB[Us][s];
                        defendedSquares = squaresToQueen & ei.attackedBy[Us][0];

                        // If there is an enemy rook or queen attacking the pawn from behind,
                        // add all X-ray attacks by the rook or queen. Otherwise consider only
                        // the squares in the pawn's path attacked or occupied by the enemy.
                        if (((Utils.ForwardBB[Them][s]
                              & ((pos.byTypeBB[PieceTypeC.ROOK] | pos.byTypeBB[PieceTypeC.QUEEN]) & pos.byColorBB[Them]))
                             != 0)
                            && ((Utils.ForwardBB[Them][s]
                                 & ((pos.byTypeBB[PieceTypeC.ROOK] | pos.byTypeBB[PieceTypeC.QUEEN])
                                    & pos.byColorBB[Them]) & pos.attacks_from_ROOK(s)) != 0))
                        {
                            unsafeSquares = squaresToQueen;
                        }
                        else
                        {
                            unsafeSquares = squaresToQueen & (ei.attackedBy[Them][0] | pos.byColorBB[Them]);
                        }

                        // If there aren't enemy attacks or pieces along the path to queen give
                        // huge bonus. Even bigger if we protect the pawn's path.
                        if (unsafeSquares == 0)
                        {
                            ebonus += (rr * (squaresToQueen == defendedSquares ? 17 : 15));
                        }
                        else
                        {
                            // OK, there are enemy attacks or pieces (but not pawns). Are those
                            // squares which are attacked by the enemy also attacked by us ?
                            // If yes, big bonus (but smaller than when there are no enemy attacks),
                            // if no, somewhat smaller bonus.
                            ebonus += (rr * ((unsafeSquares & defendedSquares) == unsafeSquares ? 13 : 8));
                        }
                    }
                } // rr != 0

                // Increase the bonus if the passed pawn is supported by a friendly pawn
                // on the same rank and a bit smaller if it's on the previous rank.
                supportingPawns = (pos.byTypeBB[PieceTypeC.PAWN] & pos.byColorBB[Us]) & Utils.AdjacentFilesBB[s & 7];
                if ((supportingPawns & Utils.RankBB[s >> 3]) != 0)
                {
                    ebonus += (r * 20);
                }
                else if ((supportingPawns
                          & Utils.RankBB[(s - (Us == ColorC.WHITE ? SquareC.DELTA_N : SquareC.DELTA_S)) >> 3]) != 0)
                {
                    ebonus += (r * 12);
                }

                // Rook pawns are a special case: They are sometimes worse, and
                // sometimes better than other passed pawns. It is difficult to find
                // good rules for determining whether they are good or bad. For now,
                // we try the following: Increase the value for rook pawns if the
                // other side has no pieces apart from a knight, and decrease the
                // value if the other side has a rook or queen.
                if ((s & 7) == FileC.FILE_A || (s & 7) == FileC.FILE_H)
                {
                    if ((Them == 0 ? pos.st.npMaterialWHITE : pos.st.npMaterialBLACK) <= Constants.KnightValueMidgame)
                    {
                        ebonus += ebonus / 4;
                    }
                    else if (((pos.byTypeBB[PieceTypeC.ROOK] | pos.byTypeBB[PieceTypeC.QUEEN]) & pos.byColorBB[Them])
                             != 0)
                    {
                        ebonus -= ebonus / 4;
                    }
                }
                score += ((mbonus << 16) + ebonus);
            }
            while (b != 0);

            // Add the scores to the middle game and endgame eval
            return Utils.apply_weight(score, Weights[EvalWeightC.PassedPawns]);
        }