Пример #1
0
        // init_eval_info() initializes king bitboards for given color adding
        // pawn attacks. To be done at the beginning of the evaluation.
        public static void init_eval_info(Position pos, EvalInfo ei, Color Us)
        {
            Color  Them = (Us == ColorS.WHITE ? ColorS.BLACK : ColorS.WHITE);
            Square Down = (Us == ColorS.WHITE ? SquareS.DELTA_S : SquareS.DELTA_N);

            ei.pinnedPieces[Us] = pos.pinned_pieces(Us);

            Bitboard b = ei.attackedBy[Them][PieceTypeS.KING] = pos.attacks_from_square_piecetype(pos.king_square(Them), PieceTypeS.KING);

            ei.attackedBy[Us][PieceTypeS.ALL_PIECES] = ei.attackedBy[Us][PieceTypeS.PAWN] = ei.pi.pawn_attacks(Us);

            // Init king safety tables only if we are going to use them
            if (pos.count(Us, PieceTypeS.QUEEN) != 0 && pos.non_pawn_material(Us) > ValueS.QueenValueMg + ValueS.PawnValueMg)
            {
                ei.kingRing[Them] = b | BitBoard.shift_bb(b, Down);
                b &= ei.attackedBy[Us][PieceTypeS.PAWN];
                ei.kingAttackersCount[Us]           = (b != 0) ? Bitcount.popcount_Max15(b) : 0;
                ei.kingAdjacentZoneAttacksCount[Us] = ei.kingAttackersWeight[Us] = 0;
            }
            else
            {
                ei.kingRing[Them]         = 0;
                ei.kingAttackersCount[Us] = 0;
            }
        }
Пример #2
0
        public static Score evaluate(Position pos, Pawns.Entry e, Color Us)
        {
            Color  Them  = (Us == ColorS.WHITE ? ColorS.BLACK : ColorS.WHITE);
            Square Up    = (Us == ColorS.WHITE ? SquareS.DELTA_N : SquareS.DELTA_S);
            Square Right = (Us == ColorS.WHITE ? SquareS.DELTA_NE : SquareS.DELTA_SW);
            Square Left  = (Us == ColorS.WHITE ? SquareS.DELTA_NW : SquareS.DELTA_SE);

            Bitboard b, p, doubled;
            Square   s;
            File     f;
            Rank     r;
            bool     passed, isolated, opposed, connected, backward, candidate, unsupported;
            Score    value = ScoreS.SCORE_ZERO;

            Square[] pl    = pos.list(Us, PieceTypeS.PAWN);
            int      plPos = 0;

            Bitboard ourPawns   = pos.pieces_color_piecetype(Us, PieceTypeS.PAWN);
            Bitboard theirPawns = pos.pieces_color_piecetype(Them, PieceTypeS.PAWN);

            e.passedPawns[Us]   = e.candidatePawns[Us] = 0;
            e.kingSquares[Us]   = SquareS.SQ_NONE;
            e.semiopenFiles[Us] = 0xFF;
            e.pawnAttacks[Us]   = BitBoard.shift_bb(ourPawns, Right) | BitBoard.shift_bb(ourPawns, Left);
            e.pawnsOnSquares[Us][ColorS.BLACK] = Bitcount.popcount_Max15(ourPawns & BitBoard.DarkSquares);
            e.pawnsOnSquares[Us][ColorS.WHITE] = pos.count(Us, PieceTypeS.PAWN) - e.pawnsOnSquares[Us][ColorS.BLACK];

            // Loop through all pawns of the current color and score each pawn
            while ((s = pl[plPos++]) != SquareS.SQ_NONE)
            {
                Debug.Assert(pos.piece_on(s) == Types.make_piece(Us, PieceTypeS.PAWN));

                f = Types.file_of(s);


                // This file cannot be semi-open
                e.semiopenFiles[Us] &= ~(1 << f);

                // Previous rank
                p = BitBoard.rank_bb_square(s - Types.pawn_push(Us));

                // Our rank plus previous one
                b = BitBoard.rank_bb_square(s) | p;

                // Flag the pawn as passed, isolated, doubled,
                // unsupported or connected (but not the backward one).
                connected   = (ourPawns & BitBoard.adjacent_files_bb(f) & b) != 0;
                unsupported = (0 == (ourPawns & BitBoard.adjacent_files_bb(f) & p));
                isolated    = (0 == (ourPawns & BitBoard.adjacent_files_bb(f)));
                doubled     = ourPawns & BitBoard.forward_bb(Us, s);
                opposed     = (theirPawns & BitBoard.forward_bb(Us, s)) != 0;
                passed      = (0 == (theirPawns & BitBoard.passed_pawn_mask(Us, s)));

                // Test for backward pawn.
                // If the pawn is passed, isolated, or connected it cannot be
                // backward. If there are friendly pawns behind on adjacent files
                // or if it can capture an enemy pawn it cannot be backward either.
                if ((passed | isolated | connected) ||
                    (ourPawns & BitBoard.pawn_attack_span(Them, s)) != 0 ||
                    (pos.attacks_from_pawn(s, Us) & theirPawns) != 0)
                {
                    backward = false;
                }
                else
                {
                    // We now know that there are no friendly pawns beside or behind this
                    // pawn on adjacent files. We now check whether the pawn is
                    // backward by looking in the forward direction on the adjacent
                    // files, and picking the closest pawn there.
                    b = BitBoard.pawn_attack_span(Us, s) & (ourPawns | theirPawns);
                    b = BitBoard.pawn_attack_span(Us, s) & BitBoard.rank_bb_square(BitBoard.backmost_sq(Us, b));

                    // If we have an enemy pawn in the same or next rank, the pawn is
                    // backward because it cannot advance without being captured.
                    backward = ((b | BitBoard.shift_bb(b, Up)) & theirPawns) != 0;
                }

                Debug.Assert(opposed | passed | (BitBoard.pawn_attack_span(Us, s) & theirPawns) != 0);

                // A not-passed pawn is a candidate to become passed, if it is free to
                // advance and if the number of friendly pawns beside or behind this
                // pawn on adjacent files is higher than or equal to the number of
                // enemy pawns in the forward direction on the adjacent files.
                candidate = !(opposed | passed | backward | isolated) &&
                            (b = BitBoard.pawn_attack_span(Them, s + Types.pawn_push(Us)) & ourPawns) != 0 &&
                            Bitcount.popcount_Max15(b) >= Bitcount.popcount_Max15(BitBoard.pawn_attack_span(Us, s) & theirPawns);

                // Passed pawns will be properly scored in evaluation because we need
                // full attack info to evaluate passed pawns. Only the frontmost passed
                // pawn on each file is considered a true passed pawn.
                if (passed && 0 == doubled)
                {
                    e.passedPawns[Us] |= BitBoard.SquareBB[s];
                }

                // Score this pawn
                if (isolated)
                {
                    value -= Isolated[opposed ? 1 : 0][f];
                }

                if (unsupported && !isolated)
                {
                    value -= UnsupportedPawnPenalty;
                }

                if (doubled != 0)
                {
                    value -= Types.divScore(Doubled[f], BitBoard.rank_distance(s, BitBoard.lsb(doubled)));
                }

                if (backward)
                {
                    value -= Backward[opposed ? 1 : 0][f];
                }

                if (connected)
                {
                    value += Connected[f][Types.relative_rank_square(Us, s)];
                }

                if (candidate)
                {
                    value += CandidatePassed[Types.relative_rank_square(Us, s)];

                    if (0 == doubled)
                    {
                        e.candidatePawns[Us] |= BitBoard.SquareBB[s];
                    }
                }
            }

            // In endgame it's better to have pawns on both wings. So give a bonus according
            // to file distance between left and right outermost pawns.
            if (pos.count(Us, PieceTypeS.PAWN) > 1)
            {
                b      = (Bitboard)(e.semiopenFiles[Us] ^ 0xFF);
                value += PawnsFileSpan * (BitBoard.msb(b) - BitBoard.lsb(b));
            }

            return(value);
        }
Пример #3
0
        // init_magics() computes all rook and bishop attacks at startup. Magic
        // bitboards are used to look up attacks of sliding pieces. As a reference see
        // chessprogramming.wikispaces.com/Magic+Bitboards. In particular, here we
        // use the so called "fancy" approach.
        public static void init_magics(PieceType pt, Bitboard[][] attacks, Bitboard[] magics,
                                       Bitboard[] masks, uint[] shifts, Square[] deltas, Fn index)
        {
            int[][] MagicBoosters = new int[2][] {
                new int[] { 969, 1976, 2850, 542, 2069, 2852, 1708, 164 },
                new int[] { 3101, 552, 3555, 926, 834, 26, 2131, 1117 }
            };

            RKISS rk = new RKISS();

            Bitboard[] occupancy = new UInt64[4096], reference = new UInt64[4096];
            Bitboard   edges, b;
            int        i, size, booster;

            for (Square s = SquareS.SQ_A1; s <= SquareS.SQ_H8; s++)
            {
                // Board edges are not considered in the relevant occupancies
                edges = ((BitBoard.Rank1BB | BitBoard.Rank8BB) & ~BitBoard.rank_bb_square(s)) | ((BitBoard.FileABB | BitBoard.FileHBB) & ~BitBoard.file_bb_square(s));

                // Given a square 's', the mask is the bitboard of sliding attacks from
                // 's' computed on an empty board. The index must be big enough to contain
                // all the attacks for each possible subset of the mask and so is 2 power
                // the number of 1s of the mask. Hence we deduce the size of the shift to
                // apply to the 64 or 32 bits word to get the index.
                masks[s]  = sliding_attack(deltas, s, 0) & ~edges;
                shifts[s] = 32 - (uint)Bitcount.popcount_Max15(masks[s]);

                // Use Carry-Rippler trick to enumerate all subsets of masks[s] and
                // store the corresponding sliding attack bitboard in reference[].
                b    = 0;
                size = 0;
                do
                {
                    occupancy[size] = b;
                    reference[size] = sliding_attack(deltas, s, b);
                    size++;
                    b = (b - masks[s]) & masks[s];
                } while (b != 0);

                // Set the offset for the table of the next square. We have individual
                // table sizes for each square with "Fancy Magic Bitboards".
                attacks[s] = new Bitboard[size];
                booster    = MagicBoosters[0][Types.rank_of(s)];

                // Find a magic for square 's' picking up an (almost) random number
                // until we find the one that passes the verification test.
                do
                {
                    do
                    {
                        magics[s] = rk.magic_rand(booster);
                    }while (Bitcount.popcount_Max15((magics[s] * masks[s]) >> 56) < 6);

                    Array.Clear(attacks[s], 0, size);

                    // A good magic must map every possible occupancy to an index that
                    // looks up the correct sliding attack in the attacks[s] database.
                    // Note that we build up the database for square 's' as a side
                    // effect of verifying the magic.
                    for (i = 0; i < size; i++)
                    {
                        Bitboard attack = attacks[s][index(s, occupancy[i], pt)];

                        if (attack != 0 && attack != reference[i])
                        {
                            break;
                        }

                        Debug.Assert(reference[i] != 0);

                        //attack = reference[i];
                        attacks[s][index(s, occupancy[i], pt)] = reference[i];
                    }
                } while (i != size);
            }
        }
Пример #4
0
        // evaluate_threats() assigns bonuses according to the type of attacking piece
        // and the type of attacked one.
        public static Score evaluate_threats(Position pos, EvalInfo ei, Color Us, bool Trace)
        {
            Color Them = (Us == ColorS.WHITE ? ColorS.BLACK : ColorS.WHITE);

            Bitboard b, weakEnemies;
            Score    score = ScoreS.SCORE_ZERO;

            // Enemies not defended by a pawn and under our attack
            weakEnemies = pos.pieces_color(Them)
                          & ~ei.attackedBy[Them][PieceTypeS.PAWN]
                          & ei.attackedBy[Us][PieceTypeS.ALL_PIECES];

            // Add a bonus according if the attacking pieces are minor or major
            if (weakEnemies != 0)
            {
                b = weakEnemies & (ei.attackedBy[Us][PieceTypeS.PAWN] | ei.attackedBy[Us][PieceTypeS.KNIGHT] | ei.attackedBy[Us][PieceTypeS.BISHOP]);
                if (b != 0)
                {
                    score += Threat[0][Types.type_of_piece(pos.piece_on(BitBoard.lsb(b)))];
                }

                b = weakEnemies & (ei.attackedBy[Us][PieceTypeS.ROOK] | ei.attackedBy[Us][PieceTypeS.QUEEN]);
                if (b != 0)
                {
                    score += Threat[1][Types.type_of_piece(pos.piece_on(BitBoard.lsb(b)))];
                }

                b = weakEnemies & ~ei.attackedBy[Them][PieceTypeS.ALL_PIECES];
                if (b != 0)
                {
                    score += BitBoard.more_than_one(b) ? Hanging[Us != pos.side_to_move()?1:0] * Bitcount.popcount_Max15(b)
                        : Hanging[Us == pos.side_to_move()?1:0];
                }
            }

            if (Trace)
            {
                Tracing.terms[Us][TermsS.THREAT] = score;
            }

            return(score);
        }
Пример #5
0
        // evaluate_king() assigns bonuses and penalties to a king of a given color
        public static Score evaluate_king(Position pos, EvalInfo ei, Color Us, bool Trace)
        {
            Color Them = (Us == ColorS.WHITE ? ColorS.BLACK : ColorS.WHITE);

            Bitboard undefended, b, b1, b2, safe;
            int      attackUnits;
            Square   ksq = pos.king_square(Us);

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

            // Main king safety evaluation
            if (ei.kingAttackersCount[Them] != 0)
            {
                // Find the attacked squares around the king which have no defenders
                // apart from the king itself
                undefended = ei.attackedBy[Them][PieceTypeS.ALL_PIECES]
                             & ei.attackedBy[Us][PieceTypeS.KING]
                             & ~(ei.attackedBy[Us][PieceTypeS.PAWN] | ei.attackedBy[Us][PieceTypeS.KNIGHT]
                                 | ei.attackedBy[Us][PieceTypeS.BISHOP] | ei.attackedBy[Us][PieceTypeS.ROOK]
                                 | ei.attackedBy[Us][PieceTypeS.QUEEN]);

                // Initialize the 'attackUnits' variable, which is used later on as an
                // index to the KingDanger[] 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 and the quality of
                // the pawn shelter (current 'score' value).
                attackUnits = Math.Min(20, (ei.kingAttackersCount[Them] * ei.kingAttackersWeight[Them]) / 2)
                              + 3 * (ei.kingAdjacentZoneAttacksCount[Them] + Bitcount.popcount_Max15(undefended))
                              + 2 * (ei.pinnedPieces[Us] != 0 ? 1 : 0)
                              - Types.mg_value(score) / 32;

                // Analyse the enemy's safe queen contact checks. Firstly, find the
                // undefended squares around the king that are attacked by the enemy's
                // queen...
                b = undefended & ei.attackedBy[Them][PieceTypeS.QUEEN] & ~pos.pieces_color(Them);
                if (b != 0)
                {
                    // ...and then remove squares not supported by another enemy piece
                    b &= (ei.attackedBy[Them][PieceTypeS.PAWN] | ei.attackedBy[Them][PieceTypeS.KNIGHT]
                          | ei.attackedBy[Them][PieceTypeS.BISHOP] | ei.attackedBy[Them][PieceTypeS.ROOK]);
                    if (b != 0)
                    {
                        attackUnits += QueenContactCheck
                                       * Bitcount.popcount_Max15(b)
                                       * (Them == pos.side_to_move() ? 2 : 1);
                    }
                }

                // Analyse the enemy's safe rook contact checks. Firstly, find the
                // undefended squares around the king that are attacked by the enemy's
                // rooks...
                b = undefended & ei.attackedBy[Them][PieceTypeS.ROOK] & ~pos.pieces_color(Them);

                // Consider only squares where the enemy rook gives check
                b &= BitBoard.PseudoAttacks[PieceTypeS.ROOK][ksq];

                if (b != 0)
                {
                    // ...and then remove squares not supported by another enemy piece
                    b &= (ei.attackedBy[Them][PieceTypeS.PAWN] | ei.attackedBy[Them][PieceTypeS.KNIGHT]
                          | ei.attackedBy[Them][PieceTypeS.BISHOP] | ei.attackedBy[Them][PieceTypeS.QUEEN]);

                    if (b != 0)
                    {
                        attackUnits += RookContactCheck
                                       * Bitcount.popcount_Max15(b)
                                       * (Them == pos.side_to_move() ? 2 : 1);
                    }
                }

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

                b1 = pos.attacks_from_square_piecetype(ksq, PieceTypeS.ROOK) & safe;
                b2 = pos.attacks_from_square_piecetype(ksq, PieceTypeS.BISHOP) & safe;

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

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

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

                // Enemy knights safe checks
                b = pos.attacks_from_square_piecetype(ksq, PieceTypeS.KNIGHT) & ei.attackedBy[Them][PieceTypeS.KNIGHT] & safe;
                if (b != 0)
                {
                    attackUnits += KnightCheck * Bitcount.popcount_Max15(b);
                }

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

                // Finally, extract the king danger score from the KingDanger[]
                // array and subtract the score from evaluation.
                score -= KingDanger[Us == Search.RootColor ? 1 : 0][attackUnits];
            }

            if (Trace)
            {
                Tracing.terms[Us][PieceTypeS.KING] = score;
            }

            return(score);
        }
Пример #6
0
        // evaluate_pieces() assigns bonuses and penalties to the pieces of a given color
        public static Score evaluate_pieces(Position pos, EvalInfo ei, Score[] mobility, Bitboard[] mobilityArea, PieceType Pt, Color Us, bool Trace)
        {
            if (Us == ColorS.WHITE && Pt == PieceTypeS.KING)
            {
                return(ScoreS.SCORE_ZERO);
            }

            Bitboard b;
            Square   s;
            Score    score = ScoreS.SCORE_ZERO;

            PieceType NextPt = (Us == ColorS.WHITE ? Pt : (Pt + 1));
            Color     Them   = (Us == ColorS.WHITE ? ColorS.BLACK : ColorS.WHITE);

            Square[] pl    = pos.list(Us, Pt);
            int      plPos = 0;

            ei.attackedBy[Us][Pt] = 0;

            while ((s = pl[plPos++]) != SquareS.SQ_NONE)
            {
                // Find attacked squares, including x-ray attacks for bishops and rooks
                b = Pt == PieceTypeS.BISHOP ? BitBoard.attacks_bb_SBBPT(s, pos.pieces() ^ pos.pieces_color_piecetype(Us, PieceTypeS.QUEEN), PieceTypeS.BISHOP)
                  : Pt == PieceTypeS.ROOK ? BitBoard.attacks_bb_SBBPT(s, pos.pieces() ^ pos.pieces_color_piecetype(Us, PieceTypeS.ROOK, PieceTypeS.QUEEN), PieceTypeS.ROOK)
                                    : pos.attacks_from_square_piecetype(s, Pt);

                if ((ei.pinnedPieces[Us] & BitBoard.SquareBB[s]) != 0)
                {
                    b &= BitBoard.LineBB[pos.king_square(Us)][s];
                }

                ei.attackedBy[Us][PieceTypeS.ALL_PIECES] |= ei.attackedBy[Us][Pt] |= b;

                if ((b & ei.kingRing[Them]) != 0)
                {
                    ei.kingAttackersCount[Us]++;
                    ei.kingAttackersWeight[Us] += KingAttackWeights[Pt];
                    Bitboard bb = (b & ei.attackedBy[Them][PieceTypeS.KING]);
                    if (bb != 0)
                    {
                        ei.kingAdjacentZoneAttacksCount[Us] += Bitcount.popcount_Max15(bb);
                    }
                }

                if (Pt == PieceTypeS.QUEEN)
                {
                    b &= ~(ei.attackedBy[Them][PieceTypeS.KNIGHT]
                           | ei.attackedBy[Them][PieceTypeS.BISHOP]
                           | ei.attackedBy[Them][PieceTypeS.ROOK]);
                }

                int mob = (Pt != PieceTypeS.QUEEN ? Bitcount.popcount_Max15(b & mobilityArea[Us])
                                                  : Bitcount.popcount(b & mobilityArea[Us]));

                mobility[Us] += MobilityBonus[Pt][mob];

                // Decrease score if we are attacked by an enemy pawn. The remaining part
                // of threat evaluation must be done later when we have full attack info.
                if ((ei.attackedBy[Them][PieceTypeS.PAWN] & BitBoard.SquareBB[s]) != 0)
                {
                    score -= ThreatenedByPawn[Pt];
                }

                if (Pt == PieceTypeS.BISHOP || Pt == PieceTypeS.KNIGHT)
                {
                    // Penalty for bishop with same coloured pawns
                    if (Pt == PieceTypeS.BISHOP)
                    {
                        score -= BishopPawns * ei.pi.pawns_on_same_color_squares(Us, s);
                    }

                    // Bishop and knight outposts squares
                    if (0 == (pos.pieces_color_piecetype(Them, PieceTypeS.PAWN) & BitBoard.pawn_attack_span(Us, s)))
                    {
                        score += evaluate_outposts(pos, ei, s, Pt, Us);
                    }

                    // Bishop or knight behind a pawn
                    if (Types.relative_rank_square(Us, s) < RankS.RANK_5 &&
                        (pos.pieces_piecetype(PieceTypeS.PAWN) & BitBoard.SquareBB[(s + Types.pawn_push(Us))]) != 0)
                    {
                        score += MinorBehindPawn;
                    }
                }

                if (Pt == PieceTypeS.ROOK)
                {
                    // Rook piece attacking enemy pawns on the same rank/file
                    if (Types.relative_rank_square(Us, s) >= RankS.RANK_5)
                    {
                        Bitboard pawns = pos.pieces_color_piecetype(Them, PieceTypeS.PAWN) & BitBoard.PseudoAttacks[PieceTypeS.ROOK][s];
                        if (pawns != 0)
                        {
                            score += Bitcount.popcount_Max15(pawns) * RookOnPawn;
                        }
                    }

                    // Give a bonus for a rook on a open or semi-open file
                    if (ei.pi.semiopen_file(Us, Types.file_of(s)) != 0)
                    {
                        score += ei.pi.semiopen_file(Them, Types.file_of(s)) != 0 ? RookOpenFile : RookSemiopenFile;
                    }

                    if (mob > 3 || ei.pi.semiopen_file(Us, Types.file_of(s)) != 0)
                    {
                        continue;
                    }

                    Square ksq = pos.king_square(Us);

                    // Penalize rooks which are trapped by a king. Penalize more if the
                    // king has lost its castling capability.
                    if (((Types.file_of(ksq) < FileS.FILE_E) == (Types.file_of(s) < Types.file_of(ksq))) &&
                        (Types.rank_of(ksq) == Types.rank_of(s) || Types.relative_rank_square(Us, ksq) == RankS.RANK_1) &&
                        0 == ei.pi.semiopen_side(Us, Types.file_of(ksq), Types.file_of(s) < Types.file_of(ksq)))
                    {
                        score -= (TrappedRook - Types.make_score(mob * 8, 0)) * (1 + (pos.can_castle_color(Us) == 0 ? 1 : 0));
                    }
                }

                // 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 (Pt == PieceTypeS.BISHOP &&
                    pos.is_chess960() != 0 &&
                    (s == Types.relative_square(Us, SquareS.SQ_A1) || s == Types.relative_square(Us, SquareS.SQ_H1)))
                {
                    Square d = Types.pawn_push(Us) + (Types.file_of(s) == FileS.FILE_A ? SquareS.DELTA_E : SquareS.DELTA_W);
                    if (pos.piece_on(s + d) == Types.make_piece(Us, PieceTypeS.PAWN))
                    {
                        score -= !pos.empty(s + d + Types.pawn_push(Us)) ? TrappedBishopA1H1 * 4
                            : pos.piece_on(s + d + d) == Types.make_piece(Us, PieceTypeS.PAWN) ? TrappedBishopA1H1 * 2
                                                                            : TrappedBishopA1H1;
                    }
                }
            }

            if (Trace)
            {
                Tracing.terms[Us][Pt] = score;
            }

            return(score - evaluate_pieces(pos, ei, mobility, mobilityArea, NextPt, Them, Trace));
        }