X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fevaluate.cpp;h=4bda8466e1fdaeddc3e346376d4a37f2a038dbae;hp=049a40deacd3de78f18023a0df22c45e338048b4;hb=f036239521fe4f6afb7e8cbc51d860ffa476f6bd;hpb=597ef38c392bc213cc078b49d024834f8b4c837b diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 049a40de..4bda8466 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -270,7 +270,7 @@ namespace { EvalInfo &ei); inline Value apply_weight(Value v, int w); - Value scale_by_game_phase(Value mv, Value ev, Phase ph, ScaleFactor sf[]); + Value scale_by_game_phase(Value mv, Value ev, Phase ph, const ScaleFactor sf[]); int count_1s_8bit(Bitboard b); @@ -322,8 +322,8 @@ Value evaluate(const Position &pos, EvalInfo &ei, int threadID) { ei.egValue += apply_weight(ei.pi->eg_value(), WeightPawnStructureEndgame); // Initialize king attack bitboards and king attack zones for both sides - ei.attackedBy[WHITE][KING] = pos.king_attacks(pos.king_square(WHITE)); - ei.attackedBy[BLACK][KING] = pos.king_attacks(pos.king_square(BLACK)); + ei.attackedBy[WHITE][KING] = pos.piece_attacks(pos.king_square(WHITE)); + ei.attackedBy[BLACK][KING] = pos.piece_attacks(pos.king_square(BLACK)); ei.kingZone[WHITE] = ei.attackedBy[BLACK][KING] | (ei.attackedBy[BLACK][KING] >> 8); ei.kingZone[BLACK] = ei.attackedBy[WHITE][KING] | (ei.attackedBy[WHITE][KING] << 8); @@ -419,36 +419,26 @@ Value evaluate(const Position &pos, EvalInfo &ei, int threadID) { && ( (factor[WHITE] == SCALE_FACTOR_NORMAL && ei.egValue > Value(0)) || (factor[BLACK] == SCALE_FACTOR_NORMAL && ei.egValue < Value(0)))) { - if (pos.non_pawn_material(WHITE) + pos.non_pawn_material(BLACK) == 2*BishopValueMidgame) - { - // Only the two bishops - if (pos.pawn_count(WHITE) + pos.pawn_count(BLACK) == 1) + ScaleFactor sf; + + // Only the two bishops ? + if ( pos.non_pawn_material(WHITE) == BishopValueMidgame + && pos.non_pawn_material(BLACK) == BishopValueMidgame) { - // KBP vs KB with only a single pawn; almost certainly a draw. - if (factor[WHITE] == SCALE_FACTOR_NORMAL) - factor[WHITE] = ScaleFactor(8); - if (factor[BLACK] == SCALE_FACTOR_NORMAL) - factor[BLACK] = ScaleFactor(8); + // Check for KBP vs KB with only a single pawn that is almost + // certainly a draw or at least two pawns. + bool one_pawn = (pos.pawn_count(WHITE) + pos.pawn_count(BLACK) == 1); + sf = one_pawn ? ScaleFactor(8) : ScaleFactor(32); } else - { - // At least two pawns - if (factor[WHITE] == SCALE_FACTOR_NORMAL) - factor[WHITE] = ScaleFactor(32); - if (factor[BLACK] == SCALE_FACTOR_NORMAL) - factor[BLACK] = ScaleFactor(32); - } - } - else - { - // Endgame with opposite-colored bishops, but also other pieces. - // Still a bit drawish, but not as drawish as with only the two - // bishops. + // Endgame with opposite-colored bishops, but also other pieces. Still + // a bit drawish, but not as drawish as with only the two bishops. + sf = ScaleFactor(50); + if (factor[WHITE] == SCALE_FACTOR_NORMAL) - factor[WHITE] = ScaleFactor(50); + factor[WHITE] = sf; if (factor[BLACK] == SCALE_FACTOR_NORMAL) - factor[BLACK] = ScaleFactor(50); - } + factor[BLACK] = sf; } // Interpolate between the middle game and the endgame score, and @@ -466,22 +456,18 @@ Value evaluate(const Position &pos, EvalInfo &ei, int threadID) { /// we should add scores from the pawn and material hash tables? Value quick_evaluate(const Position &pos) { - Color stm; - Value mgValue, egValue; - ScaleFactor factor[2] = {SCALE_FACTOR_NORMAL, SCALE_FACTOR_NORMAL}; - Phase phase; assert(pos.is_ok()); - stm = pos.side_to_move(); + static const + ScaleFactor sf[2] = {SCALE_FACTOR_NORMAL, SCALE_FACTOR_NORMAL}; - mgValue = pos.mg_value(); - egValue = pos.eg_value(); - phase = pos.game_phase(); - - Value value = scale_by_game_phase(mgValue, egValue, phase, factor); + Value mgv = pos.mg_value(); + Value egv = pos.eg_value(); + Phase ph = pos.game_phase(); + Color stm = pos.side_to_move(); - return Sign[stm] * value; + return Sign[stm] * scale_by_game_phase(mgv, egv, ph, sf); } @@ -515,9 +501,11 @@ void init_eval(int threads) { /// quit_eval() releases heap-allocated memory at program termination. void quit_eval() { - for(int i = 0; i < THREAD_MAX; i++) { - delete PawnTable[i]; - delete MaterialTable[i]; + + for (int i = 0; i < THREAD_MAX; i++) + { + delete PawnTable[i]; + delete MaterialTable[i]; } } @@ -556,11 +544,11 @@ namespace { // King attack if (b & ei.kingZone[us]) { - ei.kingAttackersCount[us]++; - ei.kingAttackersWeight[us] += AttackWeight; - Bitboard bb = (b & ei.attackedBy[them][KING]); - if (bb) - ei.kingZoneAttacksCount[us] += count_1s_max_15(bb); + ei.kingAttackersCount[us]++; + ei.kingAttackersWeight[us] += AttackWeight; + Bitboard bb = (b & ei.attackedBy[them][KING]); + if (bb) + ei.kingAdjacentZoneAttacksCount[us] += count_1s_max_15(bb); } // Mobility @@ -596,7 +584,7 @@ namespace { void evaluate_knight(const Position &p, Square s, Color us, EvalInfo &ei) { - Bitboard b = p.knight_attacks(s); + Bitboard b = p.piece_attacks(s); ei.attackedBy[us][KNIGHT] |= b; // King attack, mobility and outposts @@ -691,7 +679,7 @@ namespace { void evaluate_queen(const Position &p, Square s, Color us, EvalInfo &ei) { - Bitboard b = p.queen_attacks(s); + Bitboard b = p.piece_attacks(s); ei.attackedBy[us][QUEEN] |= b; // King attack and mobility @@ -709,6 +697,10 @@ namespace { } } + inline Bitboard shiftRowsDown(const Bitboard& b, int num) { + + return b >> (num << 3); + } // evaluate_king() assigns bonuses and penalties to a king of a given // color on a given square. @@ -717,32 +709,37 @@ namespace { int shelter = 0, sign = Sign[us]; - // King shelter. - if(relative_rank(us, s) <= RANK_4) { - Bitboard pawns = p.pawns(us) & this_and_neighboring_files_bb(s); - Rank r = square_rank(s); - for(int i = 0; i < 3; i++) - shelter += count_1s_8bit(pawns >> ((r+(i+1)*sign) * 8)) * (64>>i); - ei.mgValue += sign * Value(shelter); + // King shelter + if (relative_rank(us, s) <= RANK_4) + { + Bitboard pawns = p.pawns(us) & this_and_neighboring_files_bb(s); + Rank r = square_rank(s); + for (int i = 1; i < 4; i++) + shelter += count_1s_8bit(shiftRowsDown(pawns, r+i*sign)) * (128>>i); + + ei.mgValue += sign * Value(shelter); } // King safety. This is quite complicated, and is almost certainly far // from optimally tuned. Color them = opposite_color(us); - if(p.queen_count(them) >= 1 && ei.kingAttackersCount[them] >= 2 - && p.non_pawn_material(them) >= QueenValueMidgame + RookValueMidgame - && ei.kingZoneAttacksCount[them]) { + if ( p.queen_count(them) >= 1 + && ei.kingAttackersCount[them] >= 2 + && p.non_pawn_material(them) >= QueenValueMidgame + RookValueMidgame + && ei.kingAdjacentZoneAttacksCount[them]) + { // Is it the attackers turn to move? bool sente = (them == p.side_to_move()); // Find the attacked squares around the king which has no defenders - // apart from the king itself: + // apart from the king itself Bitboard undefended = - ei.attacked_by(them) & ~ei.attacked_by(us, PAWN) - & ~ei.attacked_by(us, KNIGHT) & ~ei.attacked_by(us, BISHOP) - & ~ei.attacked_by(us, ROOK) & ~ei.attacked_by(us, QUEEN) - & ei.attacked_by(us, KING); + ei.attacked_by(them) & ~ei.attacked_by(us, PAWN) + & ~ei.attacked_by(us, KNIGHT) & ~ei.attacked_by(us, BISHOP) + & ~ei.attacked_by(us, ROOK) & ~ei.attacked_by(us, QUEEN) + & ei.attacked_by(us, KING); + Bitboard occ = p.occupied_squares(), b, b2; // Initialize the 'attackUnits' variable, which is used later on as an @@ -751,113 +748,134 @@ namespace { // undefended squares around the king, the square of the king, and the // quality of the pawn shelter. int attackUnits = - Min((ei.kingAttackersCount[them] * ei.kingAttackersWeight[them]) / 2, 25) - + (ei.kingZoneAttacksCount[them] + count_1s_max_15(undefended)) * 3 - + InitKingDanger[relative_square(us, s)] - shelter / 32; + Min((ei.kingAttackersCount[them] * ei.kingAttackersWeight[them]) / 2, 25) + + (ei.kingAdjacentZoneAttacksCount[them] + count_1s_max_15(undefended)) * 3 + + InitKingDanger[relative_square(us, s)] - shelter / 32; - // Analyse safe queen contact checks: + // Analyse safe queen contact checks b = undefended & ei.attacked_by(them, QUEEN) & ~p.pieces_of_color(them); - if(b) { + if (b) + { Bitboard attackedByOthers = - ei.attacked_by(them, PAWN) | ei.attacked_by(them, KNIGHT) - | ei.attacked_by(them, BISHOP) | ei.attacked_by(them, ROOK); + ei.attacked_by(them, PAWN) | ei.attacked_by(them, KNIGHT) + | ei.attacked_by(them, BISHOP) | ei.attacked_by(them, ROOK); + b &= attackedByOthers; - if(b) { + if (b) + { // The bitboard b now contains the squares available for safe queen // contact checks. int count = count_1s_max_15(b); - attackUnits += QueenContactCheckBonus * count * (sente? 2 : 1); + attackUnits += QueenContactCheckBonus * count * (sente ? 2 : 1); // Is there a mate threat? - if(QueenContactMates && !p.is_check()) { + if (QueenContactMates && !p.is_check()) + { Bitboard escapeSquares = - p.king_attacks(s) & ~p.pieces_of_color(us) & ~attackedByOthers; - while(b) { - Square from, to = pop_1st_bit(&b); - if(!(escapeSquares - & ~queen_attacks_bb(to, occ & clear_mask_bb(s)))) { - // We have a mate, unless the queen is pinned or there - // is an X-ray attack through the queen. - for(int i = 0; i < p.queen_count(them); i++) { - from = p.queen_list(them, i); - if(bit_is_set(p.queen_attacks(from), to) - && !bit_is_set(p.pinned_pieces(them), from) - && !(rook_attacks_bb(to, occ & clear_mask_bb(from)) - & p.rooks_and_queens(us)) - && !(rook_attacks_bb(to, occ & clear_mask_bb(from)) - & p.rooks_and_queens(us))) - ei.mateThreat[them] = make_move(from, to); + p.piece_attacks(s) & ~p.pieces_of_color(us) & ~attackedByOthers; + + while (b) + { + Square from, to = pop_1st_bit(&b); + if (!(escapeSquares & ~queen_attacks_bb(to, occ & clear_mask_bb(s)))) + { + // We have a mate, unless the queen is pinned or there + // is an X-ray attack through the queen. + for (int i = 0; i < p.queen_count(them); i++) + { + from = p.queen_list(them, i); + if ( bit_is_set(p.piece_attacks(from), to) + && !bit_is_set(p.pinned_pieces(them), from) + && !(rook_attacks_bb(to, occ & clear_mask_bb(from)) & p.rooks_and_queens(us)) + && !(rook_attacks_bb(to, occ & clear_mask_bb(from)) & p.rooks_and_queens(us))) + + ei.mateThreat[them] = make_move(from, to); + } } - } } } } } - // Analyse safe rook contact checks: - if(RookContactCheckBonus) { - b = undefended & ei.attacked_by(them, ROOK) & ~p.pieces_of_color(them); - if(b) { - Bitboard attackedByOthers = - ei.attacked_by(them, PAWN) | ei.attacked_by(them, KNIGHT) - | ei.attacked_by(them, BISHOP) | ei.attacked_by(them, QUEEN); - b &= attackedByOthers; - if(b) { - int count = count_1s_max_15(b); - attackUnits += (RookContactCheckBonus * count * (sente? 2 : 1)); + if (RookContactCheckBonus) + { + b = undefended & ei.attacked_by(them, ROOK) & ~p.pieces_of_color(them); + if (b) + { + Bitboard attackedByOthers = + ei.attacked_by(them, PAWN) | ei.attacked_by(them, KNIGHT) + | ei.attacked_by(them, BISHOP) | ei.attacked_by(them, QUEEN); + + b &= attackedByOthers; + if (b) + { + int count = count_1s_max_15(b); + attackUnits += (RookContactCheckBonus * count * (sente? 2 : 1)); + } } - } } - // Analyse safe distance checks: - if(QueenCheckBonus > 0 || RookCheckBonus > 0) { - b = p.rook_attacks(s) & ~p.pieces_of_color(them) & ~ei.attacked_by(us); + if (QueenCheckBonus > 0 || RookCheckBonus > 0) + { + b = p.piece_attacks(s) & ~p.pieces_of_color(them) & ~ei.attacked_by(us); - // Queen checks - b2 = b & ei.attacked_by(them, QUEEN); - if(b2) attackUnits += QueenCheckBonus * count_1s_max_15(b2); + // Queen checks + b2 = b & ei.attacked_by(them, QUEEN); + if( b2) + attackUnits += QueenCheckBonus * count_1s_max_15(b2); - // Rook checks - b2 = b & ei.attacked_by(them, ROOK); - if(b2) attackUnits += RookCheckBonus * count_1s_max_15(b2); + // Rook checks + b2 = b & ei.attacked_by(them, ROOK); + if (b2) + attackUnits += RookCheckBonus * count_1s_max_15(b2); } - if(QueenCheckBonus > 0 || BishopCheckBonus > 0) { - b = p.bishop_attacks(s) & ~p.pieces_of_color(them) & ~ei.attacked_by(us); - // Queen checks - b2 = b & ei.attacked_by(them, QUEEN); - if(b2) attackUnits += QueenCheckBonus * count_1s_max_15(b2); - - // Bishop checks - b2 = b & ei.attacked_by(them, BISHOP); - if(b2) attackUnits += BishopCheckBonus * count_1s_max_15(b2); + if (QueenCheckBonus > 0 || BishopCheckBonus > 0) + { + b = p.piece_attacks(s) & ~p.pieces_of_color(them) & ~ei.attacked_by(us); + + // Queen checks + b2 = b & ei.attacked_by(them, QUEEN); + if (b2) + attackUnits += QueenCheckBonus * count_1s_max_15(b2); + + // Bishop checks + b2 = b & ei.attacked_by(them, BISHOP); + if (b2) + attackUnits += BishopCheckBonus * count_1s_max_15(b2); } - if(KnightCheckBonus > 0) { - b = p.knight_attacks(s) & ~p.pieces_of_color(them) & ~ei.attacked_by(us); - // Knight checks - b2 = b & ei.attacked_by(them, KNIGHT); - if(b2) attackUnits += KnightCheckBonus * count_1s_max_15(b2); + if (KnightCheckBonus > 0) + { + b = p.piece_attacks(s) & ~p.pieces_of_color(them) & ~ei.attacked_by(us); + + // Knight checks + b2 = b & ei.attacked_by(them, KNIGHT); + if (b2) + attackUnits += KnightCheckBonus * count_1s_max_15(b2); } // Analyse discovered checks (only for non-pawns right now, consider // adding pawns later). - if(DiscoveredCheckBonus) { + if (DiscoveredCheckBonus) + { b = p.discovered_check_candidates(them) & ~p.pawns(); - if(b) - attackUnits += - DiscoveredCheckBonus * count_1s_max_15(b) * (sente? 2 : 1); + if (b) + attackUnits += DiscoveredCheckBonus * count_1s_max_15(b) * (sente? 2 : 1); } // Has a mate threat been found? We don't do anything here if the // side with the mating move is the side to move, because in that // case the mating side will get a huge bonus at the end of the main // evaluation function instead. - if(ei.mateThreat[them] != MOVE_NONE) - attackUnits += MateThreatBonus; + if (ei.mateThreat[them] != MOVE_NONE) + attackUnits += MateThreatBonus; // Ensure that attackUnits is between 0 and 99, in order to avoid array // out of bounds errors: - if(attackUnits < 0) attackUnits = 0; - if(attackUnits >= 100) attackUnits = 99; + if (attackUnits < 0) + attackUnits = 0; + + if (attackUnits >= 100) + attackUnits = 99; // Finally, extract the king safety score from the SafetyTable[] array. // Add the score to the evaluation, and also to ei.futilityMargin. The @@ -866,9 +884,11 @@ namespace { // capturing a single attacking piece can therefore result in a score // change far bigger than the value of the captured piece. Value v = apply_weight(SafetyTable[attackUnits], WeightKingSafety[us]); + ei.mgValue -= sign * v; - if(us == p.side_to_move()) - ei.futilityMargin += v; + + if (us == p.side_to_move()) + ei.futilityMargin += v; } } @@ -1091,7 +1111,7 @@ namespace { // score, based on game phase. It also scales the return value by a // ScaleFactor array. - Value scale_by_game_phase(Value mv, Value ev, Phase ph, ScaleFactor sf[]) { + Value scale_by_game_phase(Value mv, Value ev, Phase ph, const ScaleFactor sf[]) { assert(mv > -VALUE_INFINITE && mv < VALUE_INFINITE); assert(ev > -VALUE_INFINITE && ev < VALUE_INFINITE);