X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fevaluate.cpp;h=889a0013ed7a816fe22cf2393c1ff8a928c6cb65;hp=feadbae482ab3b15a47655abbccd589aff7edc95;hb=c7dd9b8d0cb3f5e55e0456c247ac1fd3583be6be;hpb=d4250c52f0060223be666944dc156b28c86ca330 diff --git a/src/evaluate.cpp b/src/evaluate.cpp index feadbae4..889a0013 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -42,14 +42,6 @@ namespace { // by the evaluation functions. struct EvalInfo { - // Middle and end game position's static evaluations - Score value; - - // margin[color] stores the evaluation margins we should consider for - // the given position. This is a kind of uncertainty estimation and - // typically is used by the search for pruning decisions. - Value margin[2]; - // Pointer to pawn hash table entry PawnInfo* pi; @@ -240,19 +232,19 @@ namespace { void init_attack_tables(const Position& pos, EvalInfo& ei); template - Score evaluate_pieces_of_color(const Position& pos, EvalInfo& ei); + Score evaluate_pieces_of_color(const Position& pos, EvalInfo& ei, Score& mobility); template - void evaluate_king(const Position& pos, EvalInfo& ei); + Score evaluate_king(const Position& pos, EvalInfo& ei, Value margins[]); template - void evaluate_threats(const Position& pos, EvalInfo& ei); + Score evaluate_threats(const Position& pos, EvalInfo& ei); template int evaluate_space(const Position& pos, EvalInfo& ei); template - void evaluate_passed_pawns(const Position& pos, EvalInfo& ei); + Score evaluate_passed_pawns(const Position& pos, EvalInfo& ei); inline Score apply_weight(Score v, Score weight); Value scale_by_game_phase(const Score& v, Phase ph, const ScaleFactor sf[]); @@ -289,7 +281,7 @@ Value do_evaluate(const Position& pos, Value margins[]) { EvalInfo ei; ScaleFactor factor[2]; - Score mobility; + Score w_mob, b_mob; assert(pos.is_ok()); assert(pos.thread() >= 0 && pos.thread() < MAX_THREADS); @@ -297,11 +289,15 @@ Value do_evaluate(const Position& pos, Value margins[]) { // Initialize by reading the incrementally updated scores included in the // position object (material + piece square tables). - ei.value = pos.value(); + Score value = pos.value(); + + // margins[color] stores the uncertainty estimation of position's evaluation + // and typically is used by the search for pruning decisions. + margins[WHITE] = margins[BLACK] = VALUE_ZERO; // Probe the material hash table MaterialInfo* mi = MaterialTable[pos.thread()]->get_material_info(pos); - ei.value += mi->material_value(); + value += mi->material_value(); // If we have a specialized evaluation function for the current material // configuration, call it and return. @@ -314,30 +310,31 @@ Value do_evaluate(const Position& pos, Value margins[]) { // Probe the pawn hash table ei.pi = PawnTable[pos.thread()]->get_pawn_info(pos); - ei.value += apply_weight(ei.pi->pawns_value(), Weights[PawnStructure]); + value += apply_weight(ei.pi->pawns_value(), Weights[PawnStructure]); // Initialize attack bitboards with pawns evaluation init_attack_tables(pos, ei); init_attack_tables(pos, ei); // Evaluate pieces and mobility - mobility = evaluate_pieces_of_color(pos, ei) - - evaluate_pieces_of_color(pos, ei); - ei.value += apply_weight(mobility, Weights[Mobility]); + value += evaluate_pieces_of_color(pos, ei, w_mob) + - evaluate_pieces_of_color(pos, ei, b_mob); - // Kings. Kings are evaluated after all other pieces for both sides, - // because we need complete attack information for all pieces when computing + value += apply_weight(w_mob - b_mob, Weights[Mobility]); + + // Evaluate kings after all other pieces for both sides, because we + // need complete attack information for all pieces when computing // the king safety evaluation. - evaluate_king(pos, ei); - evaluate_king(pos, ei); + value += evaluate_king(pos, ei, margins) + - evaluate_king(pos, ei, margins); // Evaluate tactical threats, we need full attack info including king - evaluate_threats(pos, ei); - evaluate_threats(pos, ei); + value += evaluate_threats(pos, ei) + - evaluate_threats(pos, ei); // Evaluate passed pawns, we need full attack info including king - evaluate_passed_pawns(pos, ei); - evaluate_passed_pawns(pos, ei); + value += evaluate_passed_pawns(pos, ei) + - evaluate_passed_pawns(pos, ei); Phase phase = mi->game_phase(); @@ -348,18 +345,18 @@ Value do_evaluate(const Position& pos, Value margins[]) { if ( square_file(pos.king_square(WHITE)) >= FILE_E && square_file(pos.king_square(BLACK)) <= FILE_D) - ei.value += make_score(ei.pi->queenside_storm_value(WHITE) - ei.pi->kingside_storm_value(BLACK), 0); + value += make_score(ei.pi->queenside_storm_value(WHITE) - ei.pi->kingside_storm_value(BLACK), 0); else if ( square_file(pos.king_square(WHITE)) <= FILE_D && square_file(pos.king_square(BLACK)) >= FILE_E) - ei.value += make_score(ei.pi->kingside_storm_value(WHITE) - ei.pi->queenside_storm_value(BLACK), 0); + value += make_score(ei.pi->kingside_storm_value(WHITE) - ei.pi->queenside_storm_value(BLACK), 0); // Evaluate space for both sides if (mi->space_weight() > 0) { int s = evaluate_space(pos, ei) - evaluate_space(pos, ei); - ei.value += apply_weight(make_score(s * mi->space_weight(), 0), Weights[Space]); + value += apply_weight(make_score(s * mi->space_weight(), 0), Weights[Space]); } } @@ -367,8 +364,8 @@ Value do_evaluate(const Position& pos, Value margins[]) { // colored bishop endgames, and use a lower scale for those if ( phase < PHASE_MIDGAME && pos.opposite_colored_bishops() - && ( (factor[WHITE] == SCALE_FACTOR_NORMAL && eg_value(ei.value) > VALUE_ZERO) - || (factor[BLACK] == SCALE_FACTOR_NORMAL && eg_value(ei.value) < VALUE_ZERO))) + && ( (factor[WHITE] == SCALE_FACTOR_NORMAL && eg_value(value) > VALUE_ZERO) + || (factor[BLACK] == SCALE_FACTOR_NORMAL && eg_value(value) < VALUE_ZERO))) { ScaleFactor sf; @@ -392,12 +389,8 @@ Value do_evaluate(const Position& pos, Value margins[]) { factor[BLACK] = sf; } - // Populate margins[] - margins[WHITE] = ei.margin[WHITE]; - margins[BLACK] = ei.margin[BLACK]; - // Interpolate between the middle game and the endgame score - return Sign[pos.side_to_move()] * scale_by_game_phase(ei.value, phase, factor); + return Sign[pos.side_to_move()] * scale_by_game_phase(value, phase, factor); } } // namespace @@ -487,7 +480,7 @@ namespace { // evaluate_outposts() evaluates bishop and knight outposts squares template - void evaluate_outposts(const Position& pos, EvalInfo& ei, Square s) { + Score evaluate_outposts(const Position& pos, EvalInfo& ei, Square s) { const Color Them = (Us == WHITE ? BLACK : WHITE); @@ -506,20 +499,20 @@ namespace { else bonus += bonus / 2; } - ei.value += Sign[Us] * make_score(bonus, bonus); + return make_score(bonus, bonus); } // evaluate_pieces<>() assigns bonuses and penalties to the pieces of a given color template - Score evaluate_pieces(const Position& pos, EvalInfo& ei, Bitboard no_mob_area) { + Score evaluate_pieces(const Position& pos, EvalInfo& ei, Score& mobility, Bitboard no_mob_area) { Bitboard b; Square s, ksq; int mob; File f; - Score mobility = SCORE_ZERO; + Score bonus = SCORE_ZERO; const Color Them = (Us == WHITE ? BLACK : WHITE); const Square* ptr = pos.piece_list_begin(Us, Piece); @@ -560,18 +553,18 @@ namespace { // Decrease score if we are attacked by an enemy pawn. Remaining part // of threat evaluation must be done later when we have full attack info. if (bit_is_set(ei.attackedBy[Them][PAWN], s)) - ei.value -= Sign[Us] * ThreatedByPawnPenalty[Piece]; + bonus -= ThreatedByPawnPenalty[Piece]; // Bishop and knight outposts squares if ((Piece == BISHOP || Piece == KNIGHT) && pos.square_is_weak(s, Us)) - evaluate_outposts(pos, ei, s); + bonus += evaluate_outposts(pos, ei, s); // Queen or rook on 7th rank if ( (Piece == ROOK || Piece == QUEEN) && relative_rank(Us, s) == RANK_7 && relative_rank(Us, pos.king_square(Them)) == RANK_8) { - ei.value += Sign[Us] * (Piece == ROOK ? RookOn7thBonus : QueenOn7thBonus); + bonus += (Piece == ROOK ? RookOn7thBonus : QueenOn7thBonus); } // Special extra evaluation for rooks @@ -582,9 +575,9 @@ namespace { if (ei.pi->file_is_half_open(Us, f)) { if (ei.pi->file_is_half_open(Them, f)) - ei.value += Sign[Us] * RookOpenFileBonus; + bonus += RookOpenFileBonus; else - ei.value += Sign[Us] * RookHalfOpenFileBonus; + bonus += RookHalfOpenFileBonus; } // Penalize rooks which are trapped inside a king. Penalize more if @@ -600,8 +593,8 @@ namespace { { // Is there a half-open file between the king and the edge of the board? if (!ei.pi->has_open_file_to_right(Us, square_file(ksq))) - ei.value -= Sign[Us] * make_score(pos.can_castle(Us) ? (TrappedRookPenalty - mob * 16) / 2 - : (TrappedRookPenalty - mob * 16), 0); + bonus -= make_score(pos.can_castle(Us) ? (TrappedRookPenalty - mob * 16) / 2 + : (TrappedRookPenalty - mob * 16), 0); } else if ( square_file(ksq) <= FILE_D && square_file(s) < square_file(ksq) @@ -609,12 +602,12 @@ namespace { { // Is there a half-open file between the king and the edge of the board? if (!ei.pi->has_open_file_to_left(Us, square_file(ksq))) - ei.value -= Sign[Us] * make_score(pos.can_castle(Us) ? (TrappedRookPenalty - mob * 16) / 2 - : (TrappedRookPenalty - mob * 16), 0); + bonus -= make_score(pos.can_castle(Us) ? (TrappedRookPenalty - mob * 16) / 2 + : (TrappedRookPenalty - mob * 16), 0); } } } - return mobility; + return bonus; } @@ -622,7 +615,7 @@ namespace { // and the type of attacked one. template - void evaluate_threats(const Position& pos, EvalInfo& ei) { + Score evaluate_threats(const Position& pos, EvalInfo& ei) { const Color Them = (Us == WHITE ? BLACK : WHITE); @@ -634,7 +627,7 @@ namespace { & ~ei.attackedBy[Them][PAWN] & ei.attackedBy[Us][0]; if (!weakEnemies) - return; + return SCORE_ZERO; // Add bonus according to type of attacked enemy pieces and to the // type of attacking piece, from knights to queens. Kings are not @@ -647,7 +640,7 @@ namespace { if (b & pos.pieces(pt2)) bonus += ThreatBonus[pt1][pt2]; } - ei.value += Sign[Us] * bonus; + return bonus; } @@ -655,32 +648,34 @@ namespace { // pieces of a given color. template - Score evaluate_pieces_of_color(const Position& pos, EvalInfo& ei) { + Score evaluate_pieces_of_color(const Position& pos, EvalInfo& ei, Score& mobility) { const Color Them = (Us == WHITE ? BLACK : WHITE); - Score mobility = SCORE_ZERO; + Score bonus = SCORE_ZERO; + + mobility = SCORE_ZERO; // Do not include in mobility squares protected by enemy pawns or occupied by our pieces const Bitboard no_mob_area = ~(ei.attackedBy[Them][PAWN] | pos.pieces_of_color(Us)); - mobility += evaluate_pieces(pos, ei, no_mob_area); - mobility += evaluate_pieces(pos, ei, no_mob_area); - mobility += evaluate_pieces(pos, ei, no_mob_area); - mobility += evaluate_pieces(pos, ei, no_mob_area); + bonus += evaluate_pieces(pos, ei, mobility, no_mob_area); + bonus += evaluate_pieces(pos, ei, mobility, no_mob_area); + bonus += evaluate_pieces(pos, ei, mobility, no_mob_area); + bonus += evaluate_pieces(pos, ei, mobility, no_mob_area); // Sum up all attacked squares ei.attackedBy[Us][0] = ei.attackedBy[Us][PAWN] | ei.attackedBy[Us][KNIGHT] | ei.attackedBy[Us][BISHOP] | ei.attackedBy[Us][ROOK] | ei.attackedBy[Us][QUEEN] | ei.attackedBy[Us][KING]; - return mobility; + return bonus; } // evaluate_king<>() assigns bonuses and penalties to a king of a given color template - void evaluate_king(const Position& pos, EvalInfo& ei) { + Score evaluate_king(const Position& pos, EvalInfo& ei, Value margins[]) { const Color Them = (Us == WHITE ? BLACK : WHITE); @@ -690,7 +685,7 @@ namespace { const Square ksq = pos.king_square(Us); // King shelter - ei.value += Sign[Us] * ei.pi->king_shelter(pos, Us, ksq); + Score bonus = ei.pi->king_shelter(pos, Us, ksq); // King safety. This is quite complicated, and is almost certainly far // from optimally tuned. @@ -761,21 +756,21 @@ namespace { attackUnits = Min(99, Max(0, attackUnits)); // Finally, extract the king danger score from the KingDangerTable[] - // array and subtract the score from evaluation. Set also ei.margin[] + // array and subtract the score from evaluation. Set also margins[] // value that will be used for pruning because this value can sometimes // be very big, and so capturing a single attacking piece can therefore // result in a score change far bigger than the value of the captured piece. - ei.value -= Sign[Us] * KingDangerTable[Us][attackUnits]; - ei.margin[Us] = mg_value(KingDangerTable[Us][attackUnits]); - } else - ei.margin[Us] = VALUE_ZERO; + bonus -= KingDangerTable[Us][attackUnits]; + margins[Us] += mg_value(KingDangerTable[Us][attackUnits]); + } + return bonus; } // evaluate_passed_pawns<>() evaluates the passed pawns of the given color template - void evaluate_passed_pawns(const Position& pos, EvalInfo& ei) { + Score evaluate_passed_pawns(const Position& pos, EvalInfo& ei) { const Color Them = (Us == WHITE ? BLACK : WHITE); @@ -784,7 +779,7 @@ namespace { Bitboard b = ei.pi->passed_pawns(Us); if (!b) - return; + return SCORE_ZERO; do { Square s = pop_1st_bit(&b); @@ -866,7 +861,7 @@ namespace { } while (b); // Add the scores to the middle game and endgame eval - ei.value += Sign[Us] * apply_weight(bonus, Weights[PassedPawns]); + return apply_weight(bonus, Weights[PassedPawns]); }