425ba6f8faead8b61e22d6713d815c5d3624b962
[stockfish] / src / evaluate.cpp
1 /*
2   Stockfish, a UCI chess playing engine derived from Glaurung 2.1
3   Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file)
4
5   Stockfish is free software: you can redistribute it and/or modify
6   it under the terms of the GNU General Public License as published by
7   the Free Software Foundation, either version 3 of the License, or
8   (at your option) any later version.
9
10   Stockfish is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   GNU General Public License for more details.
14
15   You should have received a copy of the GNU General Public License
16   along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include <algorithm>
20 #include <cassert>
21 #include <cstdlib>
22 #include <cstring>   // For std::memset
23 #include <fstream>
24 #include <iomanip>
25 #include <sstream>
26 #include <iostream>
27 #include <streambuf>
28 #include <vector>
29
30 #include "bitboard.h"
31 #include "evaluate.h"
32 #include "material.h"
33 #include "misc.h"
34 #include "pawns.h"
35 #include "thread.h"
36 #include "uci.h"
37 #include "incbin/incbin.h"
38
39
40 // Macro to embed the default NNUE file data in the engine binary (using incbin.h, by Dale Weiler).
41 // This macro invocation will declare the following three variables
42 //     const unsigned char        gEmbeddedNNUEData[];  // a pointer to the embedded data
43 //     const unsigned char *const gEmbeddedNNUEEnd;     // a marker to the end
44 //     const unsigned int         gEmbeddedNNUESize;    // the size of the embedded file
45 // Note that this does not work in Microsof Visual Studio.
46 #if !defined(_MSC_VER) && !defined(NNUE_EMBEDDING_OFF)
47   INCBIN(EmbeddedNNUE, EvalFileDefaultName);
48 #else
49   const unsigned char        gEmbeddedNNUEData[1] = {0x0};
50   const unsigned char *const gEmbeddedNNUEEnd = &gEmbeddedNNUEData[1];
51   const unsigned int         gEmbeddedNNUESize = 1;
52 #endif
53
54
55 using namespace std;
56 using namespace Eval::NNUE;
57
58 namespace Eval {
59
60   bool useNNUE;
61   string eval_file_loaded = "None";
62
63   /// NNUE::init() tries to load a nnue network at startup time, or when the engine
64   /// receives a UCI command "setoption name EvalFile value nn-[a-z0-9]{12}.nnue"
65   /// The name of the nnue network is always retrieved from the EvalFile option.
66   /// We search the given network in three locations: internally (the default
67   /// network may be embedded in the binary), in the active working directory and
68   /// in the engine directory. Distro packagers may define the DEFAULT_NNUE_DIRECTORY
69   /// variable to have the engine search in a special directory in their distro.
70
71   void NNUE::init() {
72
73     useNNUE = Options["Use NNUE"];
74     if (!useNNUE)
75         return;
76
77     string eval_file = string(Options["EvalFile"]);
78
79     #if defined(DEFAULT_NNUE_DIRECTORY)
80     #define stringify2(x) #x
81     #define stringify(x) stringify2(x)
82     vector<string> dirs = { "<internal>" , "" , CommandLine::binaryDirectory , stringify(DEFAULT_NNUE_DIRECTORY) };
83     #else
84     vector<string> dirs = { "<internal>" , "" , CommandLine::binaryDirectory };
85     #endif
86
87     for (string directory : dirs)
88         if (eval_file_loaded != eval_file)
89         {
90             if (directory != "<internal>")
91             {
92                 ifstream stream(directory + eval_file, ios::binary);
93                 if (load_eval(eval_file, stream))
94                     eval_file_loaded = eval_file;
95             }
96
97             if (directory == "<internal>" && eval_file == EvalFileDefaultName)
98             {
99                 // C++ way to prepare a buffer for a memory stream
100                 class MemoryBuffer : public basic_streambuf<char> {
101                     public: MemoryBuffer(char* p, size_t n) { setg(p, p, p + n); setp(p, p + n); }
102                 };
103
104                 MemoryBuffer buffer(const_cast<char*>(reinterpret_cast<const char*>(gEmbeddedNNUEData)),
105                                     size_t(gEmbeddedNNUESize));
106
107                 istream stream(&buffer);
108                 if (load_eval(eval_file, stream))
109                     eval_file_loaded = eval_file;
110             }
111         }
112   }
113
114   /// NNUE::verify() verifies that the last net used was loaded successfully
115   void NNUE::verify() {
116
117     string eval_file = string(Options["EvalFile"]);
118
119     if (useNNUE && eval_file_loaded != eval_file)
120     {
121         UCI::OptionsMap defaults;
122         UCI::init(defaults);
123
124         string msg1 = "If the UCI option \"Use NNUE\" is set to true, network evaluation parameters compatible with the engine must be available.";
125         string msg2 = "The option is set to true, but the network file " + eval_file + " was not loaded successfully.";
126         string msg3 = "The UCI option EvalFile might need to specify the full path, including the directory name, to the network file.";
127         string msg4 = "The default net can be downloaded from: https://tests.stockfishchess.org/api/nn/" + string(defaults["EvalFile"]);
128         string msg5 = "The engine will be terminated now.";
129
130         sync_cout << "info string ERROR: " << msg1 << sync_endl;
131         sync_cout << "info string ERROR: " << msg2 << sync_endl;
132         sync_cout << "info string ERROR: " << msg3 << sync_endl;
133         sync_cout << "info string ERROR: " << msg4 << sync_endl;
134         sync_cout << "info string ERROR: " << msg5 << sync_endl;
135
136         exit(EXIT_FAILURE);
137     }
138
139     if (useNNUE)
140         sync_cout << "info string NNUE evaluation using " << eval_file << " enabled" << sync_endl;
141     else
142         sync_cout << "info string classical evaluation enabled" << sync_endl;
143   }
144 }
145
146 namespace Trace {
147
148   enum Tracing { NO_TRACE, TRACE };
149
150   enum Term { // The first 8 entries are reserved for PieceType
151     MATERIAL = 8, IMBALANCE, MOBILITY, THREAT, PASSED, SPACE, WINNABLE, TOTAL, TERM_NB
152   };
153
154   Score scores[TERM_NB][COLOR_NB];
155
156   double to_cp(Value v) { return double(v) / PawnValueEg; }
157
158   void add(int idx, Color c, Score s) {
159     scores[idx][c] = s;
160   }
161
162   void add(int idx, Score w, Score b = SCORE_ZERO) {
163     scores[idx][WHITE] = w;
164     scores[idx][BLACK] = b;
165   }
166
167   std::ostream& operator<<(std::ostream& os, Score s) {
168     os << std::setw(5) << to_cp(mg_value(s)) << " "
169        << std::setw(5) << to_cp(eg_value(s));
170     return os;
171   }
172
173   std::ostream& operator<<(std::ostream& os, Term t) {
174
175     if (t == MATERIAL || t == IMBALANCE || t == WINNABLE || t == TOTAL)
176         os << " ----  ----"    << " | " << " ----  ----";
177     else
178         os << scores[t][WHITE] << " | " << scores[t][BLACK];
179
180     os << " | " << scores[t][WHITE] - scores[t][BLACK] << "\n";
181     return os;
182   }
183 }
184
185 using namespace Trace;
186
187 namespace {
188
189   // Threshold for lazy and space evaluation
190   constexpr Value LazyThreshold1 =  Value(1400);
191   constexpr Value LazyThreshold2 =  Value(1300);
192   constexpr Value SpaceThreshold = Value(12222);
193   constexpr Value NNUEThreshold1 =   Value(550);
194   constexpr Value NNUEThreshold2 =   Value(150);
195
196   // KingAttackWeights[PieceType] contains king attack weights by piece type
197   constexpr int KingAttackWeights[PIECE_TYPE_NB] = { 0, 0, 81, 52, 44, 10 };
198
199   // SafeCheck[PieceType][single/multiple] contains safe check bonus by piece type,
200   // higher if multiple safe checks are possible for that piece type.
201   constexpr int SafeCheck[][2] = {
202       {}, {}, {803, 1292}, {639, 974}, {1087, 1878}, {759, 1132}
203   };
204
205 #define S(mg, eg) make_score(mg, eg)
206
207   // MobilityBonus[PieceType-2][attacked] contains bonuses for middle and end game,
208   // indexed by piece type and number of attacked squares in the mobility area.
209   constexpr Score MobilityBonus[][32] = {
210     { S(-62,-79), S(-53,-57), S(-12,-31), S( -3,-17), S(  3,  7), S( 12, 13), // Knight
211       S( 21, 16), S( 28, 21), S( 37, 26) },
212     { S(-47,-59), S(-20,-25), S( 14, -8), S( 29, 12), S( 39, 21), S( 53, 40), // Bishop
213       S( 53, 56), S( 60, 58), S( 62, 65), S( 69, 72), S( 78, 78), S( 83, 87),
214       S( 91, 88), S( 96, 98) },
215     { S(-61,-82), S(-20,-17), S(  2, 23) ,S(  3, 40), S(  4, 72), S( 11,100), // Rook
216       S( 22,104), S( 31,120), S( 39,134), S(40 ,138), S( 41,158), S( 47,163),
217       S( 59,168), S( 60,169), S( 64,173) },
218     { S(-29,-49), S(-16,-29), S( -8, -8), S( -8, 17), S( 18, 39), S( 25, 54), // Queen
219       S( 23, 59), S( 37, 73), S( 41, 76), S( 54, 95), S( 65, 95) ,S( 68,101),
220       S( 69,124), S( 70,128), S( 70,132), S( 70,133) ,S( 71,136), S( 72,140),
221       S( 74,147), S( 76,149), S( 90,153), S(104,169), S(105,171), S(106,171),
222       S(112,178), S(114,185), S(114,187), S(119,221) }
223   };
224
225   // KingProtector[knight/bishop] contains penalty for each distance unit to own king
226   constexpr Score KingProtector[] = { S(8, 9), S(6, 9) };
227
228   // Outpost[knight/bishop] contains bonuses for each knight or bishop occupying a
229   // pawn protected square on rank 4 to 6 which is also safe from a pawn attack.
230   constexpr Score Outpost[] = { S(56, 34), S(31, 23) };
231
232   // PassedRank[Rank] contains a bonus according to the rank of a passed pawn
233   constexpr Score PassedRank[RANK_NB] = {
234     S(0, 0), S(9, 28), S(15, 31), S(17, 39), S(64, 70), S(171, 177), S(277, 260)
235   };
236
237   // RookOnFile[semiopen/open] contains bonuses for each rook when there is
238   // no (friendly) pawn on the rook file.
239   constexpr Score RookOnFile[] = { S(19, 7), S(48, 27) };
240
241   // ThreatByMinor/ByRook[attacked PieceType] contains bonuses according to
242   // which piece type attacks which one. Attacks on lesser pieces which are
243   // pawn-defended are not considered.
244   constexpr Score ThreatByMinor[PIECE_TYPE_NB] = {
245     S(0, 0), S(5, 32), S(55, 41), S(77, 56), S(89, 119), S(79, 162)
246   };
247
248   constexpr Score ThreatByRook[PIECE_TYPE_NB] = {
249     S(0, 0), S(3, 44), S(37, 68), S(42, 60), S(0, 39), S(58, 43)
250   };
251
252   // Assorted bonuses and penalties
253   constexpr Score BadOutpost          = S( -7, 36);
254   constexpr Score BishopOnKingRing    = S( 24,  0);
255   constexpr Score BishopPawns         = S(  3,  7);
256   constexpr Score BishopXRayPawns     = S(  4,  5);
257   constexpr Score CorneredBishop      = S( 50, 50);
258   constexpr Score FlankAttacks        = S(  8,  0);
259   constexpr Score Hanging             = S( 69, 36);
260   constexpr Score KnightOnQueen       = S( 16, 11);
261   constexpr Score LongDiagonalBishop  = S( 45,  0);
262   constexpr Score MinorBehindPawn     = S( 18,  3);
263   constexpr Score PassedFile          = S( 11,  8);
264   constexpr Score PawnlessFlank       = S( 17, 95);
265   constexpr Score ReachableOutpost    = S( 31, 22);
266   constexpr Score RestrictedPiece     = S(  7,  7);
267   constexpr Score RookOnKingRing      = S( 16,  0);
268   constexpr Score SliderOnQueen       = S( 60, 18);
269   constexpr Score ThreatByKing        = S( 24, 89);
270   constexpr Score ThreatByPawnPush    = S( 48, 39);
271   constexpr Score ThreatBySafePawn    = S(173, 94);
272   constexpr Score TrappedRook         = S( 55, 13);
273   constexpr Score WeakQueenProtection = S( 14,  0);
274   constexpr Score WeakQueen           = S( 56, 15);
275
276
277 #undef S
278
279   // Evaluation class computes and stores attacks tables and other working data
280   template<Tracing T>
281   class Evaluation {
282
283   public:
284     Evaluation() = delete;
285     explicit Evaluation(const Position& p) : pos(p) {}
286     Evaluation& operator=(const Evaluation&) = delete;
287     Value value();
288
289   private:
290     template<Color Us> void initialize();
291     template<Color Us, PieceType Pt> Score pieces();
292     template<Color Us> Score king() const;
293     template<Color Us> Score threats() const;
294     template<Color Us> Score passed() const;
295     template<Color Us> Score space() const;
296     Value winnable(Score score) const;
297
298     const Position& pos;
299     Material::Entry* me;
300     Pawns::Entry* pe;
301     Bitboard mobilityArea[COLOR_NB];
302     Score mobility[COLOR_NB] = { SCORE_ZERO, SCORE_ZERO };
303
304     // attackedBy[color][piece type] is a bitboard representing all squares
305     // attacked by a given color and piece type. Special "piece types" which
306     // is also calculated is ALL_PIECES.
307     Bitboard attackedBy[COLOR_NB][PIECE_TYPE_NB];
308
309     // attackedBy2[color] are the squares attacked by at least 2 units of a given
310     // color, including x-rays. But diagonal x-rays through pawns are not computed.
311     Bitboard attackedBy2[COLOR_NB];
312
313     // kingRing[color] are the squares adjacent to the king plus some other
314     // very near squares, depending on king position.
315     Bitboard kingRing[COLOR_NB];
316
317     // kingAttackersCount[color] is the number of pieces of the given color
318     // which attack a square in the kingRing of the enemy king.
319     int kingAttackersCount[COLOR_NB];
320
321     // kingAttackersWeight[color] is the sum of the "weights" of the pieces of
322     // the given color which attack a square in the kingRing of the enemy king.
323     // The weights of the individual piece types are given by the elements in
324     // the KingAttackWeights array.
325     int kingAttackersWeight[COLOR_NB];
326
327     // kingAttacksCount[color] is the number of attacks by the given color to
328     // squares directly adjacent to the enemy king. Pieces which attack more
329     // than one square are counted multiple times. For instance, if there is
330     // a white knight on g5 and black's king is on g8, this white knight adds 2
331     // to kingAttacksCount[WHITE].
332     int kingAttacksCount[COLOR_NB];
333   };
334
335
336   // Evaluation::initialize() computes king and pawn attacks, and the king ring
337   // bitboard for a given color. This is done at the beginning of the evaluation.
338
339   template<Tracing T> template<Color Us>
340   void Evaluation<T>::initialize() {
341
342     constexpr Color     Them = ~Us;
343     constexpr Direction Up   = pawn_push(Us);
344     constexpr Direction Down = -Up;
345     constexpr Bitboard LowRanks = (Us == WHITE ? Rank2BB | Rank3BB : Rank7BB | Rank6BB);
346
347     const Square ksq = pos.square<KING>(Us);
348
349     Bitboard dblAttackByPawn = pawn_double_attacks_bb<Us>(pos.pieces(Us, PAWN));
350
351     // Find our pawns that are blocked or on the first two ranks
352     Bitboard b = pos.pieces(Us, PAWN) & (shift<Down>(pos.pieces()) | LowRanks);
353
354     // Squares occupied by those pawns, by our king or queen, by blockers to attacks on our king
355     // or controlled by enemy pawns are excluded from the mobility area.
356     mobilityArea[Us] = ~(b | pos.pieces(Us, KING, QUEEN) | pos.blockers_for_king(Us) | pe->pawn_attacks(Them));
357
358     // Initialize attackedBy[] for king and pawns
359     attackedBy[Us][KING] = attacks_bb<KING>(ksq);
360     attackedBy[Us][PAWN] = pe->pawn_attacks(Us);
361     attackedBy[Us][ALL_PIECES] = attackedBy[Us][KING] | attackedBy[Us][PAWN];
362     attackedBy2[Us] = dblAttackByPawn | (attackedBy[Us][KING] & attackedBy[Us][PAWN]);
363
364     // Init our king safety tables
365     Square s = make_square(std::clamp(file_of(ksq), FILE_B, FILE_G),
366                            std::clamp(rank_of(ksq), RANK_2, RANK_7));
367     kingRing[Us] = attacks_bb<KING>(s) | s;
368
369     kingAttackersCount[Them] = popcount(kingRing[Us] & pe->pawn_attacks(Them));
370     kingAttacksCount[Them] = kingAttackersWeight[Them] = 0;
371
372     // Remove from kingRing[] the squares defended by two pawns
373     kingRing[Us] &= ~dblAttackByPawn;
374   }
375
376
377   // Evaluation::pieces() scores pieces of a given color and type
378
379   template<Tracing T> template<Color Us, PieceType Pt>
380   Score Evaluation<T>::pieces() {
381
382     constexpr Color     Them = ~Us;
383     constexpr Direction Down = -pawn_push(Us);
384     constexpr Bitboard OutpostRanks = (Us == WHITE ? Rank4BB | Rank5BB | Rank6BB
385                                                    : Rank5BB | Rank4BB | Rank3BB);
386     const Square* pl = pos.squares<Pt>(Us);
387
388     Bitboard b, bb;
389     Score score = SCORE_ZERO;
390
391     attackedBy[Us][Pt] = 0;
392
393     for (Square s = *pl; s != SQ_NONE; s = *++pl)
394     {
395         // Find attacked squares, including x-ray attacks for bishops and rooks
396         b = Pt == BISHOP ? attacks_bb<BISHOP>(s, pos.pieces() ^ pos.pieces(QUEEN))
397           : Pt ==   ROOK ? attacks_bb<  ROOK>(s, pos.pieces() ^ pos.pieces(QUEEN) ^ pos.pieces(Us, ROOK))
398                          : attacks_bb<Pt>(s, pos.pieces());
399
400         if (pos.blockers_for_king(Us) & s)
401             b &= line_bb(pos.square<KING>(Us), s);
402
403         attackedBy2[Us] |= attackedBy[Us][ALL_PIECES] & b;
404         attackedBy[Us][Pt] |= b;
405         attackedBy[Us][ALL_PIECES] |= b;
406
407         if (b & kingRing[Them])
408         {
409             kingAttackersCount[Us]++;
410             kingAttackersWeight[Us] += KingAttackWeights[Pt];
411             kingAttacksCount[Us] += popcount(b & attackedBy[Them][KING]);
412         }
413
414         else if (Pt == ROOK && (file_bb(s) & kingRing[Them]))
415             score += RookOnKingRing;
416
417         else if (Pt == BISHOP && (attacks_bb<BISHOP>(s, pos.pieces(PAWN)) & kingRing[Them]))
418             score += BishopOnKingRing;
419
420         int mob = popcount(b & mobilityArea[Us]);
421
422         mobility[Us] += MobilityBonus[Pt - 2][mob];
423
424         if (Pt == BISHOP || Pt == KNIGHT)
425         {
426             // Bonus if the piece is on an outpost square or can reach one
427             // Reduced bonus for knights (BadOutpost) if few relevant targets
428             bb = OutpostRanks & (attackedBy[Us][PAWN] | shift<Down>(pos.pieces(PAWN)))
429                               & ~pe->pawn_attacks_span(Them);
430             Bitboard targets = pos.pieces(Them) & ~pos.pieces(PAWN);
431
432             if (   Pt == KNIGHT
433                 && bb & s & ~CenterFiles // on a side outpost
434                 && !(b & targets)        // no relevant attacks
435                 && (!more_than_one(targets & (s & QueenSide ? QueenSide : KingSide))))
436                 score += BadOutpost;
437             else if (bb & s)
438                 score += Outpost[Pt == BISHOP];
439             else if (Pt == KNIGHT && bb & b & ~pos.pieces(Us))
440                 score += ReachableOutpost;
441
442             // Bonus for a knight or bishop shielded by pawn
443             if (shift<Down>(pos.pieces(PAWN)) & s)
444                 score += MinorBehindPawn;
445
446             // Penalty if the piece is far from the king
447             score -= KingProtector[Pt == BISHOP] * distance(pos.square<KING>(Us), s);
448
449             if (Pt == BISHOP)
450             {
451                 // Penalty according to the number of our pawns on the same color square as the
452                 // bishop, bigger when the center files are blocked with pawns and smaller
453                 // when the bishop is outside the pawn chain.
454                 Bitboard blocked = pos.pieces(Us, PAWN) & shift<Down>(pos.pieces());
455
456                 score -= BishopPawns * pos.pawns_on_same_color_squares(Us, s)
457                                      * (!(attackedBy[Us][PAWN] & s) + popcount(blocked & CenterFiles));
458
459                 // Penalty for all enemy pawns x-rayed
460                 score -= BishopXRayPawns * popcount(attacks_bb<BISHOP>(s) & pos.pieces(Them, PAWN));
461
462                 // Bonus for bishop on a long diagonal which can "see" both center squares
463                 if (more_than_one(attacks_bb<BISHOP>(s, pos.pieces(PAWN)) & Center))
464                     score += LongDiagonalBishop;
465
466                 // An important Chess960 pattern: a cornered bishop blocked by a friendly
467                 // pawn diagonally in front of it is a very serious problem, especially
468                 // when that pawn is also blocked.
469                 if (   pos.is_chess960()
470                     && (s == relative_square(Us, SQ_A1) || s == relative_square(Us, SQ_H1)))
471                 {
472                     Direction d = pawn_push(Us) + (file_of(s) == FILE_A ? EAST : WEST);
473                     if (pos.piece_on(s + d) == make_piece(Us, PAWN))
474                         score -= !pos.empty(s + d + pawn_push(Us))                ? CorneredBishop * 4
475                                 : pos.piece_on(s + d + d) == make_piece(Us, PAWN) ? CorneredBishop * 2
476                                                                                   : CorneredBishop;
477                 }
478             }
479         }
480
481         if (Pt == ROOK)
482         {
483             // Bonus for rook on an open or semi-open file
484             if (pos.is_on_semiopen_file(Us, s))
485                 score += RookOnFile[pos.is_on_semiopen_file(Them, s)];
486
487             // Penalty when trapped by the king, even more if the king cannot castle
488             else if (mob <= 3)
489             {
490                 File kf = file_of(pos.square<KING>(Us));
491                 if ((kf < FILE_E) == (file_of(s) < kf))
492                     score -= TrappedRook * (1 + !pos.castling_rights(Us));
493             }
494         }
495
496         if (Pt == QUEEN)
497         {
498             // Penalty if any relative pin or discovered attack against the queen
499             Bitboard queenPinners;
500             if (pos.slider_blockers(pos.pieces(Them, ROOK, BISHOP), s, queenPinners))
501                 score -= WeakQueen;
502         }
503     }
504     if (T)
505         Trace::add(Pt, Us, score);
506
507     return score;
508   }
509
510
511   // Evaluation::king() assigns bonuses and penalties to a king of a given color
512
513   template<Tracing T> template<Color Us>
514   Score Evaluation<T>::king() const {
515
516     constexpr Color    Them = ~Us;
517     constexpr Bitboard Camp = (Us == WHITE ? AllSquares ^ Rank6BB ^ Rank7BB ^ Rank8BB
518                                            : AllSquares ^ Rank1BB ^ Rank2BB ^ Rank3BB);
519
520     Bitboard weak, b1, b2, b3, safe, unsafeChecks = 0;
521     Bitboard rookChecks, queenChecks, bishopChecks, knightChecks;
522     int kingDanger = 0;
523     const Square ksq = pos.square<KING>(Us);
524
525     // Init the score with king shelter and enemy pawns storm
526     Score score = pe->king_safety<Us>(pos);
527
528     // Attacked squares defended at most once by our queen or king
529     weak =  attackedBy[Them][ALL_PIECES]
530           & ~attackedBy2[Us]
531           & (~attackedBy[Us][ALL_PIECES] | attackedBy[Us][KING] | attackedBy[Us][QUEEN]);
532
533     // Analyse the safe enemy's checks which are possible on next move
534     safe  = ~pos.pieces(Them);
535     safe &= ~attackedBy[Us][ALL_PIECES] | (weak & attackedBy2[Them]);
536
537     b1 = attacks_bb<ROOK  >(ksq, pos.pieces() ^ pos.pieces(Us, QUEEN));
538     b2 = attacks_bb<BISHOP>(ksq, pos.pieces() ^ pos.pieces(Us, QUEEN));
539
540     // Enemy rooks checks
541     rookChecks = b1 & attackedBy[Them][ROOK] & safe;
542     if (rookChecks)
543         kingDanger += SafeCheck[ROOK][more_than_one(rookChecks)];
544     else
545         unsafeChecks |= b1 & attackedBy[Them][ROOK];
546
547     // Enemy queen safe checks: count them only if the checks are from squares from
548     // which opponent cannot give a rook check, because rook checks are more valuable.
549     queenChecks =  (b1 | b2) & attackedBy[Them][QUEEN] & safe
550                  & ~(attackedBy[Us][QUEEN] | rookChecks);
551     if (queenChecks)
552         kingDanger += SafeCheck[QUEEN][more_than_one(queenChecks)];
553
554     // Enemy bishops checks: count them only if they are from squares from which
555     // opponent cannot give a queen check, because queen checks are more valuable.
556     bishopChecks =  b2 & attackedBy[Them][BISHOP] & safe
557                   & ~queenChecks;
558     if (bishopChecks)
559         kingDanger += SafeCheck[BISHOP][more_than_one(bishopChecks)];
560
561     else
562         unsafeChecks |= b2 & attackedBy[Them][BISHOP];
563
564     // Enemy knights checks
565     knightChecks = attacks_bb<KNIGHT>(ksq) & attackedBy[Them][KNIGHT];
566     if (knightChecks & safe)
567         kingDanger += SafeCheck[KNIGHT][more_than_one(knightChecks & safe)];
568     else
569         unsafeChecks |= knightChecks;
570
571     // Find the squares that opponent attacks in our king flank, the squares
572     // which they attack twice in that flank, and the squares that we defend.
573     b1 = attackedBy[Them][ALL_PIECES] & KingFlank[file_of(ksq)] & Camp;
574     b2 = b1 & attackedBy2[Them];
575     b3 = attackedBy[Us][ALL_PIECES] & KingFlank[file_of(ksq)] & Camp;
576
577     int kingFlankAttack  = popcount(b1) + popcount(b2);
578     int kingFlankDefense = popcount(b3);
579
580     kingDanger +=        kingAttackersCount[Them] * kingAttackersWeight[Them]
581                  + 185 * popcount(kingRing[Us] & weak)
582                  + 148 * popcount(unsafeChecks)
583                  +  98 * popcount(pos.blockers_for_king(Us))
584                  +  69 * kingAttacksCount[Them]
585                  +   3 * kingFlankAttack * kingFlankAttack / 8
586                  +       mg_value(mobility[Them] - mobility[Us])
587                  - 873 * !pos.count<QUEEN>(Them)
588                  - 100 * bool(attackedBy[Us][KNIGHT] & attackedBy[Us][KING])
589                  -   6 * mg_value(score) / 8
590                  -   4 * kingFlankDefense
591                  +  37;
592
593     // Transform the kingDanger units into a Score, and subtract it from the evaluation
594     if (kingDanger > 100)
595         score -= make_score(kingDanger * kingDanger / 4096, kingDanger / 16);
596
597     // Penalty when our king is on a pawnless flank
598     if (!(pos.pieces(PAWN) & KingFlank[file_of(ksq)]))
599         score -= PawnlessFlank;
600
601     // Penalty if king flank is under attack, potentially moving toward the king
602     score -= FlankAttacks * kingFlankAttack;
603
604     if (T)
605         Trace::add(KING, Us, score);
606
607     return score;
608   }
609
610
611   // Evaluation::threats() assigns bonuses according to the types of the
612   // attacking and the attacked pieces.
613
614   template<Tracing T> template<Color Us>
615   Score Evaluation<T>::threats() const {
616
617     constexpr Color     Them     = ~Us;
618     constexpr Direction Up       = pawn_push(Us);
619     constexpr Bitboard  TRank3BB = (Us == WHITE ? Rank3BB : Rank6BB);
620
621     Bitboard b, weak, defended, nonPawnEnemies, stronglyProtected, safe;
622     Score score = SCORE_ZERO;
623
624     // Non-pawn enemies
625     nonPawnEnemies = pos.pieces(Them) & ~pos.pieces(PAWN);
626
627     // Squares strongly protected by the enemy, either because they defend the
628     // square with a pawn, or because they defend the square twice and we don't.
629     stronglyProtected =  attackedBy[Them][PAWN]
630                        | (attackedBy2[Them] & ~attackedBy2[Us]);
631
632     // Non-pawn enemies, strongly protected
633     defended = nonPawnEnemies & stronglyProtected;
634
635     // Enemies not strongly protected and under our attack
636     weak = pos.pieces(Them) & ~stronglyProtected & attackedBy[Us][ALL_PIECES];
637
638     // Bonus according to the kind of attacking pieces
639     if (defended | weak)
640     {
641         b = (defended | weak) & (attackedBy[Us][KNIGHT] | attackedBy[Us][BISHOP]);
642         while (b)
643             score += ThreatByMinor[type_of(pos.piece_on(pop_lsb(&b)))];
644
645         b = weak & attackedBy[Us][ROOK];
646         while (b)
647             score += ThreatByRook[type_of(pos.piece_on(pop_lsb(&b)))];
648
649         if (weak & attackedBy[Us][KING])
650             score += ThreatByKing;
651
652         b =  ~attackedBy[Them][ALL_PIECES]
653            | (nonPawnEnemies & attackedBy2[Us]);
654         score += Hanging * popcount(weak & b);
655
656         // Additional bonus if weak piece is only protected by a queen
657         score += WeakQueenProtection * popcount(weak & attackedBy[Them][QUEEN]);
658     }
659
660     // Bonus for restricting their piece moves
661     b =   attackedBy[Them][ALL_PIECES]
662        & ~stronglyProtected
663        &  attackedBy[Us][ALL_PIECES];
664     score += RestrictedPiece * popcount(b);
665
666     // Protected or unattacked squares
667     safe = ~attackedBy[Them][ALL_PIECES] | attackedBy[Us][ALL_PIECES];
668
669     // Bonus for attacking enemy pieces with our relatively safe pawns
670     b = pos.pieces(Us, PAWN) & safe;
671     b = pawn_attacks_bb<Us>(b) & nonPawnEnemies;
672     score += ThreatBySafePawn * popcount(b);
673
674     // Find squares where our pawns can push on the next move
675     b  = shift<Up>(pos.pieces(Us, PAWN)) & ~pos.pieces();
676     b |= shift<Up>(b & TRank3BB) & ~pos.pieces();
677
678     // Keep only the squares which are relatively safe
679     b &= ~attackedBy[Them][PAWN] & safe;
680
681     // Bonus for safe pawn threats on the next move
682     b = pawn_attacks_bb<Us>(b) & nonPawnEnemies;
683     score += ThreatByPawnPush * popcount(b);
684
685     // Bonus for threats on the next moves against enemy queen
686     if (pos.count<QUEEN>(Them) == 1)
687     {
688         bool queenImbalance = pos.count<QUEEN>() == 1;
689
690         Square s = pos.square<QUEEN>(Them);
691         safe =   mobilityArea[Us]
692               & ~pos.pieces(Us, PAWN)
693               & ~stronglyProtected;
694
695         b = attackedBy[Us][KNIGHT] & attacks_bb<KNIGHT>(s);
696
697         score += KnightOnQueen * popcount(b & safe) * (1 + queenImbalance);
698
699         b =  (attackedBy[Us][BISHOP] & attacks_bb<BISHOP>(s, pos.pieces()))
700            | (attackedBy[Us][ROOK  ] & attacks_bb<ROOK  >(s, pos.pieces()));
701
702         score += SliderOnQueen * popcount(b & safe & attackedBy2[Us]) * (1 + queenImbalance);
703     }
704
705     if (T)
706         Trace::add(THREAT, Us, score);
707
708     return score;
709   }
710
711   // Evaluation::passed() evaluates the passed pawns and candidate passed
712   // pawns of the given color.
713
714   template<Tracing T> template<Color Us>
715   Score Evaluation<T>::passed() const {
716
717     constexpr Color     Them = ~Us;
718     constexpr Direction Up   = pawn_push(Us);
719     constexpr Direction Down = -Up;
720
721     auto king_proximity = [&](Color c, Square s) {
722       return std::min(distance(pos.square<KING>(c), s), 5);
723     };
724
725     Bitboard b, bb, squaresToQueen, unsafeSquares, blockedPassers, helpers;
726     Score score = SCORE_ZERO;
727
728     b = pe->passed_pawns(Us);
729
730     blockedPassers = b & shift<Down>(pos.pieces(Them, PAWN));
731     if (blockedPassers)
732     {
733         helpers =  shift<Up>(pos.pieces(Us, PAWN))
734                  & ~pos.pieces(Them)
735                  & (~attackedBy2[Them] | attackedBy[Us][ALL_PIECES]);
736
737         // Remove blocked candidate passers that don't have help to pass
738         b &=  ~blockedPassers
739             | shift<WEST>(helpers)
740             | shift<EAST>(helpers);
741     }
742
743     while (b)
744     {
745         Square s = pop_lsb(&b);
746
747         assert(!(pos.pieces(Them, PAWN) & forward_file_bb(Us, s + Up)));
748
749         int r = relative_rank(Us, s);
750
751         Score bonus = PassedRank[r];
752
753         if (r > RANK_3)
754         {
755             int w = 5 * r - 13;
756             Square blockSq = s + Up;
757
758             // Adjust bonus based on the king's proximity
759             bonus += make_score(0, (  king_proximity(Them, blockSq) * 19 / 4
760                                     - king_proximity(Us,   blockSq) *  2) * w);
761
762             // If blockSq is not the queening square then consider also a second push
763             if (r != RANK_7)
764                 bonus -= make_score(0, king_proximity(Us, blockSq + Up) * w);
765
766             // If the pawn is free to advance, then increase the bonus
767             if (pos.empty(blockSq))
768             {
769                 squaresToQueen = forward_file_bb(Us, s);
770                 unsafeSquares = passed_pawn_span(Us, s);
771
772                 bb = forward_file_bb(Them, s) & pos.pieces(ROOK, QUEEN);
773
774                 if (!(pos.pieces(Them) & bb))
775                     unsafeSquares &= attackedBy[Them][ALL_PIECES];
776
777                 // If there are no enemy attacks on passed pawn span, assign a big bonus.
778                 // Otherwise assign a smaller bonus if the path to queen is not attacked
779                 // and even smaller bonus if it is attacked but block square is not.
780                 int k = !unsafeSquares                    ? 35 :
781                         !(unsafeSquares & squaresToQueen) ? 20 :
782                         !(unsafeSquares & blockSq)        ?  9 :
783                                                              0 ;
784
785                 // Assign a larger bonus if the block square is defended
786                 if ((pos.pieces(Us) & bb) || (attackedBy[Us][ALL_PIECES] & blockSq))
787                     k += 5;
788
789                 bonus += make_score(k * w, k * w);
790             }
791         } // r > RANK_3
792
793         score += bonus - PassedFile * edge_distance(file_of(s));
794     }
795
796     if (T)
797         Trace::add(PASSED, Us, score);
798
799     return score;
800   }
801
802
803   // Evaluation::space() computes a space evaluation for a given side, aiming to improve game
804   // play in the opening. It is based on the number of safe squares on the four central files
805   // on ranks 2 to 4. Completely safe squares behind a friendly pawn are counted twice.
806   // Finally, the space bonus is multiplied by a weight which decreases according to occupancy.
807
808   template<Tracing T> template<Color Us>
809   Score Evaluation<T>::space() const {
810
811     // Early exit if, for example, both queens or 6 minor pieces have been exchanged
812     if (pos.non_pawn_material() < SpaceThreshold)
813         return SCORE_ZERO;
814
815     constexpr Color Them     = ~Us;
816     constexpr Direction Down = -pawn_push(Us);
817     constexpr Bitboard SpaceMask =
818       Us == WHITE ? CenterFiles & (Rank2BB | Rank3BB | Rank4BB)
819                   : CenterFiles & (Rank7BB | Rank6BB | Rank5BB);
820
821     // Find the available squares for our pieces inside the area defined by SpaceMask
822     Bitboard safe =   SpaceMask
823                    & ~pos.pieces(Us, PAWN)
824                    & ~attackedBy[Them][PAWN];
825
826     // Find all squares which are at most three squares behind some friendly pawn
827     Bitboard behind = pos.pieces(Us, PAWN);
828     behind |= shift<Down>(behind);
829     behind |= shift<Down+Down>(behind);
830
831     int bonus = popcount(safe) + popcount(behind & safe & ~attackedBy[Them][ALL_PIECES]);
832     int weight = pos.count<ALL_PIECES>(Us) - 3 + std::min(pe->blocked_count(), 9);
833     Score score = make_score(bonus * weight * weight / 16, 0);
834
835     if (T)
836         Trace::add(SPACE, Us, score);
837
838     return score;
839   }
840
841
842   // Evaluation::winnable() adjusts the midgame and endgame score components, based on
843   // the known attacking/defending status of the players. The final value is derived
844   // by interpolation from the midgame and endgame values.
845
846   template<Tracing T>
847   Value Evaluation<T>::winnable(Score score) const {
848
849     int outflanking =  distance<File>(pos.square<KING>(WHITE), pos.square<KING>(BLACK))
850                      - distance<Rank>(pos.square<KING>(WHITE), pos.square<KING>(BLACK));
851
852     bool pawnsOnBothFlanks =   (pos.pieces(PAWN) & QueenSide)
853                             && (pos.pieces(PAWN) & KingSide);
854
855     bool almostUnwinnable =   outflanking < 0
856                            && !pawnsOnBothFlanks;
857
858     bool infiltration =   rank_of(pos.square<KING>(WHITE)) > RANK_4
859                        || rank_of(pos.square<KING>(BLACK)) < RANK_5;
860
861     // Compute the initiative bonus for the attacking side
862     int complexity =   9 * pe->passed_count()
863                     + 12 * pos.count<PAWN>()
864                     +  9 * outflanking
865                     + 21 * pawnsOnBothFlanks
866                     + 24 * infiltration
867                     + 51 * !pos.non_pawn_material()
868                     - 43 * almostUnwinnable
869                     -110 ;
870
871     Value mg = mg_value(score);
872     Value eg = eg_value(score);
873
874     // Now apply the bonus: note that we find the attacking side by extracting the
875     // sign of the midgame or endgame values, and that we carefully cap the bonus
876     // so that the midgame and endgame scores do not change sign after the bonus.
877     int u = ((mg > 0) - (mg < 0)) * std::clamp(complexity + 50, -abs(mg), 0);
878     int v = ((eg > 0) - (eg < 0)) * std::max(complexity, -abs(eg));
879
880     mg += u;
881     eg += v;
882
883     // Compute the scale factor for the winning side
884     Color strongSide = eg > VALUE_DRAW ? WHITE : BLACK;
885     int sf = me->scale_factor(pos, strongSide);
886
887     // If scale factor is not already specific, scale down via general heuristics
888     if (sf == SCALE_FACTOR_NORMAL)
889     {
890         if (pos.opposite_bishops())
891         {
892             if (   pos.non_pawn_material(WHITE) == BishopValueMg
893                 && pos.non_pawn_material(BLACK) == BishopValueMg)
894                 sf = 18 + 4 * popcount(pe->passed_pawns(strongSide));
895             else
896                 sf = 22 + 3 * pos.count<ALL_PIECES>(strongSide);
897         }
898         else if (  pos.non_pawn_material(WHITE) == RookValueMg
899                 && pos.non_pawn_material(BLACK) == RookValueMg
900                 && pos.count<PAWN>(strongSide) - pos.count<PAWN>(~strongSide) <= 1
901                 && bool(KingSide & pos.pieces(strongSide, PAWN)) != bool(QueenSide & pos.pieces(strongSide, PAWN))
902                 && (attacks_bb<KING>(pos.square<KING>(~strongSide)) & pos.pieces(~strongSide, PAWN)))
903             sf = 36;
904         else if (pos.count<QUEEN>() == 1)
905             sf = 37 + 3 * (pos.count<QUEEN>(WHITE) == 1 ? pos.count<BISHOP>(BLACK) + pos.count<KNIGHT>(BLACK)
906                                                         : pos.count<BISHOP>(WHITE) + pos.count<KNIGHT>(WHITE));
907         else
908             sf = std::min(sf, 36 + 7 * pos.count<PAWN>(strongSide)) - 4 * !pawnsOnBothFlanks;
909       
910         sf -= 4 * !pawnsOnBothFlanks;
911     }
912
913     // Interpolate between the middlegame and (scaled by 'sf') endgame score
914     v =  mg * int(me->game_phase())
915        + eg * int(PHASE_MIDGAME - me->game_phase()) * ScaleFactor(sf) / SCALE_FACTOR_NORMAL;
916     v /= PHASE_MIDGAME;
917
918     if (T)
919     {
920         Trace::add(WINNABLE, make_score(u, eg * ScaleFactor(sf) / SCALE_FACTOR_NORMAL - eg_value(score)));
921         Trace::add(TOTAL, make_score(mg, eg * ScaleFactor(sf) / SCALE_FACTOR_NORMAL));
922     }
923
924     return Value(v);
925   }
926
927
928   // Evaluation::value() is the main function of the class. It computes the various
929   // parts of the evaluation and returns the value of the position from the point
930   // of view of the side to move.
931
932   template<Tracing T>
933   Value Evaluation<T>::value() {
934
935     assert(!pos.checkers());
936
937     // Probe the material hash table
938     me = Material::probe(pos);
939
940     // If we have a specialized evaluation function for the current material
941     // configuration, call it and return.
942     if (me->specialized_eval_exists())
943         return me->evaluate(pos);
944
945     // Initialize score by reading the incrementally updated scores included in
946     // the position object (material + piece square tables) and the material
947     // imbalance. Score is computed internally from the white point of view.
948     Score score = pos.psq_score() + me->imbalance() + pos.this_thread()->contempt;
949
950     // Probe the pawn hash table
951     pe = Pawns::probe(pos);
952     score += pe->pawn_score(WHITE) - pe->pawn_score(BLACK);
953
954     // Early exit if score is high
955     auto lazy_skip = [&](Value lazyThreshold) {
956         return abs(mg_value(score) + eg_value(score)) / 2 > lazyThreshold + pos.non_pawn_material() / 64;
957     };
958
959     if (lazy_skip(LazyThreshold1))
960         goto make_v;
961
962     // Main evaluation begins here
963     initialize<WHITE>();
964     initialize<BLACK>();
965
966     // Pieces evaluated first (also populates attackedBy, attackedBy2).
967     // Note that the order of evaluation of the terms is left unspecified.
968     score +=  pieces<WHITE, KNIGHT>() - pieces<BLACK, KNIGHT>()
969             + pieces<WHITE, BISHOP>() - pieces<BLACK, BISHOP>()
970             + pieces<WHITE, ROOK  >() - pieces<BLACK, ROOK  >()
971             + pieces<WHITE, QUEEN >() - pieces<BLACK, QUEEN >();
972
973     score += mobility[WHITE] - mobility[BLACK];
974
975     // More complex interactions that require fully populated attack bitboards
976     score +=  king<   WHITE>() - king<   BLACK>()
977             + passed< WHITE>() - passed< BLACK>();
978
979     if (lazy_skip(LazyThreshold2))
980         goto make_v;
981
982     score +=  threats<WHITE>() - threats<BLACK>()
983             + space<  WHITE>() - space<  BLACK>();
984
985 make_v:
986     // Derive single value from mg and eg parts of score
987     Value v = winnable(score);
988
989     // In case of tracing add all remaining individual evaluation terms
990     if (T)
991     {
992         Trace::add(MATERIAL, pos.psq_score());
993         Trace::add(IMBALANCE, me->imbalance());
994         Trace::add(PAWN, pe->pawn_score(WHITE), pe->pawn_score(BLACK));
995         Trace::add(MOBILITY, mobility[WHITE], mobility[BLACK]);
996     }
997
998     // Evaluation grain
999     v = (v / 16) * 16;
1000
1001     // Side to move point of view
1002     v = (pos.side_to_move() == WHITE ? v : -v) + Tempo;
1003
1004     return v;
1005   }
1006
1007 } // namespace
1008
1009
1010 /// evaluate() is the evaluator for the outer world. It returns a static
1011 /// evaluation of the position from the point of view of the side to move.
1012
1013 Value Eval::evaluate(const Position& pos) {
1014
1015   Value v;
1016
1017   if (!Eval::useNNUE)
1018       v = Evaluation<NO_TRACE>(pos).value();
1019   else
1020   {
1021       // Scale and shift NNUE for compatibility with search and classical evaluation
1022       auto  adjusted_NNUE = [&](){
1023          int mat = pos.non_pawn_material() + PieceValue[MG][PAWN] * pos.count<PAWN>();
1024          return NNUE::evaluate(pos) * (720 + mat / 32) / 1024 + Tempo;
1025       };
1026
1027       // If there is PSQ imbalance use classical eval, with small probability if it is small
1028       Value psq = Value(abs(eg_value(pos.psq_score())));
1029       int   r50 = 16 + pos.rule50_count();
1030       bool  largePsq = psq * 16 > (NNUEThreshold1 + pos.non_pawn_material() / 64) * r50;
1031       bool  classical = largePsq || (psq > PawnValueMg / 4 && !(pos.this_thread()->nodes & 0xB));
1032
1033       v = classical ? Evaluation<NO_TRACE>(pos).value() : adjusted_NNUE();
1034
1035       // If the classical eval is small and imbalance large, use NNUE nevertheless.
1036       // For the case of opposite colored bishops, switch to NNUE eval with
1037       // small probability if the classical eval is less than the threshold.
1038       if (   largePsq
1039           && (abs(v) * 16 < NNUEThreshold2 * r50
1040           || (   pos.opposite_bishops()
1041               && abs(v) * 16 < (NNUEThreshold1 + pos.non_pawn_material() / 64) * r50
1042               && !(pos.this_thread()->nodes & 0xB))))
1043           v = adjusted_NNUE();
1044   }
1045
1046   // Damp down the evaluation linearly when shuffling
1047   v = v * (100 - pos.rule50_count()) / 100;
1048
1049   // Guarantee evaluation does not hit the tablebase range
1050   v = std::clamp(v, VALUE_TB_LOSS_IN_MAX_PLY + 1, VALUE_TB_WIN_IN_MAX_PLY - 1);
1051
1052   return v;
1053 }
1054
1055 /// trace() is like evaluate(), but instead of returning a value, it returns
1056 /// a string (suitable for outputting to stdout) that contains the detailed
1057 /// descriptions and values of each evaluation term. Useful for debugging.
1058 /// Trace scores are from white's point of view
1059
1060 std::string Eval::trace(const Position& pos) {
1061
1062   if (pos.checkers())
1063       return "Final evaluation: none (in check)";
1064
1065   std::stringstream ss;
1066   ss << std::showpoint << std::noshowpos << std::fixed << std::setprecision(2);
1067
1068   Value v;
1069
1070   std::memset(scores, 0, sizeof(scores));
1071
1072   pos.this_thread()->contempt = SCORE_ZERO; // Reset any dynamic contempt
1073
1074   v = Evaluation<TRACE>(pos).value();
1075
1076   ss << std::showpoint << std::noshowpos << std::fixed << std::setprecision(2)
1077      << "     Term    |    White    |    Black    |    Total   \n"
1078      << "             |   MG    EG  |   MG    EG  |   MG    EG \n"
1079      << " ------------+-------------+-------------+------------\n"
1080      << "    Material | " << Term(MATERIAL)
1081      << "   Imbalance | " << Term(IMBALANCE)
1082      << "       Pawns | " << Term(PAWN)
1083      << "     Knights | " << Term(KNIGHT)
1084      << "     Bishops | " << Term(BISHOP)
1085      << "       Rooks | " << Term(ROOK)
1086      << "      Queens | " << Term(QUEEN)
1087      << "    Mobility | " << Term(MOBILITY)
1088      << " King safety | " << Term(KING)
1089      << "     Threats | " << Term(THREAT)
1090      << "      Passed | " << Term(PASSED)
1091      << "       Space | " << Term(SPACE)
1092      << "    Winnable | " << Term(WINNABLE)
1093      << " ------------+-------------+-------------+------------\n"
1094      << "       Total | " << Term(TOTAL);
1095
1096   v = pos.side_to_move() == WHITE ? v : -v;
1097
1098   ss << "\nClassical evaluation: " << to_cp(v) << " (white side)\n";
1099
1100   if (Eval::useNNUE)
1101   {
1102       v = NNUE::evaluate(pos);
1103       v = pos.side_to_move() == WHITE ? v : -v;
1104       ss << "\nNNUE evaluation:      " << to_cp(v) << " (white side)\n";
1105   }
1106
1107   v = evaluate(pos);
1108   v = pos.side_to_move() == WHITE ? v : -v;
1109   ss << "\nFinal evaluation:     " << to_cp(v) << " (white side)\n";
1110
1111   return ss.str();
1112 }