- /// Constants and variables
-
- // Doubled pawn penalty by file, middle game
- const Value DoubledPawnMidgamePenalty[8] = {
- Value(13), Value(20), Value(23), Value(23),
- Value(23), Value(23), Value(20), Value(13)
- };
-
- // Doubled pawn penalty by file, endgame
- const Value DoubledPawnEndgamePenalty[8] = {
- Value(43), Value(48), Value(48), Value(48),
- Value(48), Value(48), Value(48), Value(43)
- };
-
- // Isolated pawn penalty by file, middle game
- const Value IsolatedPawnMidgamePenalty[8] = {
- Value(25), Value(36), Value(40), Value(40),
- Value(40), Value(40), Value(36), Value(25)
- };
-
- // Isolated pawn penalty by file, endgame
- const Value IsolatedPawnEndgamePenalty[8] = {
- Value(30), Value(35), Value(35), Value(35),
- Value(35), Value(35), Value(35), Value(30)
- };
-
- // Backward pawn penalty by file, middle game
- const Value BackwardPawnMidgamePenalty[8] = {
- Value(20), Value(29), Value(33), Value(33),
- Value(33), Value(33), Value(29), Value(20)
- };
-
- // Backward pawn penalty by file, endgame
- const Value BackwardPawnEndgamePenalty[8] = {
- Value(28), Value(31), Value(31), Value(31),
- Value(31), Value(31), Value(31), Value(28)
- };
-
- // Pawn chain membership bonus by file, middle game
- const Value ChainMidgameBonus[8] = {
- Value(11), Value(13), Value(13), Value(14),
- Value(14), Value(13), Value(13), Value(11)
- };
-
- // Pawn chain membership bonus by file, endgame
- const Value ChainEndgameBonus[8] = {
- Value(-1), Value(-1), Value(-1), Value(-1),
- Value(-1), Value(-1), Value(-1), Value(-1)
- };
-
- // Candidate passed pawn bonus by rank, middle game
- const Value CandidateMidgameBonus[8] = {
- Value( 0), Value( 6), Value(6), Value(14),
- Value(34), Value(83), Value(0), Value( 0)
- };
-
- // Candidate passed pawn bonus by rank, endgame
- const Value CandidateEndgameBonus[8] = {
- Value( 0), Value( 13), Value(13), Value(29),
- Value(68), Value(166), Value( 0), Value( 0)
- };
-
- // Pawn storm tables for positions with opposite castling
- const int QStormTable[64] = {
- 0, 0, 0, 0, 0, 0, 0, 0,
- -22,-22,-22,-14,-6, 0, 0, 0,
- -6,-10,-10,-10,-6, 0, 0, 0,
- 4, 12, 16, 12, 4, 0, 0, 0,
- 16, 23, 23, 16, 0, 0, 0, 0,
- 23, 31, 31, 23, 0, 0, 0, 0,
- 23, 31, 31, 23, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0
- };
-
- const int KStormTable[64] = {
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0,-10,-19,-28,-33,-33,
- 0, 0, 0,-10,-15,-19,-24,-24,
- 0, 0, 0, 0, 1, 1, 1, 1,
- 0, 0, 0, 0, 1, 10, 19, 19,
- 0, 0, 0, 0, 1, 19, 31, 27,
- 0, 0, 0, 0, 0, 22, 31, 22,
- 0, 0, 0, 0, 0, 0, 0, 0
- };
-
- // Pawn storm open file bonuses by file
- const int16_t KStormOpenFileBonus[8] = { 31, 31, 18, 0, 0, 0, 0, 0 };
- const int16_t QStormOpenFileBonus[8] = { 0, 0, 0, 0, 0, 26, 42, 26 };
-
- // Pawn storm lever bonuses by file
- const int StormLeverBonus[8] = { -8, -8, -13, 0, 0, -13, -8, -8 };
-
-}
+ #define V Value
+ #define S(mg, eg) make_score(mg, eg)
+
+ // Isolated pawn penalty by opposed flag
+ const Score Isolated[2] = { S(45, 40), S(30, 27) };
+
+ // Backward pawn penalty by opposed flag
+ const Score Backward[2] = { S(56, 33), S(41, 19) };
+
+ // Unsupported pawn penalty for pawns which are neither isolated or backward,
+ // by number of pawns it supports [less than 2 / exactly 2].
+ const Score Unsupported[2] = { S(17, 8), S(21, 12) };
+
+ // Connected pawn bonus by opposed, phalanx, twice supported and rank
+ Score Connected[2][2][2][RANK_NB];
+
+ // Doubled pawn penalty by file
+ const Score Doubled[FILE_NB] = {
+ S(11, 34), S(17, 38), S(19, 38), S(19, 38),
+ S(19, 38), S(19, 38), S(17, 38), S(11, 34) };
+
+ // Lever bonus by rank
+ const Score Lever[RANK_NB] = {
+ S( 0, 0), S( 0, 0), S(0, 0), S(0, 0),
+ S(17, 16), S(33, 32), S(0, 0), S(0, 0) };
+
+ // Weakness of our pawn shelter in front of the king by [distance from edge][rank]
+ const Value ShelterWeakness[][RANK_NB] = {
+ { V( 97), V(21), V(26), V(51), V(87), V( 89), V( 99) },
+ { V(120), V( 0), V(28), V(76), V(88), V(103), V(104) },
+ { V(101), V( 7), V(54), V(78), V(77), V( 92), V(101) },
+ { V( 80), V(11), V(44), V(68), V(87), V( 90), V(119) } };
+
+ // Danger of enemy pawns moving toward our king by [type][distance from edge][rank]
+ const Value StormDanger[][4][RANK_NB] = {
+ { { V( 0), V( 67), V( 134), V(38), V(32) },
+ { V( 0), V( 57), V( 139), V(37), V(22) },
+ { V( 0), V( 43), V( 115), V(43), V(27) },
+ { V( 0), V( 68), V( 124), V(57), V(32) } },
+ { { V(20), V( 43), V( 100), V(56), V(20) },
+ { V(23), V( 20), V( 98), V(40), V(15) },
+ { V(23), V( 39), V( 103), V(36), V(18) },
+ { V(28), V( 19), V( 108), V(42), V(26) } },
+ { { V( 0), V( 0), V( 75), V(14), V( 2) },
+ { V( 0), V( 0), V( 150), V(30), V( 4) },
+ { V( 0), V( 0), V( 160), V(22), V( 5) },
+ { V( 0), V( 0), V( 166), V(24), V(13) } },
+ { { V( 0), V(-283), V(-281), V(57), V(31) },
+ { V( 0), V( 58), V( 141), V(39), V(18) },
+ { V( 0), V( 65), V( 142), V(48), V(32) },
+ { V( 0), V( 60), V( 126), V(51), V(19) } } };
+
+ // Max bonus for king safety. Corresponds to start position with all the pawns
+ // in front of the king and no enemy pawn on the horizon.
+ const Value MaxSafetyBonus = V(258);
+
+ #undef S
+ #undef V
+
+ template<Color Us>
+ Score evaluate(const Position& pos, Pawns::Entry* e) {
+
+ const Color Them = (Us == WHITE ? BLACK : WHITE);
+ const Square Up = (Us == WHITE ? DELTA_N : DELTA_S);
+ const Square Right = (Us == WHITE ? DELTA_NE : DELTA_SW);
+ const Square Left = (Us == WHITE ? DELTA_NW : DELTA_SE);
+
+ Bitboard b, neighbours, stoppers, doubled, supported, phalanx;
+ Square s;
+ bool opposed, lever, connected, backward;
+ Score score = SCORE_ZERO;
+ const Square* pl = pos.squares<PAWN>(Us);
+ const Bitboard* pawnAttacksBB = StepAttacksBB[make_piece(Us, PAWN)];
+
+ Bitboard ourPawns = pos.pieces(Us , PAWN);
+ Bitboard theirPawns = pos.pieces(Them, PAWN);
+
+ e->passedPawns[Us] = e->pawnAttacksSpan[Us] = 0;
+ e->kingSquares[Us] = SQ_NONE;
+ e->semiopenFiles[Us] = 0xFF;
+ e->pawnAttacks[Us] = shift_bb<Right>(ourPawns) | shift_bb<Left>(ourPawns);
+ e->pawnsOnSquares[Us][BLACK] = popcount(ourPawns & DarkSquares);
+ e->pawnsOnSquares[Us][WHITE] = pos.count<PAWN>(Us) - e->pawnsOnSquares[Us][BLACK];
+
+ // Loop through all pawns of the current color and score each pawn
+ while ((s = *pl++) != SQ_NONE)
+ {
+ assert(pos.piece_on(s) == make_piece(Us, PAWN));
+
+ File f = file_of(s);
+
+ e->semiopenFiles[Us] &= ~(1 << f);
+ e->pawnAttacksSpan[Us] |= pawn_attack_span(Us, s);
+
+ // Flag the pawn
+ opposed = theirPawns & forward_bb(Us, s);
+ stoppers = theirPawns & passed_pawn_mask(Us, s);
+ lever = theirPawns & pawnAttacksBB[s];
+ doubled = ourPawns & forward_bb(Us, s);
+ neighbours = ourPawns & adjacent_files_bb(f);
+ phalanx = neighbours & rank_bb(s);
+ supported = neighbours & rank_bb(s - Up);
+ connected = supported | phalanx;
+
+ // A pawn is backward when it is behind all pawns of the same color on the
+ // adjacent files and cannot be safely advanced.
+ if (!neighbours || lever || relative_rank(Us, s) >= RANK_5)
+ backward = false;
+ else
+ {
+ // Find the backmost rank with neighbours or stoppers
+ b = rank_bb(backmost_sq(Us, neighbours | stoppers));
+
+ // The pawn is backward when it cannot safely progress to that rank:
+ // either there is a stopper in the way on this rank, or there is a
+ // stopper on adjacent file which controls the way to that rank.
+ backward = (b | shift_bb<Up>(b & adjacent_files_bb(f))) & stoppers;
+
+ assert(!backward || !(pawn_attack_span(Them, s + Up) & neighbours));
+ }
+
+ // Passed pawns will be properly scored in evaluation because we need
+ // full attack info to evaluate them. Only the frontmost passed
+ // pawn on each file is considered a true passed pawn.
+ if (!(stoppers | doubled))
+ e->passedPawns[Us] |= s;
+
+ // Score this pawn
+ if (!neighbours)
+ score -= Isolated[opposed];
+
+ else if (backward)
+ score -= Backward[opposed];
+
+ else if (!supported)
+ score -= Unsupported[more_than_one(neighbours & pawnAttacksBB[s])];
+
+ if (connected)
+ score += Connected[opposed][!!phalanx][more_than_one(supported)][relative_rank(Us, s)];
+
+ if (doubled)
+ score -= Doubled[f] / distance<Rank>(s, frontmost_sq(Us, doubled));
+
+ if (lever)
+ score += Lever[relative_rank(Us, s)];
+ }
+
+ b = e->semiopenFiles[Us] ^ 0xFF;
+ e->pawnSpan[Us] = b ? int(msb(b) - lsb(b)) : 0;
+
+ return score;
+ }