X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fevaluate.cpp;h=383d9e62f1fec595399c722c8dc59baff9938e63;hp=a1a120435a8d38194bc306a1f7b2917a77f779b9;hb=3e2591d83c285597a7400c79b61ab9dc38875163;hpb=e6310b3469b07b6bbecf8d8f75367a655090f22b diff --git a/src/evaluate.cpp b/src/evaluate.cpp index a1a12043..383d9e62 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -30,34 +30,50 @@ namespace { - namespace Tracing { + namespace Trace { enum Term { // First 8 entries are for PieceType MATERIAL = 8, IMBALANCE, MOBILITY, THREAT, PASSED, SPACE, TOTAL, TERM_NB }; - Score scores[COLOR_NB][TERM_NB]; + double scores[TERM_NB][COLOR_NB][PHASE_NB]; - std::ostream& operator<<(std::ostream& os, Term idx); + double to_cp(Value v) { return double(v) / PawnValueEg; } - double to_cp(Value v); - void write(int idx, Color c, Score s); - void write(int idx, Score w, Score b = SCORE_ZERO); - std::string do_trace(const Position& pos); + void add(int idx, Color c, Score s) { + scores[idx][c][MG] = to_cp(mg_value(s)); + scores[idx][c][EG] = to_cp(eg_value(s)); + } + + void add(int idx, Score w, Score b = SCORE_ZERO) { + add(idx, WHITE, w); add(idx, BLACK, b); + } + + std::ostream& operator<<(std::ostream& os, Term t) { + + if (t == MATERIAL || t == IMBALANCE || t == Term(PAWN) || t == TOTAL) + os << " --- --- | --- --- | "; + else + os << std::setw(5) << scores[t][WHITE][MG] << " " + << std::setw(5) << scores[t][WHITE][EG] << " | " + << std::setw(5) << scores[t][BLACK][MG] << " " + << std::setw(5) << scores[t][BLACK][EG] << " | "; + + os << std::setw(5) << scores[t][WHITE][MG] - scores[t][BLACK][MG] << " " + << std::setw(5) << scores[t][WHITE][EG] - scores[t][BLACK][EG] << " \n"; + + return os; + } } + using namespace Trace; // Struct EvalInfo contains various information computed and collected // by the evaluation functions. struct EvalInfo { - // Pointers to material and pawn hash table entries - Material::Entry* mi; - Pawns::Entry* pi; - // attackedBy[color][piece type] is a bitboard representing all squares - // attacked by a given color and piece type, attackedBy[color][ALL_PIECES] - // contains all squares attacked by the given color. + // attacked by a given color and piece type (can be also ALL_PIECES). Bitboard attackedBy[COLOR_NB][PIECE_TYPE_NB]; // kingRing[color] is the zone around the king which is considered @@ -86,6 +102,7 @@ namespace { int kingAdjacentZoneAttacksCount[COLOR_NB]; Bitboard pinnedPieces[COLOR_NB]; + Pawns::Entry* pi; }; @@ -124,8 +141,8 @@ namespace { S( 94, 99), S( 96,100), S(99,111), S(99,112) } }; - // Outpost[knight/bishop][supported by pawn] contains bonuses for knights and bishops - // outposts, bigger if outpost piece is supported by a pawn. + // Outpost[knight/bishop][supported by pawn] contains bonuses for knights and + // bishops outposts, bigger if outpost piece is supported by a pawn. const Score Outpost[][2] = { { S(28, 7), S(42,11) }, // Knights { S(12, 3), S(18, 5) } // Bishops @@ -146,6 +163,13 @@ namespace { S(0, 0), S(0, 0), S(107, 138), S(84, 122), S(114, 203), S(121, 217) }; + // Passed[mg/eg][rank] contains midgame and endgame bonuses for passed pawns. + // We don't use a Score because we process the two components independently. + const Value Passed[][RANK_NB] = { + { V(0), V( 1), V(34), V(90), V(214), V(328) }, + { V(7), V(14), V(37), V(63), V(134), V(189) } + }; + const Score ThreatenedByHangingPawn = S(40, 60); // Assorted bonuses and penalties used by evaluation @@ -160,7 +184,6 @@ namespace { const Score Unstoppable = S( 0, 20); const Score Hanging = S(31, 26); const Score PawnAttackThreat = S(20, 20); - const Score PawnSafePush = S( 5, 5); // Penalty for a bishop on a1/h1 (a8/h8 for black) which is trapped by // a friendly pawn on b2/g2 (b7/g7 for black). This can obviously only @@ -207,8 +230,9 @@ namespace { const Square Down = (Us == WHITE ? DELTA_S : DELTA_N); ei.pinnedPieces[Us] = pos.pinned_pieces(Us); - ei.attackedBy[Us][ALL_PIECES] = ei.attackedBy[Us][PAWN] = ei.pi->pawn_attacks(Us); Bitboard b = ei.attackedBy[Them][KING] = pos.attacks_from(pos.square(Them)); + ei.attackedBy[Them][ALL_PIECES] |= b; + ei.attackedBy[Us][ALL_PIECES] |= ei.attackedBy[Us][PAWN] = ei.pi->pawn_attacks(Us); // Init king safety tables only if we are going to use them if (pos.non_pawn_material(Us) >= QueenValueMg) @@ -225,8 +249,8 @@ namespace { // evaluate_pieces() assigns bonuses and penalties to the pieces of a given color - template - Score evaluate_pieces(const Position& pos, EvalInfo& ei, Score* mobility, Bitboard* mobilityArea) { + template + Score evaluate_pieces(const Position& pos, EvalInfo& ei, Score* mobility, const Bitboard* mobilityArea) { Bitboard b; Square s; @@ -326,22 +350,22 @@ namespace { } } - if (Trace) - Tracing::write(Pt, Us, score); + if (DoTrace) + Trace::add(Pt, Us, score); // Recursively call evaluate_pieces() of next piece type until KING excluded - return score - evaluate_pieces(pos, ei, mobility, mobilityArea); + return score - evaluate_pieces(pos, ei, mobility, mobilityArea); } template<> - Score evaluate_pieces(const Position&, EvalInfo&, Score*, Bitboard*) { return SCORE_ZERO; } + Score evaluate_pieces(const Position&, EvalInfo&, Score*, const Bitboard*) { return SCORE_ZERO; } template<> - Score evaluate_pieces(const Position&, EvalInfo&, Score*, Bitboard*) { return SCORE_ZERO; } + Score evaluate_pieces(const Position&, EvalInfo&, Score*, const Bitboard*) { return SCORE_ZERO; } // evaluate_king() assigns bonuses and penalties to a king of a given color - template + template Score evaluate_king(const Position& pos, const EvalInfo& ei) { const Color Them = (Us == WHITE ? BLACK : WHITE); @@ -372,9 +396,9 @@ namespace { attackUnits = std::min(74, ei.kingAttackersCount[Them] * ei.kingAttackersWeight[Them]) + 8 * ei.kingAdjacentZoneAttacksCount[Them] + 25 * popcount(undefended) - + 11 * (ei.pinnedPieces[Us] != 0) - - mg_value(score) / 8 - - !pos.count(Them) * 60; + + 11 * !!ei.pinnedPieces[Us] + - 60 * !pos.count(Them) + - mg_value(score) / 8; // Analyse the enemy's safe queen contact checks. Firstly, find the // undefended squares around the king reachable by the enemy queen... @@ -437,8 +461,8 @@ namespace { score -= KingDanger[std::max(std::min(attackUnits, 399), 0)]; } - if (Trace) - Tracing::write(KING, Us, score); + if (DoTrace) + Trace::add(KING, Us, score); return score; } @@ -447,7 +471,7 @@ namespace { // evaluate_threats() assigns bonuses according to the type of attacking piece // and the type of attacked one. - template + template Score evaluate_threats(const Position& pos, const EvalInfo& ei) { const Color Them = (Us == WHITE ? BLACK : WHITE); @@ -520,7 +544,7 @@ namespace { score += more_than_one(b) ? KingOnMany : KingOnOne; } - // Add a small bonus for safe pawn pushes + // Bonus if some pawns can safely push and attack an enemy piece b = pos.pieces(Us, PAWN) & ~TRank7BB; b = shift_bb(b | (shift_bb(b & TRank2BB) & ~pos.pieces())); @@ -528,10 +552,6 @@ namespace { & ~ei.attackedBy[Them][PAWN] & (ei.attackedBy[Us][ALL_PIECES] | ~ei.attackedBy[Them][ALL_PIECES]); - if (b) - score += popcount(b) * PawnSafePush; - - // Add another bonus if the pawn push attacks an enemy piece b = (shift_bb(b) | shift_bb(b)) & pos.pieces(Them) & ~ei.attackedBy[Us][PAWN]; @@ -539,8 +559,8 @@ namespace { if (b) score += popcount(b) * PawnAttackThreat; - if (Trace) - Tracing::write(Tracing::THREAT, Us, score); + if (DoTrace) + Trace::add(THREAT, Us, score); return score; } @@ -548,7 +568,7 @@ namespace { // evaluate_passed_pawns() evaluates the passed pawns of the given color - template + template Score evaluate_passed_pawns(const Position& pos, const EvalInfo& ei) { const Color Them = (Us == WHITE ? BLACK : WHITE); @@ -567,8 +587,7 @@ namespace { int r = relative_rank(Us, s) - RANK_2; int rr = r * (r - 1); - // Base bonus based on rank - Value mbonus = Value(17 * rr), ebonus = Value(7 * (rr + r + 1)); + Value mbonus = Passed[MG][r], ebonus = Passed[EG][r]; if (rr) { @@ -622,8 +641,8 @@ namespace { score += make_score(mbonus, ebonus); } - if (Trace) - Tracing::write(Tracing::PASSED, Us, score * Weights[PassedPawns]); + if (DoTrace) + Trace::add(PASSED, Us, score * Weights[PassedPawns]); // Add the scores to the middlegame and endgame eval return score * Weights[PassedPawns]; @@ -654,10 +673,10 @@ namespace { behind |= (Us == WHITE ? behind >> 8 : behind << 8); behind |= (Us == WHITE ? behind >> 16 : behind << 16); - // Since SpaceMask[Us] is fully on our half of the board + // Since SpaceMask[Us] is fully on our half of the board... assert(unsigned(safe >> (Us == WHITE ? 32 : 0)) == 0); - // Count safe + (behind & safe) with a single popcount + // ...count safe + (behind & safe) with a single popcount int bonus = popcount((Us == WHITE ? safe << 32 : safe >> 32) | (behind & safe)); int weight = pos.count(Us) + pos.count(Us) + pos.count(Them) + pos.count(Them); @@ -665,234 +684,193 @@ namespace { return make_score(bonus * weight * weight, 0); } +} // namespace - // do_evaluate() is the evaluation entry point, called directly from evaluate() - - template - Value do_evaluate(const Position& pos) { - - assert(!pos.checkers()); - - EvalInfo ei; - Score score, mobility[2] = { SCORE_ZERO, SCORE_ZERO }; - - // Initialize score by reading the incrementally updated scores included - // in the position object (material + piece square tables). - // Score is computed from the point of view of white. - score = pos.psq_score(); - - // Probe the material hash table - ei.mi = Material::probe(pos); - score += ei.mi->imbalance(); - - // If we have a specialized evaluation function for the current material - // configuration, call it and return. - if (ei.mi->specialized_eval_exists()) - return ei.mi->evaluate(pos); - - // Probe the pawn hash table - ei.pi = Pawns::probe(pos); - score += ei.pi->pawns_score() * Weights[PawnStructure]; - // Initialize attack and king safety bitboards - init_eval_info(pos, ei); - init_eval_info(pos, ei); +/// evaluate() is the main evaluation function. It returns a static evaluation +/// of the position always from the point of view of the side to move. - ei.attackedBy[WHITE][ALL_PIECES] |= ei.attackedBy[WHITE][KING]; - ei.attackedBy[BLACK][ALL_PIECES] |= ei.attackedBy[BLACK][KING]; +template +Value Eval::evaluate(const Position& pos) { - // Pawns blocked or on ranks 2 and 3. Will be excluded from the mobility area - Bitboard blockedPawns[] = { - pos.pieces(WHITE, PAWN) & (shift_bb(pos.pieces()) | Rank2BB | Rank3BB), - pos.pieces(BLACK, PAWN) & (shift_bb(pos.pieces()) | Rank7BB | Rank6BB) - }; + assert(!pos.checkers()); - // Do not include in mobility squares protected by enemy pawns, or occupied - // by our blocked pawns or king. - Bitboard mobilityArea[] = { - ~(ei.attackedBy[BLACK][PAWN] | blockedPawns[WHITE] | pos.square(WHITE)), - ~(ei.attackedBy[WHITE][PAWN] | blockedPawns[BLACK] | pos.square(BLACK)) - }; + EvalInfo ei; + Score score, mobility[2] = { SCORE_ZERO, SCORE_ZERO }; - // Evaluate pieces and mobility - score += evaluate_pieces(pos, ei, mobility, mobilityArea); - score += (mobility[WHITE] - mobility[BLACK]) * Weights[Mobility]; + // Initialize score by reading the incrementally updated scores included + // in the position object (material + piece square tables). + // Score is computed from the point of view of white. + score = pos.psq_score(); - // Evaluate kings after all other pieces because we need complete attack - // information when computing the king safety evaluation. - score += evaluate_king(pos, ei) - - evaluate_king(pos, ei); + // Probe the material hash table + Material::Entry* me = Material::probe(pos); + score += me->imbalance(); - // Evaluate tactical threats, we need full attack information including king - score += evaluate_threats(pos, ei) - - evaluate_threats(pos, ei); + // If we have a specialized evaluation function for the current material + // configuration, call it and return. + if (me->specialized_eval_exists()) + return me->evaluate(pos); - // Evaluate passed pawns, we need full attack information including king - score += evaluate_passed_pawns(pos, ei) - - evaluate_passed_pawns(pos, ei); + // Probe the pawn hash table + ei.pi = Pawns::probe(pos); + score += ei.pi->pawns_score() * Weights[PawnStructure]; - // If both sides have only pawns, score for potential unstoppable pawns - if (!pos.non_pawn_material(WHITE) && !pos.non_pawn_material(BLACK)) - { - Bitboard b; - if ((b = ei.pi->passed_pawns(WHITE)) != 0) - score += int(relative_rank(WHITE, frontmost_sq(WHITE, b))) * Unstoppable; + // Initialize attack and king safety bitboards + ei.attackedBy[WHITE][ALL_PIECES] = ei.attackedBy[BLACK][ALL_PIECES] = 0; + init_eval_info(pos, ei); + init_eval_info(pos, ei); - if ((b = ei.pi->passed_pawns(BLACK)) != 0) - score -= int(relative_rank(BLACK, frontmost_sq(BLACK, b))) * Unstoppable; - } + // Pawns blocked or on ranks 2 and 3. Will be excluded from the mobility area + Bitboard blockedPawns[] = { + pos.pieces(WHITE, PAWN) & (shift_bb(pos.pieces()) | Rank2BB | Rank3BB), + pos.pieces(BLACK, PAWN) & (shift_bb(pos.pieces()) | Rank7BB | Rank6BB) + }; - // Evaluate space for both sides, only during opening - if (pos.non_pawn_material(WHITE) + pos.non_pawn_material(BLACK) >= 11756) - score += (evaluate_space(pos, ei) - evaluate_space(pos, ei)) * Weights[Space]; + // Do not include in mobility squares protected by enemy pawns, or occupied + // by our blocked pawns or king. + Bitboard mobilityArea[] = { + ~(ei.attackedBy[BLACK][PAWN] | blockedPawns[WHITE] | pos.square(WHITE)), + ~(ei.attackedBy[WHITE][PAWN] | blockedPawns[BLACK] | pos.square(BLACK)) + }; - // Scale winning side if position is more drawish than it appears - Color strongSide = eg_value(score) > VALUE_DRAW ? WHITE : BLACK; - ScaleFactor sf = ei.mi->scale_factor(pos, strongSide); + // Evaluate pieces and mobility + score += evaluate_pieces(pos, ei, mobility, mobilityArea); + score += (mobility[WHITE] - mobility[BLACK]) * Weights[Mobility]; - // If we don't already have an unusual scale factor, check for certain - // types of endgames, and use a lower scale for those. - if ( ei.mi->game_phase() < PHASE_MIDGAME - && (sf == SCALE_FACTOR_NORMAL || sf == SCALE_FACTOR_ONEPAWN)) - { - if (pos.opposite_bishops()) - { - // Endgame with opposite-colored bishops and no other pieces (ignoring pawns) - // is almost a draw, in case of KBP vs KB is even more a draw. - if ( pos.non_pawn_material(WHITE) == BishopValueMg - && pos.non_pawn_material(BLACK) == BishopValueMg) - sf = more_than_one(pos.pieces(PAWN)) ? ScaleFactor(32) : ScaleFactor(8); - - // Endgame with opposite-colored bishops, but also other pieces. Still - // a bit drawish, but not as drawish as with only the two bishops. - else - sf = ScaleFactor(50 * sf / SCALE_FACTOR_NORMAL); - } - // Endings where weaker side can place his king in front of the opponent's - // pawns are drawish. - else if ( abs(eg_value(score)) <= BishopValueEg - && ei.pi->pawn_span(strongSide) <= 1 - && !pos.pawn_passed(~strongSide, pos.square(~strongSide))) - sf = ei.pi->pawn_span(strongSide) ? ScaleFactor(56) : ScaleFactor(38); - } + // Evaluate kings after all other pieces because we need complete attack + // information when computing the king safety evaluation. + score += evaluate_king(pos, ei) + - evaluate_king(pos, ei); - // Interpolate between a middlegame and a (scaled by 'sf') endgame score - Value v = mg_value(score) * int(ei.mi->game_phase()) - + eg_value(score) * int(PHASE_MIDGAME - ei.mi->game_phase()) * sf / SCALE_FACTOR_NORMAL; + // Evaluate tactical threats, we need full attack information including king + score += evaluate_threats(pos, ei) + - evaluate_threats(pos, ei); - v /= int(PHASE_MIDGAME); + // Evaluate passed pawns, we need full attack information including king + score += evaluate_passed_pawns(pos, ei) + - evaluate_passed_pawns(pos, ei); - // In case of tracing add all single evaluation terms for both white and black - if (Trace) - { - Tracing::write(Tracing::MATERIAL, pos.psq_score()); - Tracing::write(Tracing::IMBALANCE, ei.mi->imbalance()); - Tracing::write(PAWN, ei.pi->pawns_score()); - Tracing::write(Tracing::MOBILITY, mobility[WHITE] * Weights[Mobility] - , mobility[BLACK] * Weights[Mobility]); - Tracing::write(Tracing::SPACE, evaluate_space(pos, ei) * Weights[Space] - , evaluate_space(pos, ei) * Weights[Space]); - Tracing::write(Tracing::TOTAL, score); - } + // If both sides have only pawns, score for potential unstoppable pawns + if (!pos.non_pawn_material(WHITE) && !pos.non_pawn_material(BLACK)) + { + Bitboard b; + if ((b = ei.pi->passed_pawns(WHITE)) != 0) + score += int(relative_rank(WHITE, frontmost_sq(WHITE, b))) * Unstoppable; - return (pos.side_to_move() == WHITE ? v : -v) + Eval::Tempo; // Side to move point of view + if ((b = ei.pi->passed_pawns(BLACK)) != 0) + score -= int(relative_rank(BLACK, frontmost_sq(BLACK, b))) * Unstoppable; } - - // Tracing functions - - double Tracing::to_cp(Value v) { return double(v) / PawnValueEg; } - - void Tracing::write(int idx, Color c, Score s) { scores[c][idx] = s; } - - void Tracing::write(int idx, Score w, Score b) { - scores[WHITE][idx] = w, scores[BLACK][idx] = b; + // Evaluate space for both sides, only during opening + if (pos.non_pawn_material(WHITE) + pos.non_pawn_material(BLACK) >= 11756) + score += (evaluate_space(pos, ei) - evaluate_space(pos, ei)) * Weights[Space]; + + // Scale winning side if position is more drawish than it appears + Color strongSide = eg_value(score) > VALUE_DRAW ? WHITE : BLACK; + ScaleFactor sf = me->scale_factor(pos, strongSide); + + // If we don't already have an unusual scale factor, check for certain + // types of endgames, and use a lower scale for those. + if ( me->game_phase() < PHASE_MIDGAME + && (sf == SCALE_FACTOR_NORMAL || sf == SCALE_FACTOR_ONEPAWN)) + { + if (pos.opposite_bishops()) + { + // Endgame with opposite-colored bishops and no other pieces (ignoring pawns) + // is almost a draw, in case of KBP vs KB is even more a draw. + if ( pos.non_pawn_material(WHITE) == BishopValueMg + && pos.non_pawn_material(BLACK) == BishopValueMg) + sf = more_than_one(pos.pieces(PAWN)) ? ScaleFactor(32) : ScaleFactor(8); + + // Endgame with opposite-colored bishops, but also other pieces. Still + // a bit drawish, but not as drawish as with only the two bishops. + else + sf = ScaleFactor(50 * sf / SCALE_FACTOR_NORMAL); + } + // Endings where weaker side can place his king in front of the opponent's + // pawns are drawish. + else if ( abs(eg_value(score)) <= BishopValueEg + && ei.pi->pawn_span(strongSide) <= 1 + && !pos.pawn_passed(~strongSide, pos.square(~strongSide))) + sf = ei.pi->pawn_span(strongSide) ? ScaleFactor(56) : ScaleFactor(38); } - std::ostream& Tracing::operator<<(std::ostream& os, Term t) { - - double wScore[] = { to_cp(mg_value(scores[WHITE][t])), to_cp(eg_value(scores[WHITE][t])) }; - double bScore[] = { to_cp(mg_value(scores[BLACK][t])), to_cp(eg_value(scores[BLACK][t])) }; - - if (t == MATERIAL || t == IMBALANCE || t == Term(PAWN) || t == TOTAL) - os << " --- --- | --- --- | "; - else - os << std::setw(5) << wScore[MG] << " " << std::setw(5) << wScore[EG] << " | " - << std::setw(5) << bScore[MG] << " " << std::setw(5) << bScore[EG] << " | "; + // Interpolate between a middlegame and a (scaled by 'sf') endgame score + Value v = mg_value(score) * int(me->game_phase()) + + eg_value(score) * int(PHASE_MIDGAME - me->game_phase()) * sf / SCALE_FACTOR_NORMAL; + + v /= int(PHASE_MIDGAME); + + // In case of tracing add all single evaluation terms + if (DoTrace) + { + Trace::add(MATERIAL, pos.psq_score()); + Trace::add(IMBALANCE, me->imbalance()); + Trace::add(PAWN, ei.pi->pawns_score()); + Trace::add(MOBILITY, mobility[WHITE] * Weights[Mobility] + , mobility[BLACK] * Weights[Mobility]); + Trace::add(SPACE, evaluate_space(pos, ei) * Weights[Space] + , evaluate_space(pos, ei) * Weights[Space]); + Trace::add(TOTAL, score); + } - os << std::setw(5) << wScore[MG] - bScore[MG] << " " - << std::setw(5) << wScore[EG] - bScore[EG] << " \n"; + return (pos.side_to_move() == WHITE ? v : -v) + Eval::Tempo; // Side to move point of view +} - return os; - } +// Explicit template instantiations +template Value Eval::evaluate(const Position&); +template Value Eval::evaluate(const Position&); - std::string Tracing::do_trace(const Position& pos) { - - std::memset(scores, 0, sizeof(scores)); - - Value v = do_evaluate(pos); - v = pos.side_to_move() == WHITE ? v : -v; // White's point of view - - std::stringstream ss; - ss << std::showpoint << std::noshowpos << std::fixed << std::setprecision(2) - << " Eval term | White | Black | Total \n" - << " | MG EG | MG EG | MG EG \n" - << "----------------+-------------+-------------+-------------\n" - << " Material | " << Term(MATERIAL) - << " Imbalance | " << Term(IMBALANCE) - << " Pawns | " << Term(PAWN) - << " Knights | " << Term(KNIGHT) - << " Bishop | " << Term(BISHOP) - << " Rooks | " << Term(ROOK) - << " Queens | " << Term(QUEEN) - << " Mobility | " << Term(MOBILITY) - << " King safety | " << Term(KING) - << " Threats | " << Term(THREAT) - << " Passed pawns | " << Term(PASSED) - << " Space | " << Term(SPACE) - << "----------------+-------------+-------------+-------------\n" - << " Total | " << Term(TOTAL); - - ss << "\nTotal Evaluation: " << to_cp(v) << " (white side)\n"; - - return ss.str(); - } -} // namespace +/// trace() is like evaluate(), but instead of returning a value, it returns +/// a string (suitable for outputting to stdout) that contains the detailed +/// descriptions and values of each evaluation term. Useful for debugging. +std::string Eval::trace(const Position& pos) { -namespace Eval { + std::memset(scores, 0, sizeof(scores)); - /// evaluate() is the main evaluation function. It returns a static evaluation - /// of the position always from the point of view of the side to move. + Value v = evaluate(pos); + v = pos.side_to_move() == WHITE ? v : -v; // White's point of view - Value evaluate(const Position& pos) { - return do_evaluate(pos); - } + std::stringstream ss; + ss << std::showpoint << std::noshowpos << std::fixed << std::setprecision(2) + << " Eval term | White | Black | Total \n" + << " | MG EG | MG EG | MG EG \n" + << "----------------+-------------+-------------+-------------\n" + << " Material | " << Term(MATERIAL) + << " Imbalance | " << Term(IMBALANCE) + << " Pawns | " << Term(PAWN) + << " Knights | " << Term(KNIGHT) + << " Bishop | " << Term(BISHOP) + << " Rooks | " << Term(ROOK) + << " Queens | " << Term(QUEEN) + << " Mobility | " << Term(MOBILITY) + << " King safety | " << Term(KING) + << " Threats | " << Term(THREAT) + << " Passed pawns | " << Term(PASSED) + << " Space | " << Term(SPACE) + << "----------------+-------------+-------------+-------------\n" + << " Total | " << Term(TOTAL); + ss << "\nTotal Evaluation: " << to_cp(v) << " (white side)\n"; - /// trace() is like evaluate(), but instead of returning a value, it returns - /// a string (suitable for outputting to stdout) that contains the detailed - /// descriptions and values of each evaluation term. It's mainly used for - /// debugging. - std::string trace(const Position& pos) { - return Tracing::do_trace(pos); - } + return ss.str(); +} - /// init() computes evaluation weights, usually at startup +/// init() computes evaluation weights, usually at startup - void init() { +void Eval::init() { - const int MaxSlope = 8700; - const int Peak = 1280000; - int t = 0; + const int MaxSlope = 8700; + const int Peak = 1280000; + int t = 0; - for (int i = 0; i < 400; ++i) - { - t = std::min(Peak, std::min(i * i * 27, t + MaxSlope)); - KingDanger[i] = make_score(t / 1000, 0) * Weights[KingSafety]; - } + for (int i = 0; i < 400; ++i) + { + t = std::min(Peak, std::min(i * i * 27, t + MaxSlope)); + KingDanger[i] = make_score(t / 1000, 0) * Weights[KingSafety]; } - -} // namespace Eval +}