enum Tracing { NO_TRACE, TRACE };
enum Term { // The first 8 entries are reserved for PieceType
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
+ MATERIAL = 8, IMBALANCE, MOBILITY, THREAT, PASSED, SPACE, WINNABLE, TOTAL, TERM_NB
{ S(-60,-78), S(-20,-17), S( 2, 23), S( 3, 39), S( 3, 70), S( 11, 99), // Rook
S( 22,103), S( 31,121), S( 40,134), S( 40,139), S( 41,158), S( 48,164),
S( 57,168), S( 57,169), S( 62,172) },
{ S(-60,-78), S(-20,-17), S( 2, 23), S( 3, 39), S( 3, 70), S( 11, 99), // Rook
S( 22,103), S( 31,121), S( 40,134), S( 40,139), S( 41,158), S( 48,164),
S( 57,168), S( 57,169), S( 62,172) },
- { S(-34,-36), S(-15,-21), S(-10, -1), S(-10, 22), S( 20, 41), S( 23, 56), // Queen
+ { S(-30,-48), S(-12,-30), S( -8, -7), S( -9, 19), S( 20, 40), S( 23, 55), // Queen
S( 23, 59), S( 35, 75), S( 38, 78), S( 53, 96), S( 64, 96), S( 65,100),
S( 65,121), S( 66,127), S( 67,131), S( 67,133), S( 72,136), S( 72,141),
S( 77,147), S( 79,150), S( 93,151), S(108,168), S(108,168), S(108,171),
S( 23, 59), S( 35, 75), S( 38, 78), S( 53, 96), S( 64, 96), S( 65,100),
S( 65,121), S( 66,127), S( 67,131), S( 67,133), S( 72,136), S( 72,141),
S( 77,147), S( 79,150), S( 93,151), S(108,168), S(108,168), S(108,171),
// Assorted bonuses and penalties
constexpr Score BishopPawns = S( 3, 7);
// Assorted bonuses and penalties
constexpr Score BishopPawns = S( 3, 7);
constexpr Score BishopXRayPawns = S( 4, 5);
constexpr Score CorneredBishop = S( 50, 50);
constexpr Score FlankAttacks = S( 8, 0);
constexpr Score BishopXRayPawns = S( 4, 5);
constexpr Score CorneredBishop = S( 50, 50);
constexpr Score FlankAttacks = S( 8, 0);
constexpr Score PassedFile = S( 11, 8);
constexpr Score PawnlessFlank = S( 17, 95);
constexpr Score RestrictedPiece = S( 7, 7);
constexpr Score PassedFile = S( 11, 8);
constexpr Score PawnlessFlank = S( 17, 95);
constexpr Score RestrictedPiece = S( 7, 7);
constexpr Score RookOnQueenFile = S( 5, 9);
constexpr Score SliderOnQueen = S( 59, 18);
constexpr Score ThreatByKing = S( 24, 89);
constexpr Score RookOnQueenFile = S( 5, 9);
constexpr Score SliderOnQueen = S( 59, 18);
constexpr Score ThreatByKing = S( 24, 89);
template<Color Us> Score threats() const;
template<Color Us> Score passed() const;
template<Color Us> Score space() const;
template<Color Us> Score threats() const;
template<Color Us> Score passed() const;
template<Color Us> Score space() const;
mobilityArea[Us] = ~(b | pos.pieces(Us, KING, QUEEN) | pos.blockers_for_king(Us) | pe->pawn_attacks(Them));
// Initialize attackedBy[] for king and pawns
mobilityArea[Us] = ~(b | pos.pieces(Us, KING, QUEEN) | pos.blockers_for_king(Us) | pe->pawn_attacks(Them));
// Initialize attackedBy[] for king and pawns
attackedBy[Us][PAWN] = pe->pawn_attacks(Us);
attackedBy[Us][ALL_PIECES] = attackedBy[Us][KING] | attackedBy[Us][PAWN];
attackedBy2[Us] = dblAttackByPawn | (attackedBy[Us][KING] & attackedBy[Us][PAWN]);
attackedBy[Us][PAWN] = pe->pawn_attacks(Us);
attackedBy[Us][ALL_PIECES] = attackedBy[Us][KING] | attackedBy[Us][PAWN];
attackedBy2[Us] = dblAttackByPawn | (attackedBy[Us][KING] & attackedBy[Us][PAWN]);
// Init our king safety tables
Square s = make_square(Utility::clamp(file_of(ksq), FILE_B, FILE_G),
Utility::clamp(rank_of(ksq), RANK_2, RANK_7));
// Init our king safety tables
Square s = make_square(Utility::clamp(file_of(ksq), FILE_B, FILE_G),
Utility::clamp(rank_of(ksq), RANK_2, RANK_7));
kingAttackersCount[Them] = popcount(kingRing[Us] & pe->pawn_attacks(Them));
kingAttacksCount[Them] = kingAttackersWeight[Them] = 0;
kingAttackersCount[Them] = popcount(kingRing[Us] & pe->pawn_attacks(Them));
kingAttacksCount[Them] = kingAttackersWeight[Them] = 0;
// 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))
// 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))
+ else if (Pt == ROOK && (file_bb(s) & kingRing[Them]))
+ score += RookOnKingRing;
+
+ else if (Pt == BISHOP && (attacks_bb<BISHOP>(s, pos.pieces(PAWN)) & kingRing[Them]))
+ score += BishopOnKingRing;
+
* (!(attackedBy[Us][PAWN] & s) + popcount(blocked & CenterFiles));
// Penalty for all enemy pawns x-rayed
* (!(attackedBy[Us][PAWN] & s) + popcount(blocked & CenterFiles));
// Penalty for all enemy pawns x-rayed
// Bonus for bishop on a long diagonal which can "see" both center squares
if (more_than_one(attacks_bb<BISHOP>(s, pos.pieces(PAWN)) & Center))
// Bonus for bishop on a long diagonal which can "see" both center squares
if (more_than_one(attacks_bb<BISHOP>(s, pos.pieces(PAWN)) & Center))
- b = (attackedBy[Us][BISHOP] & pos.attacks_from<BISHOP>(s))
- | (attackedBy[Us][ROOK ] & pos.attacks_from<ROOK >(s));
+ b = (attackedBy[Us][BISHOP] & attacks_bb<BISHOP>(s, pos.pieces()))
+ | (attackedBy[Us][ROOK ] & attacks_bb<ROOK >(s, pos.pieces()));
int outflanking = distance<File>(pos.square<KING>(WHITE), pos.square<KING>(BLACK))
- distance<Rank>(pos.square<KING>(WHITE), pos.square<KING>(BLACK));
int outflanking = distance<File>(pos.square<KING>(WHITE), pos.square<KING>(BLACK))
- distance<Rank>(pos.square<KING>(WHITE), pos.square<KING>(BLACK));
int u = ((mg > 0) - (mg < 0)) * Utility::clamp(complexity + 50, -abs(mg), 0);
int v = ((eg > 0) - (eg < 0)) * std::max(complexity, -abs(eg));
int u = ((mg > 0) - (mg < 0)) * Utility::clamp(complexity + 50, -abs(mg), 0);
int v = ((eg > 0) - (eg < 0)) * std::max(complexity, -abs(eg));
- if (T)
- Trace::add(INITIATIVE, make_score(u, v));
-
- return make_score(u, v);
- }
-
-
- // Evaluation::scale_factor() computes the scale factor for the winning side
Color strongSide = eg > VALUE_DRAW ? WHITE : BLACK;
int sf = me->scale_factor(pos, strongSide);
Color strongSide = eg > VALUE_DRAW ? WHITE : BLACK;
int sf = me->scale_factor(pos, strongSide);
- return ScaleFactor(sf);
+ // Interpolate between the middlegame and (scaled by 'sf') endgame score
+ v = mg * int(me->game_phase())
+ + eg * int(PHASE_MIDGAME - me->game_phase()) * ScaleFactor(sf) / SCALE_FACTOR_NORMAL;
+ v /= PHASE_MIDGAME;
+
+ if (T)
+ {
+ Trace::add(WINNABLE, make_score(u, eg * ScaleFactor(sf) / SCALE_FACTOR_NORMAL - eg_value(score)));
+ Trace::add(TOTAL, make_score(mg, eg * ScaleFactor(sf) / SCALE_FACTOR_NORMAL));
+ }
+
+ return Value(v);
- score += initiative(score);
-
- // Interpolate between a middlegame and a (scaled by 'sf') endgame score
- ScaleFactor sf = scale_factor(eg_value(score));
- v = mg_value(score) * int(me->game_phase())
- + eg_value(score) * int(PHASE_MIDGAME - me->game_phase()) * sf / SCALE_FACTOR_NORMAL;
-
- v /= PHASE_MIDGAME;
+ // Derive single value from mg and eg parts of score
+ v = winnable(score);
Trace::add(IMBALANCE, me->imbalance());
Trace::add(PAWN, pe->pawn_score(WHITE), pe->pawn_score(BLACK));
Trace::add(MOBILITY, mobility[WHITE], mobility[BLACK]);
Trace::add(IMBALANCE, me->imbalance());
Trace::add(PAWN, pe->pawn_score(WHITE), pe->pawn_score(BLACK));
Trace::add(MOBILITY, mobility[WHITE], mobility[BLACK]);
- return (pos.side_to_move() == WHITE ? v : -v) + Tempo;
+ v = (pos.side_to_move() == WHITE ? v : -v) + Tempo;
+
+ // Damp down the evaluation linearly when shuffling
+ v = v * (100 - pos.rule50_count()) / 100;
+
+ return v;
<< " Threats | " << Term(THREAT)
<< " Passed | " << Term(PASSED)
<< " Space | " << Term(SPACE)
<< " Threats | " << Term(THREAT)
<< " Passed | " << Term(PASSED)
<< " Space | " << Term(SPACE)