-
-namespace Trace {
-
- enum Tracing { NO_TRACE, TRACE };
-
- enum Term { // The first 8 entries are reserved for PieceType
- MATERIAL = 8, IMBALANCE, MOBILITY, THREAT, PASSED, SPACE, INITIATIVE, TOTAL, TERM_NB
- };
-
- Score scores[TERM_NB][COLOR_NB];
-
- double to_cp(Value v) { return double(v) / PawnValueEg; }
-
- void add(int idx, Color c, Score s) {
- scores[idx][c] = s;
- }
-
- void add(int idx, Score w, Score b = SCORE_ZERO) {
- scores[idx][WHITE] = w;
- scores[idx][BLACK] = b;
- }
-
- std::ostream& operator<<(std::ostream& os, Score s) {
- os << std::setw(5) << to_cp(mg_value(s)) << " "
- << std::setw(5) << to_cp(eg_value(s));
- return os;
- }
-
- std::ostream& operator<<(std::ostream& os, Term t) {
-
- if (t == MATERIAL || t == IMBALANCE || t == INITIATIVE || t == TOTAL)
- os << " ---- ----" << " | " << " ---- ----";
- else
- os << scores[t][WHITE] << " | " << scores[t][BLACK];
-
- os << " | " << scores[t][WHITE] - scores[t][BLACK] << "\n";
- return os;
- }
-}
-
-using namespace Trace;
-
-namespace {
-
- constexpr Bitboard QueenSide = FileABB | FileBBB | FileCBB | FileDBB;
- constexpr Bitboard CenterFiles = FileCBB | FileDBB | FileEBB | FileFBB;
- constexpr Bitboard KingSide = FileEBB | FileFBB | FileGBB | FileHBB;
- constexpr Bitboard Center = (FileDBB | FileEBB) & (Rank4BB | Rank5BB);
-
- constexpr Bitboard KingFlank[FILE_NB] = {
- QueenSide ^ FileDBB, QueenSide, QueenSide,
- CenterFiles, CenterFiles,
- KingSide, KingSide, KingSide ^ FileEBB
- };
-
- // Threshold for lazy and space evaluation
- constexpr Value LazyThreshold = Value(1500);
- constexpr Value SpaceThreshold = Value(12222);
-
- // KingAttackWeights[PieceType] contains king attack weights by piece type
- constexpr int KingAttackWeights[PIECE_TYPE_NB] = { 0, 0, 77, 55, 44, 10 };
-
- // Penalties for enemy's safe checks
- constexpr int QueenSafeCheck = 780;
- constexpr int RookSafeCheck = 880;
- constexpr int BishopSafeCheck = 435;
- constexpr int KnightSafeCheck = 790;
-
-#define S(mg, eg) make_score(mg, eg)
-
- // MobilityBonus[PieceType-2][attacked] contains bonuses for middle and end game,
- // indexed by piece type and number of attacked squares in the mobility area.
- constexpr Score MobilityBonus[][32] = {
- { S(-62,-81), S(-53,-56), S(-12,-30), S( -4,-14), S( 3, 8), S( 13, 15), // Knights
- S( 22, 23), S( 28, 27), S( 33, 33) },
- { S(-48,-59), S(-20,-23), S( 16, -3), S( 26, 13), S( 38, 24), S( 51, 42), // Bishops
- S( 55, 54), S( 63, 57), S( 63, 65), S( 68, 73), S( 81, 78), S( 81, 86),
- S( 91, 88), S( 98, 97) },
- { S(-58,-76), S(-27,-18), S(-15, 28), S(-10, 55), S( -5, 69), S( -2, 82), // Rooks
- S( 9,112), S( 16,118), S( 30,132), S( 29,142), S( 32,155), S( 38,165),
- S( 46,166), S( 48,169), S( 58,171) },
- { S(-39,-36), S(-21,-15), S( 3, 8), S( 3, 18), S( 14, 34), S( 22, 54), // Queens
- S( 28, 61), S( 41, 73), S( 43, 79), S( 48, 92), S( 56, 94), S( 60,104),
- S( 60,113), S( 66,120), S( 67,123), S( 70,126), S( 71,133), S( 73,136),
- S( 79,140), S( 88,143), S( 88,148), S( 99,166), S(102,170), S(102,175),
- S(106,184), S(109,191), S(113,206), S(116,212) }
- };
-
- // Outpost[knight/bishop][supported by pawn] contains bonuses for minor
- // pieces if they occupy or can reach an outpost square, bigger if that
- // square is supported by a pawn.
- constexpr Score Outpost[][2] = {
- { S(22, 6), S(36,12) }, // Knight
- { S( 9, 2), S(15, 5) } // Bishop
- };
-
- // RookOnFile[semiopen/open] contains bonuses for each rook when there is
- // no (friendly) pawn on the rook file.
- constexpr Score RookOnFile[] = { S(18, 7), S(44, 20) };
-
- // ThreatByMinor/ByRook[attacked PieceType] contains bonuses according to
- // which piece type attacks which one. Attacks on lesser pieces which are
- // pawn-defended are not considered.
- constexpr Score ThreatByMinor[PIECE_TYPE_NB] = {
- S(0, 0), S(0, 31), S(39, 42), S(57, 44), S(68, 112), S(62, 120)
- };
-
- constexpr Score ThreatByRook[PIECE_TYPE_NB] = {
- S(0, 0), S(0, 24), S(38, 71), S(38, 61), S(0, 38), S(51, 38)
- };
-
- // PassedRank[Rank] contains a bonus according to the rank of a passed pawn
- constexpr Score PassedRank[RANK_NB] = {
- S(0, 0), S(5, 18), S(12, 23), S(10, 31), S(57, 62), S(163, 167), S(271, 250)
- };
-
- // PassedFile[File] contains a bonus according to the file of a passed pawn
- constexpr Score PassedFile[FILE_NB] = {
- S( -1, 7), S( 0, 9), S(-9, -8), S(-30,-14),
- S(-30,-14), S(-9, -8), S( 0, 9), S( -1, 7)
- };
-
- // Assorted bonuses and penalties
- constexpr Score BishopPawns = S( 3, 7);
- constexpr Score CloseEnemies = S( 8, 0);
- constexpr Score CorneredBishop = S( 50, 50);
- constexpr Score Hanging = S( 69, 36);
- constexpr Score KingProtector = S( 7, 8);
- constexpr Score KnightOnQueen = S( 16, 12);
- constexpr Score LongDiagonalBishop = S( 45, 0);
- constexpr Score MinorBehindPawn = S( 18, 3);
- constexpr Score PawnlessFlank = S( 17, 95);
- constexpr Score RestrictedPiece = S( 7, 7);
- constexpr Score RookOnPawn = S( 10, 32);
- constexpr Score SliderOnQueen = S( 59, 18);
- constexpr Score ThreatByKing = S( 24, 89);
- constexpr Score ThreatByPawnPush = S( 48, 39);
- constexpr Score ThreatByRank = S( 13, 0);
- constexpr Score ThreatBySafePawn = S(173, 94);
- constexpr Score TrappedRook = S( 96, 4);
- constexpr Score WeakQueen = S( 49, 15);
- constexpr Score WeakUnopposedPawn = S( 12, 23);
-
-#undef S
-
- // Evaluation class computes and stores attacks tables and other working data
- template<Tracing T>
- class Evaluation {
-
- public:
- Evaluation() = delete;
- explicit Evaluation(const Position& p) : pos(p) {}
- Evaluation& operator=(const Evaluation&) = delete;
- Value value();
-
- private:
- template<Color Us> void initialize();
- template<Color Us, PieceType Pt> Score pieces();
- template<Color Us> Score king() const;
- template<Color Us> Score threats() const;
- template<Color Us> Score passed() const;
- template<Color Us> Score space() const;
- ScaleFactor scale_factor(Value eg) const;
- Score initiative(Value eg) const;
-
- const Position& pos;
- Material::Entry* me;
- Pawns::Entry* pe;
- Bitboard mobilityArea[COLOR_NB];
- Score mobility[COLOR_NB] = { SCORE_ZERO, SCORE_ZERO };
-
- // attackedBy[color][piece type] is a bitboard representing all squares
- // attacked by a given color and piece type. Special "piece types" which
- // is also calculated is ALL_PIECES.
- Bitboard attackedBy[COLOR_NB][PIECE_TYPE_NB];
-
- // attackedBy2[color] are the squares attacked by 2 pieces of a given color,
- // possibly via x-ray or by one pawn and one piece. Diagonal x-ray through
- // pawn or squares attacked by 2 pawns are not explicitly added.
- Bitboard attackedBy2[COLOR_NB];
-
- // kingRing[color] are the squares adjacent to the king, plus (only for a
- // king on its first rank) the squares two ranks in front. For instance,
- // if black's king is on g8, kingRing[BLACK] is f8, h8, f7, g7, h7, f6, g6
- // and h6.
- Bitboard kingRing[COLOR_NB];
-
- // kingAttackersCount[color] is the number of pieces of the given color
- // which attack a square in the kingRing of the enemy king.
- int kingAttackersCount[COLOR_NB];
-
- // kingAttackersWeight[color] is the sum of the "weights" of the pieces of
- // the given color which attack a square in the kingRing of the enemy king.
- // The weights of the individual piece types are given by the elements in
- // the KingAttackWeights array.
- int kingAttackersWeight[COLOR_NB];
-
- // kingAttacksCount[color] is the number of attacks by the given color to
- // squares directly adjacent to the enemy king. Pieces which attack more
- // than one square are counted multiple times. For instance, if there is
- // a white knight on g5 and black's king is on g8, this white knight adds 2
- // to kingAttacksCount[WHITE].
- int kingAttacksCount[COLOR_NB];
- };
-
-
- // Evaluation::initialize() computes king and pawn attacks, and the king ring
- // bitboard for a given color. This is done at the beginning of the evaluation.
- template<Tracing T> template<Color Us>
- void Evaluation<T>::initialize() {
-
- constexpr Color Them = (Us == WHITE ? BLACK : WHITE);
- constexpr Direction Up = (Us == WHITE ? NORTH : SOUTH);
- constexpr Direction Down = (Us == WHITE ? SOUTH : NORTH);
- constexpr Bitboard LowRanks = (Us == WHITE ? Rank2BB | Rank3BB: Rank7BB | Rank6BB);
-
- // Find our pawns that are blocked or on the first two ranks
- Bitboard b = pos.pieces(Us, PAWN) & (shift<Down>(pos.pieces()) | LowRanks);
-
- // Squares occupied by those pawns, by our king or queen, or controlled by enemy pawns
- // are excluded from the mobility area.
- mobilityArea[Us] = ~(b | pos.pieces(Us, KING, QUEEN) | pe->pawn_attacks(Them));
-
- // Initialise attackedBy bitboards for kings and pawns
- attackedBy[Us][KING] = pos.attacks_from<KING>(pos.square<KING>(Us));
- attackedBy[Us][PAWN] = pe->pawn_attacks(Us);
- attackedBy[Us][ALL_PIECES] = attackedBy[Us][KING] | attackedBy[Us][PAWN];
- attackedBy2[Us] = attackedBy[Us][KING] & attackedBy[Us][PAWN];
-
- // Init our king safety tables
- kingRing[Us] = attackedBy[Us][KING];
- if (relative_rank(Us, pos.square<KING>(Us)) == RANK_1)
- kingRing[Us] |= shift<Up>(kingRing[Us]);
-
- if (file_of(pos.square<KING>(Us)) == FILE_H)
- kingRing[Us] |= shift<WEST>(kingRing[Us]);
-
- else if (file_of(pos.square<KING>(Us)) == FILE_A)
- kingRing[Us] |= shift<EAST>(kingRing[Us]);
-
- kingAttackersCount[Them] = popcount(kingRing[Us] & pe->pawn_attacks(Them));
- kingRing[Us] &= ~double_pawn_attacks_bb<Us>(pos.pieces(Us, PAWN));
- kingAttacksCount[Them] = kingAttackersWeight[Them] = 0;
- }
-
-
- // Evaluation::pieces() scores pieces of a given color and type
- template<Tracing T> template<Color Us, PieceType Pt>
- Score Evaluation<T>::pieces() {
-
- constexpr Color Them = (Us == WHITE ? BLACK : WHITE);
- constexpr Direction Down = (Us == WHITE ? SOUTH : NORTH);
- constexpr Bitboard OutpostRanks = (Us == WHITE ? Rank4BB | Rank5BB | Rank6BB
- : Rank5BB | Rank4BB | Rank3BB);
- const Square* pl = pos.squares<Pt>(Us);
-
- Bitboard b, bb;
- Square s;
- Score score = SCORE_ZERO;
-
- attackedBy[Us][Pt] = 0;
-
- while ((s = *pl++) != SQ_NONE)
- {
- // Find attacked squares, including x-ray attacks for bishops and rooks
- b = Pt == BISHOP ? attacks_bb<BISHOP>(s, pos.pieces() ^ pos.pieces(QUEEN))
- : Pt == ROOK ? attacks_bb< ROOK>(s, pos.pieces() ^ pos.pieces(QUEEN) ^ pos.pieces(Us, ROOK))
- : pos.attacks_from<Pt>(s);
-
- if (pos.blockers_for_king(Us) & s)
- b &= LineBB[pos.square<KING>(Us)][s];
-
- attackedBy2[Us] |= attackedBy[Us][ALL_PIECES] & b;
- attackedBy[Us][Pt] |= b;
- attackedBy[Us][ALL_PIECES] |= b;
-
- if (b & kingRing[Them])