X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fevaluate.cpp;h=540f402e7187bdbe6fbca0a1e9fe3bb81b62d8c5;hp=2f51b1c3c766382f54b690f2ab6c1598decd424e;hb=843a5961e1d9c938e692a115b6bc8774f20d5769;hpb=8307da0de77c9c7bbf7c56a7d9c8a688ff4dfb4e diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 2f51b1c3..540f402e 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -18,7 +18,6 @@ */ #include -#include #include #include #include @@ -30,6 +29,8 @@ #include "thread.h" #include "ucioption.h" +Color EvalRootColor; + namespace { // Struct EvalInfo contains various information computed and collected @@ -156,8 +157,8 @@ namespace { const Score QueenOn7thBonus = make_score(27, 54); // Rooks on open files (modified by Joona Kiiski) - const Score RookOpenFileBonus = make_score(43, 43); - const Score RookHalfOpenFileBonus = make_score(19, 19); + const Score RookOpenFileBonus = make_score(43, 21); + const Score RookHalfOpenFileBonus = make_score(19, 10); // Penalty for rooks trapped inside a friendly king which has lost the // right to castle. @@ -251,7 +252,6 @@ namespace { inline Score apply_weight(Score v, Score weight); Value scale_by_game_phase(const Score& v, Phase ph, ScaleFactor sf); Score weight_option(const std::string& mgOpt, const std::string& egOpt, Score internalWeight); - void init_safety(); double to_cp(Value v); void trace_add(int idx, Score term_w, Score term_b = SCORE_ZERO); } @@ -390,27 +390,42 @@ Value do_evaluate(const Position& pos, Value& margin) { } // namespace -/// read_weights() reads evaluation weights from the corresponding UCI parameters +/// eval_init() reads evaluation weights from the corresponding UCI parameters +/// and setup weights and tables. +void eval_init() { -void read_evaluation_uci_options(Color us) { + const Value MaxSlope = Value(30); + const Value Peak = Value(1280); + Value t[100]; // King safety is asymmetrical. Our king danger level is weighted by // "Cowardice" UCI parameter, instead the opponent one by "Aggressiveness". - const int kingDangerUs = (us == WHITE ? KingDangerUs : KingDangerThem); - const int kingDangerThem = (us == WHITE ? KingDangerThem : KingDangerUs); - Weights[Mobility] = weight_option("Mobility (Middle Game)", "Mobility (Endgame)", WeightsInternal[Mobility]); Weights[PassedPawns] = weight_option("Passed Pawns (Middle Game)", "Passed Pawns (Endgame)", WeightsInternal[PassedPawns]); Weights[Space] = weight_option("Space", "Space", WeightsInternal[Space]); - Weights[kingDangerUs] = weight_option("Cowardice", "Cowardice", WeightsInternal[KingDangerUs]); - Weights[kingDangerThem] = weight_option("Aggressiveness", "Aggressiveness", WeightsInternal[KingDangerThem]); + Weights[KingDangerUs] = weight_option("Cowardice", "Cowardice", WeightsInternal[KingDangerUs]); + Weights[KingDangerThem] = weight_option("Aggressiveness", "Aggressiveness", WeightsInternal[KingDangerThem]); // If running in analysis mode, make sure we use symmetrical king safety. We do this // by replacing both Weights[kingDangerUs] and Weights[kingDangerThem] by their average. if (Options["UCI_AnalyseMode"]) - Weights[kingDangerUs] = Weights[kingDangerThem] = (Weights[kingDangerUs] + Weights[kingDangerThem]) / 2; + Weights[KingDangerUs] = Weights[KingDangerThem] = (Weights[KingDangerUs] + Weights[KingDangerThem]) / 2; + + // First setup the base table + for (int i = 0; i < 100; i++) + { + t[i] = Value(int(0.4 * i * i)); + + if (i > 0) + t[i] = std::min(t[i], t[i - 1] + MaxSlope); + + t[i] = std::min(t[i], Peak); + } - init_safety(); + // Then apply the weights and get the final KingDangerTable[] array + for (Color c = WHITE; c <= BLACK; c++) + for (int i = 0; i < 100; i++) + KingDangerTable[c == WHITE][i] = apply_weight(make_score(t[i], 0), Weights[KingDangerUs + c]); } @@ -422,7 +437,6 @@ namespace { template void init_eval_info(const Position& pos, EvalInfo& ei) { - const BitCountType Max15 = HasPopCnt ? CNT_POPCNT : Is64Bit ? CNT64_MAX15 : CNT32_MAX15; const Color Them = (Us == WHITE ? BLACK : WHITE); Bitboard b = ei.attackedBy[Them][KING] = pos.attacks_from(pos.king_square(Them)); @@ -434,7 +448,7 @@ namespace { { ei.kingRing[Them] = (b | (Us == WHITE ? b >> 8 : b << 8)); b &= ei.attackedBy[Us][PAWN]; - ei.kingAttackersCount[Us] = b ? count_1s(b) / 2 : 0; + ei.kingAttackersCount[Us] = b ? popcount(b) / 2 : 0; ei.kingAdjacentZoneAttacksCount[Us] = ei.kingAttackersWeight[Us] = 0; } else ei.kingRing[Them] = ei.kingAttackersCount[Us] = 0; @@ -455,7 +469,7 @@ namespace { // Increase bonus if supported by pawn, especially if the opponent has // no minor piece which can exchange the outpost piece. - if (bonus && bit_is_set(ei.attackedBy[Us][PAWN], s)) + if (bonus && (ei.attackedBy[Us][PAWN] & s)) { if ( !pos.pieces(KNIGHT, Them) && !(same_color_squares(s) & pos.pieces(BISHOP, Them))) @@ -478,8 +492,6 @@ namespace { File f; Score score = SCORE_ZERO; - const BitCountType Full = HasPopCnt ? CNT_POPCNT : Is64Bit ? CNT64 : CNT32; - const BitCountType Max15 = HasPopCnt ? CNT_POPCNT : Is64Bit ? CNT64_MAX15 : CNT32_MAX15; const Color Them = (Us == WHITE ? BLACK : WHITE); const Square* pl = pos.piece_list(Us, Piece); @@ -491,34 +503,43 @@ namespace { if (Piece == KNIGHT || Piece == QUEEN) b = pos.attacks_from(s); else if (Piece == BISHOP) - b = bishop_attacks_bb(s, pos.occupied_squares() & ~pos.pieces(QUEEN, Us)); + b = attacks_bb(s, pos.occupied_squares() & ~pos.pieces(QUEEN, Us)); else if (Piece == ROOK) - b = rook_attacks_bb(s, pos.occupied_squares() & ~pos.pieces(ROOK, QUEEN, Us)); + b = attacks_bb(s, pos.occupied_squares() & ~pos.pieces(ROOK, QUEEN, Us)); else assert(false); - // Update attack info ei.attackedBy[Us][Piece] |= b; - // King attacks if (b & ei.kingRing[Them]) { ei.kingAttackersCount[Us]++; ei.kingAttackersWeight[Us] += KingAttackWeights[Piece]; Bitboard bb = (b & ei.attackedBy[Them][KING]); if (bb) - ei.kingAdjacentZoneAttacksCount[Us] += count_1s(bb); + ei.kingAdjacentZoneAttacksCount[Us] += popcount(bb); } - // Mobility - mob = (Piece != QUEEN ? count_1s(b & mobilityArea) - : count_1s(b & mobilityArea)); + mob = (Piece != QUEEN ? popcount(b & mobilityArea) + : popcount(b & mobilityArea)); mobility += MobilityBonus[Piece][mob]; + // Add a bonus if a slider is pinning an enemy piece + if ( (Piece == BISHOP || Piece == ROOK || Piece == QUEEN) + && (PseudoAttacks[Piece][pos.king_square(Them)] & s)) + { + b = BetweenBB[s][pos.king_square(Them)] & pos.occupied_squares(); + + assert(b); + + if (single_bit(b) && (b & pos.pieces(Them))) + score += ThreatBonus[Piece][type_of(pos.piece_on(first_1(b)))]; + } + // 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)) + if (ei.attackedBy[Them][PAWN] & s) score -= ThreatenedByPawnPenalty[Piece]; // Bishop and knight outposts squares @@ -667,7 +688,6 @@ namespace { template Score evaluate_king(const Position& pos, EvalInfo& ei, Value margins[]) { - const BitCountType Max15 = HasPopCnt ? CNT_POPCNT : Is64Bit ? CNT64_MAX15 : CNT32_MAX15; const Color Them = (Us == WHITE ? BLACK : WHITE); Bitboard undefended, b, b1, b2, safe; @@ -695,7 +715,7 @@ namespace { // attacked and undefended squares around our king, the square of the // king, and the quality of the pawn shelter. attackUnits = std::min(25, (ei.kingAttackersCount[Them] * ei.kingAttackersWeight[Them]) / 2) - + 3 * (ei.kingAdjacentZoneAttacksCount[Them] + count_1s(undefended)) + + 3 * (ei.kingAdjacentZoneAttacksCount[Them] + popcount(undefended)) + InitKingDanger[relative_square(Us, ksq)] - mg_value(ei.pi->king_shelter(pos, ksq)) / 32; @@ -709,7 +729,7 @@ namespace { | ei.attackedBy[Them][BISHOP] | ei.attackedBy[Them][ROOK]); if (b) attackUnits += QueenContactCheckBonus - * count_1s(b) + * popcount(b) * (Them == pos.side_to_move() ? 2 : 1); } @@ -718,7 +738,7 @@ namespace { b = undefended & ei.attackedBy[Them][ROOK] & ~pos.pieces(Them); // Consider only squares where the enemy rook gives check - b &= RookPseudoAttacks[ksq]; + b &= PseudoAttacks[ROOK][ksq]; if (b) { @@ -727,7 +747,7 @@ namespace { | ei.attackedBy[Them][BISHOP] | ei.attackedBy[Them][QUEEN]); if (b) attackUnits += RookContactCheckBonus - * count_1s(b) + * popcount(b) * (Them == pos.side_to_move() ? 2 : 1); } @@ -740,22 +760,22 @@ namespace { // Enemy queen safe checks b = (b1 | b2) & ei.attackedBy[Them][QUEEN]; if (b) - attackUnits += QueenCheckBonus * count_1s(b); + attackUnits += QueenCheckBonus * popcount(b); // Enemy rooks safe checks b = b1 & ei.attackedBy[Them][ROOK]; if (b) - attackUnits += RookCheckBonus * count_1s(b); + attackUnits += RookCheckBonus * popcount(b); // Enemy bishops safe checks b = b2 & ei.attackedBy[Them][BISHOP]; if (b) - attackUnits += BishopCheckBonus * count_1s(b); + attackUnits += BishopCheckBonus * popcount(b); // Enemy knights safe checks b = pos.attacks_from(ksq) & ei.attackedBy[Them][KNIGHT] & safe; if (b) - attackUnits += KnightCheckBonus * count_1s(b); + attackUnits += KnightCheckBonus * popcount(b); // To index KingDangerTable[] attackUnits must be in [0, 99] range attackUnits = std::min(99, std::max(0, attackUnits)); @@ -765,8 +785,8 @@ namespace { // 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. - score -= KingDangerTable[Us][attackUnits]; - margins[Us] += mg_value(KingDangerTable[Us][attackUnits]); + score -= KingDangerTable[Us == EvalRootColor][attackUnits]; + margins[Us] += mg_value(KingDangerTable[Us == EvalRootColor][attackUnits]); } if (Trace) @@ -845,7 +865,7 @@ namespace { // Increase the bonus if the passed pawn is supported by a friendly pawn // on the same rank and a bit smaller if it's on the previous rank. - supportingPawns = pos.pieces(PAWN, Us) & neighboring_files_bb(file_of(s)); + supportingPawns = pos.pieces(PAWN, Us) & adjacent_files_bb(file_of(s)); if (supportingPawns & rank_bb(s)) ebonus += Value(r * 20); @@ -879,8 +899,6 @@ namespace { Score evaluate_unstoppable_pawns(const Position& pos, EvalInfo& ei) { - const BitCountType Max15 = HasPopCnt ? CNT_POPCNT : Is64Bit ? CNT64_MAX15 : CNT32_MAX15; - Bitboard b, b2, blockers, supporters, queeningPath, candidates; Square s, blockSq, queeningSquare; Color c, winnerSide, loserSide; @@ -893,7 +911,7 @@ namespace { for (c = WHITE; c <= BLACK; c++) { // Skip if other side has non-pawn pieces - if (pos.non_pawn_material(flip(c))) + if (pos.non_pawn_material(~c)) continue; b = ei.pi->passed_pawns(c); @@ -906,7 +924,7 @@ namespace { // Compute plies to queening and check direct advancement movesToGo = rank_distance(s, queeningSquare) - int(relative_rank(c, s) == RANK_2); - oppMovesToGo = square_distance(pos.king_square(flip(c)), queeningSquare) - int(c != pos.side_to_move()); + oppMovesToGo = square_distance(pos.king_square(~c), queeningSquare) - int(c != pos.side_to_move()); pathDefended = ((ei.attackedBy[c][0] & queeningPath) == queeningPath); if (movesToGo >= oppMovesToGo && !pathDefended) @@ -918,7 +936,7 @@ namespace { assert((queeningPath & pos.occupied_squares()) == (queeningPath & pos.pieces(c))); // Add moves needed to free the path from friendly pieces and retest condition - movesToGo += count_1s(queeningPath & pos.pieces(c)); + movesToGo += popcount(queeningPath & pos.pieces(c)); if (movesToGo >= oppMovesToGo && !pathDefended) continue; @@ -934,7 +952,7 @@ namespace { return SCORE_ZERO; winnerSide = (pliesToQueen[WHITE] < pliesToQueen[BLACK] ? WHITE : BLACK); - loserSide = flip(winnerSide); + loserSide = ~winnerSide; // Step 3. Can the losing side possibly create a new passed pawn and thus prevent the loss? b = candidates = pos.pieces(PAWN, loserSide); @@ -951,7 +969,7 @@ namespace { // Check if (without even considering any obstacles) we're too far away or doubled if ( pliesToQueen[winnerSide] + 3 <= pliesToGo || (squares_in_front_of(loserSide, s) & pos.pieces(PAWN, loserSide))) - clear_bit(&candidates, s); + candidates ^= s; } // If any candidate is already a passed pawn it _may_ promote in time. We give up. @@ -973,7 +991,7 @@ namespace { pliesToGo = 2 * movesToGo - int(loserSide == pos.side_to_move()); // Generate list of blocking pawns and supporters - supporters = neighboring_files_bb(file_of(s)) & candidates; + supporters = adjacent_files_bb(file_of(s)) & candidates; opposed = squares_in_front_of(loserSide, s) & pos.pieces(PAWN, winnerSide); blockers = passed_pawn_mask(loserSide, s) & pos.pieces(PAWN, winnerSide); @@ -1046,7 +1064,6 @@ namespace { template int evaluate_space(const Position& pos, EvalInfo& ei) { - const BitCountType Max15 = HasPopCnt ? CNT_POPCNT : Is64Bit ? CNT64_MAX15 : CNT32_MAX15; const Color Them = (Us == WHITE ? BLACK : WHITE); // Find the safe squares for our pieces inside the area defined by @@ -1062,7 +1079,7 @@ namespace { behind |= (Us == WHITE ? behind >> 8 : behind << 8); behind |= (Us == WHITE ? behind >> 16 : behind << 16); - return count_1s(safe) + count_1s(behind & safe); + return popcount(safe) + popcount(behind & safe); } @@ -1102,33 +1119,6 @@ namespace { } - // init_safety() initizes the king safety evaluation, based on UCI - // parameters. It is called from read_weights(). - - void init_safety() { - - const Value MaxSlope = Value(30); - const Value Peak = Value(1280); - Value t[100]; - - // First setup the base table - for (int i = 0; i < 100; i++) - { - t[i] = Value(int(0.4 * i * i)); - - if (i > 0) - t[i] = std::min(t[i], t[i - 1] + MaxSlope); - - t[i] = std::min(t[i], Peak); - } - - // Then apply the weights and get the final KingDangerTable[] array - for (Color c = WHITE; c <= BLACK; c++) - for (int i = 0; i < 100; i++) - KingDangerTable[c][i] = apply_weight(make_score(t[i], 0), Weights[KingDangerUs + c]); - } - - // A couple of little helpers used by tracing code, to_cp() converts a value to // a double in centipawns scale, trace_add() stores white and black scores.