X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fevaluate.cpp;h=f44173445bac916afc72090d68d5a217b0d4cc2d;hp=6f4de561fd42aa68156a4df42e25ec54f1b7790a;hb=3ee3cdc09b2d52a17f5db4b7ecb0fcc64c27ccd6;hpb=853ce65f178204f0c88098f937d759dd40c4c3c9 diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 6f4de561..f4417344 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -63,6 +63,7 @@ namespace { const int WeightPassedPawnsMidgameInternal = 0x100; const int WeightPassedPawnsEndgameInternal = 0x100; const int WeightKingSafetyInternal = 0x100; + const int WeightKingOppSafetyInternal = 0x100; // Visually better to define tables constants typedef Value V; @@ -274,6 +275,7 @@ namespace { int count_1s_8bit(Bitboard b); int compute_weight(int uciWeight, int internalWeight); + int weight_option(const std::string& opt, int weight); void init_safety(); } @@ -328,19 +330,19 @@ Value evaluate(const Position &pos, EvalInfo &ei, int threadID) { // 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.attackZone[WHITE] = + ei.kingZone[WHITE] = ei.attackedBy[BLACK][KING] | (ei.attackedBy[BLACK][KING] >> 8); - ei.attackZone[BLACK] = + ei.kingZone[BLACK] = ei.attackedBy[WHITE][KING] | (ei.attackedBy[WHITE][KING] << 8); // Initialize pawn attack bitboards for both sides: ei.attackedBy[WHITE][PAWN] = ((pos.pawns(WHITE) << 9) & ~FileABB) | ((pos.pawns(WHITE) << 7) & ~FileHBB); - ei.attackCount[WHITE] += + ei.kingAttackersCount[WHITE] += count_1s_max_15(ei.attackedBy[WHITE][PAWN] & ei.attackedBy[BLACK][KING])/2; ei.attackedBy[BLACK][PAWN] = ((pos.pawns(BLACK) >> 7) & ~FileABB) | ((pos.pawns(BLACK) >> 9) & ~FileHBB); - ei.attackCount[BLACK] += + ei.kingAttackersCount[BLACK] += count_1s_max_15(ei.attackedBy[BLACK][PAWN] & ei.attackedBy[WHITE][KING])/2; // Evaluate pieces: @@ -538,32 +540,19 @@ void quit_eval() { /// read_weights() reads evaluation weights from the corresponding UCI /// parameters. -void read_weights(Color sideToMove) { - WeightMobilityMidgame = - compute_weight(get_option_value_int("Mobility (Middle Game)"), - WeightMobilityMidgameInternal); - WeightMobilityEndgame = - compute_weight(get_option_value_int("Mobility (Endgame)"), - WeightMobilityEndgameInternal); - WeightPawnStructureMidgame = - compute_weight(get_option_value_int("Pawn Structure (Middle Game)"), - WeightPawnStructureMidgameInternal); - WeightPawnStructureEndgame = - compute_weight(get_option_value_int("Pawn Structure (Endgame)"), - WeightPawnStructureEndgameInternal); - WeightPassedPawnsMidgame = - compute_weight(get_option_value_int("Passed Pawns (Middle Game)"), - WeightPassedPawnsMidgameInternal); - WeightPassedPawnsEndgame = - compute_weight(get_option_value_int("Passed Pawns (Endgame)"), - WeightPassedPawnsEndgameInternal); - WeightKingSafety[sideToMove] = - compute_weight(get_option_value_int("Cowardice"), WeightKingSafetyInternal); - WeightKingSafety[opposite_color(sideToMove)] = - compute_weight(get_option_value_int("Aggressiveness"), - WeightKingSafetyInternal); - WeightKingSafety[opposite_color(sideToMove)] = - (get_option_value_int("Aggressiveness") * 0x100) / 100; +void read_weights(Color us) { + + WeightMobilityMidgame = weight_option("Mobility (Middle Game)", WeightMobilityMidgameInternal); + WeightMobilityEndgame = weight_option("Mobility (Endgame)", WeightMobilityEndgameInternal); + WeightPawnStructureMidgame = weight_option("Pawn Structure (Middle Game)", WeightPawnStructureMidgameInternal); + WeightPawnStructureEndgame = weight_option("Pawn Structure (Endgame)", WeightPawnStructureEndgameInternal); + WeightPassedPawnsMidgame = weight_option("Passed Pawns (Middle Game)", WeightPassedPawnsMidgameInternal); + WeightPassedPawnsEndgame = weight_option("Passed Pawns (Endgame)", WeightPassedPawnsEndgameInternal); + + Color them = opposite_color(us); + + WeightKingSafety[us] = weight_option("Cowardice", WeightKingSafetyInternal); + WeightKingSafety[them] = weight_option("Aggressiveness", WeightKingOppSafetyInternal); init_safety(); } @@ -574,16 +563,19 @@ namespace { // evaluate_common() computes terms common to all pieces attack int evaluate_common(const Position&p, const Bitboard& b, Color us, EvalInfo& ei, - int AttackWeight, const Value* mgBonus, const Value* egBonus) { + int AttackWeight, const Value* mgBonus, const Value* egBonus, + Square s = SQ_NONE, const Value* OutpostBonus = NULL) { Color them = opposite_color(us); // King attack - if(b & ei.attackZone[us]) { - ei.attackCount[us]++; - ei.attackWeight[us] += AttackWeight; + if (b & ei.kingZone[us]) + { + ei.kingAttackersCount[us]++; + ei.kingAttackersWeight[us] += AttackWeight; Bitboard bb = (b & ei.attackedBy[them][KING]); - if(bb) ei.attacked[us] += count_1s_max_15(bb); + if (bb) + ei.kingZoneAttacksCount[us] += count_1s_max_15(bb); } // Mobility @@ -591,43 +583,40 @@ namespace { ei.mgMobility += Sign[us] * mgBonus[mob]; ei.egMobility += Sign[us] * egBonus[mob]; + // Bishop and Knight outposts + if (!OutpostBonus || !p.square_is_weak(s, them)) + return mob; + + // Initial bonus based on square + Value v, bonus; + v = bonus = OutpostBonus[relative_square(us, s)]; + + // Increase bonus if supported by pawn, especially if the opponent has + // no minor piece which can exchange the outpost piece + if (v && (p.pawn_attacks(them, s) & p.pawns(us))) + { + bonus += v / 2; + if ( p.knight_count(them) == 0 + && (SquaresByColorBB[square_color(s)] & p.bishops(them)) == EmptyBoardBB) + bonus += v; + } + ei.mgValue += Sign[us] * bonus; + ei.egValue += Sign[us] * bonus; return mob; } + // evaluate_knight() assigns bonuses and penalties to a knight of a given // color on a given square. void evaluate_knight(const Position &p, Square s, Color us, EvalInfo &ei) { - Color them = opposite_color(us); Bitboard b = p.knight_attacks(s); ei.attackedBy[us][KNIGHT] |= b; - // King attack and mobility - evaluate_common(p, b, us, ei, KnightAttackWeight, - MidgameKnightMobilityBonus, EndgameKnightMobilityBonus); - - // Knight outposts: - if(p.square_is_weak(s, them)) { - Value v, bonus; - - // Initial bonus based on square: - v = bonus = KnightOutpostBonus[relative_square(us, s)]; - - // Increase bonus if supported by pawn, especially if the opponent has - // no minor piece which can exchange the outpost piece: - if(v && p.pawn_attacks(them, s) & p.pawns(us)) { - bonus += v/2; - if(p.knight_count(them) == 0 && - (SquaresByColorBB[square_color(s)] & - p.bishops(them)) == EmptyBoardBB) { - bonus += v; - } - } - - ei.mgValue += Sign[us] * bonus; - ei.egValue += Sign[us] * bonus; - } + // King attack, mobility and outposts + evaluate_common(p, b, us, ei, KnightAttackWeight, MidgameKnightMobilityBonus, + EndgameKnightMobilityBonus, s, KnightOutpostBonus); } @@ -636,37 +625,12 @@ namespace { void evaluate_bishop(const Position &p, Square s, Color us, EvalInfo &ei) { - Color them = opposite_color(us); - Bitboard b = - bishop_attacks_bb(s, p.occupied_squares() & ~p.queens(us)); - + Bitboard b = bishop_attacks_bb(s, p.occupied_squares() & ~p.queens(us)); ei.attackedBy[us][BISHOP] |= b; - // King attack and mobility - evaluate_common(p, b, us, ei, BishopAttackWeight, - MidgameBishopMobilityBonus, EndgameBishopMobilityBonus); - - // Bishop outposts: - if(p.square_is_weak(s, them)) { - Value v, bonus; - - // Initial bonus based on square: - v = bonus = BishopOutpostBonus[relative_square(us, s)]; - - // Increase bonus if supported by pawn, especially if the opponent has - // no minor piece which can exchange the outpost piece: - if(v && p.pawn_attacks(them, s) & p.pawns(us)) { - bonus += v/2; - if(p.knight_count(them) == 0 && - (SquaresByColorBB[square_color(s)] & - p.bishops(them)) == EmptyBoardBB) { - bonus += v; - } - } - - ei.mgValue += Sign[us] * bonus; - ei.egValue += Sign[us] * bonus; - } + // King attack, mobility and outposts + evaluate_common(p, b, us, ei, BishopAttackWeight, MidgameBishopMobilityBonus, + EndgameBishopMobilityBonus, s, BishopOutpostBonus); } @@ -675,62 +639,64 @@ namespace { void evaluate_rook(const Position &p, Square s, Color us, EvalInfo &ei) { + //Bitboard b = p.rook_attacks(s); + Bitboard b = rook_attacks_bb(s, p.occupied_squares() & ~p.rooks_and_queens(us)); + ei.attackedBy[us][ROOK] |= b; + + // King attack and mobility + int mob = evaluate_common(p, b, us, ei, RookAttackWeight, MidgameRookMobilityBonus, + EndgameRookMobilityBonus); + + // Rook on 7th rank Color them = opposite_color(us); - // Open and half-open files: - File f = square_file(s); - if(ei.pi->file_is_half_open(us, f)) { - if(ei.pi->file_is_half_open(them, f)) { - ei.mgValue += Sign[us] * RookOpenFileBonus; - ei.egValue += Sign[us] * RookOpenFileBonus; - } - else { - ei.mgValue += Sign[us] * RookHalfOpenFileBonus; - ei.egValue += Sign[us] * RookHalfOpenFileBonus; - } + if ( relative_rank(us, s) == RANK_7 + && relative_rank(us, p.king_square(them)) == RANK_8) + { + ei.mgValue += Sign[us] * MidgameRookOn7thBonus; + ei.egValue += Sign[us] * EndgameRookOn7thBonus; } - // Rook on 7th rank: - if(pawn_rank(us, s) == RANK_7 && - pawn_rank(us, p.king_square(them)) == RANK_8) { - ei.mgValue += Sign[us] * MidgameRookOn7thBonus; - ei.egValue += Sign[us] * EndgameRookOn7thBonus; + // Open and half-open files + File f = square_file(s); + if (ei.pi->file_is_half_open(us, f)) + { + if (ei.pi->file_is_half_open(them, f)) + { + ei.mgValue += Sign[us] * RookOpenFileBonus; + ei.egValue += Sign[us] * RookOpenFileBonus; + } + else + { + ei.mgValue += Sign[us] * RookHalfOpenFileBonus; + ei.egValue += Sign[us] * RookHalfOpenFileBonus; + } } - //Bitboard b = p.rook_attacks(s); - Bitboard b = - rook_attacks_bb(s, p.occupied_squares() & ~p.rooks_and_queens(us)); - ei.attackedBy[us][ROOK] |= b; + // Penalize rooks which are trapped inside a king. Penalize more if + // king has lost right to castle + if (mob > 6 || ei.pi->file_is_half_open(us, f)) + return; - // King attack and mobility - int mob = evaluate_common(p, b, us, ei, RookAttackWeight, - MidgameRookMobilityBonus, EndgameRookMobilityBonus); - - // Penalize rooks which are trapped inside a king which has lost the - // right to castle: - if(mob <= 6 && !ei.pi->file_is_half_open(us, f)) { - Square ksq = p.king_square(us); - if(square_file(ksq) >= FILE_E && square_file(s) > square_file(ksq) && - (pawn_rank(us, ksq) == RANK_1 || square_rank(ksq) == square_rank(s))) { - // 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.mgValue -= p.can_castle(us)? - Sign[us] * ((TrappedRookPenalty - mob * 16) / 2) : - Sign[us] * (TrappedRookPenalty - mob * 16); - } - } - else if(square_file(ksq) <= FILE_D && square_file(s) < square_file(ksq) - && (pawn_rank(us, ksq) == RANK_1 || - square_rank(ksq) == square_rank(s))) { - // 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.mgValue -= p.can_castle(us)? - Sign[us] * ((TrappedRookPenalty - mob * 16) / 2) : - Sign[us] * (TrappedRookPenalty - mob * 16); - } - } + Square ksq = p.king_square(us); + + if ( square_file(ksq) >= FILE_E + && square_file(s) > square_file(ksq) + && (relative_rank(us, ksq) == RANK_1 || square_rank(ksq) == square_rank(s))) + { + // 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.mgValue -= p.can_castle(us)? Sign[us] * ((TrappedRookPenalty - mob * 16) / 2) + : Sign[us] * (TrappedRookPenalty - mob * 16); + } + else if ( square_file(ksq) <= FILE_D + && square_file(s) < square_file(ksq) + && (relative_rank(us, ksq) == RANK_1 || square_rank(ksq) == square_rank(s))) + { + // 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.mgValue -= p.can_castle(us)? Sign[us] * ((TrappedRookPenalty - mob * 16) / 2) + : Sign[us] * (TrappedRookPenalty - mob * 16); } } @@ -740,21 +706,22 @@ namespace { void evaluate_queen(const Position &p, Square s, Color us, EvalInfo &ei) { - Color them = opposite_color(us); - - // Queen on 7th rank: - if(pawn_rank(us, s) == RANK_7 && - pawn_rank(us, p.king_square(them)) == RANK_8) { - ei.mgValue += Sign[us] * MidgameQueenOn7thBonus; - ei.egValue += Sign[us] * EndgameQueenOn7thBonus; - } - Bitboard b = p.queen_attacks(s); ei.attackedBy[us][QUEEN] |= b; // King attack and mobility - evaluate_common(p, b, us, ei, QueenAttackWeight, - MidgameQueenMobilityBonus, EndgameQueenMobilityBonus); + evaluate_common(p, b, us, ei, QueenAttackWeight, MidgameQueenMobilityBonus, + EndgameQueenMobilityBonus); + + // Queen on 7th rank + Color them = opposite_color(us); + + if ( relative_rank(us, s) == RANK_7 + && relative_rank(us, p.king_square(them)) == RANK_8) + { + ei.mgValue += Sign[us] * MidgameQueenOn7thBonus; + ei.egValue += Sign[us] * EndgameQueenOn7thBonus; + } } @@ -766,7 +733,7 @@ namespace { int shelter = 0, sign = Sign[us]; // King shelter. - if(pawn_rank(us, s) <= RANK_4) { + 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++) @@ -777,9 +744,9 @@ namespace { // 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.attackCount[them] >= 2 + if(p.queen_count(them) >= 1 && ei.kingAttackersCount[them] >= 2 && p.non_pawn_material(them) >= QueenValueMidgame + RookValueMidgame - && ei.attacked[them]) { + && ei.kingZoneAttacksCount[them]) { // Is it the attackers turn to move? bool sente = (them == p.side_to_move()); @@ -799,8 +766,8 @@ namespace { // undefended squares around the king, the square of the king, and the // quality of the pawn shelter. int attackUnits = - Min((ei.attackCount[them] * ei.attackWeight[them]) / 2, 25) - + (ei.attacked[them] + count_1s_max_15(undefended)) * 3 + 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; // Analyse safe queen contact checks: @@ -938,7 +905,7 @@ namespace { assert(pos.piece_on(s) == pawn_of_color(us)); assert(pos.pawn_is_passed(us, s)); - int r = int(pawn_rank(us, s) - RANK_2); + int r = int(relative_rank(us, s) - RANK_2); int tr = Max(0, r * (r-1)); Square blockSq = s + pawn_push(us); @@ -1003,7 +970,7 @@ namespace { + ((us == pos.side_to_move())? 0 : 1); if(d < 0) { - int mtg = RANK_8 - pawn_rank(us, s); + int mtg = RANK_8 - relative_rank(us, s); int blockerCount = count_1s_max_15(squares_in_front_of(us,s)&pos.occupied_squares()); mtg += blockerCount; @@ -1069,26 +1036,20 @@ namespace { void evaluate_trapped_bishop_a7h7(const Position &pos, Square s, Color us, EvalInfo &ei) { - Piece pawn = pawn_of_color(opposite_color(us)); - Square b6, b8; assert(square_is_ok(s)); assert(pos.piece_on(s) == bishop_of_color(us)); - if(square_file(s) == FILE_A) { - b6 = relative_square(us, SQ_B6); - b8 = relative_square(us, SQ_B8); - } - else { - b6 = relative_square(us, SQ_G6); - b8 = relative_square(us, SQ_G8); - } + Square b6 = relative_square(us, (square_file(s) == FILE_A) ? SQ_B6 : SQ_G6); + Square b8 = relative_square(us, (square_file(s) == FILE_A) ? SQ_B8 : SQ_G8); - if(pos.piece_on(b6) == pawn && pos.see(s, b6) < 0 && pos.see(s, b8) < 0) { - ei.mgValue -= Sign[us] * TrappedBishopA7H7Penalty; - ei.egValue -= Sign[us] * TrappedBishopA7H7Penalty; + if ( pos.piece_on(b6) == pawn_of_color(opposite_color(us)) + && pos.see(s, b6) < 0 + && pos.see(s, b8) < 0) + { + ei.mgValue -= Sign[us] * TrappedBishopA7H7Penalty; + ei.egValue -= Sign[us] * TrappedBishopA7H7Penalty; } - } @@ -1146,21 +1107,20 @@ namespace { // ScaleFactor array. Value scale_by_game_phase(Value mv, Value ev, Phase ph, ScaleFactor sf[]) { + assert(mv > -VALUE_INFINITE && mv < VALUE_INFINITE); assert(ev > -VALUE_INFINITE && ev < VALUE_INFINITE); assert(ph >= PHASE_ENDGAME && ph <= PHASE_MIDGAME); - if(ev > Value(0)) - ev = apply_scale_factor(ev, sf[WHITE]); - else - ev = apply_scale_factor(ev, sf[BLACK]); + ev = apply_scale_factor(ev, sf[(ev > Value(0) ? WHITE : BLACK)]); + + // Linearized sigmoid interpolator + int sph = int(ph); + sph -= (64 - sph) / 4; + sph = Min(PHASE_MIDGAME, Max(PHASE_ENDGAME, sph)); - // Superlinear interpolator - int sli_ph = int(ph); - sli_ph -= (64 - sli_ph) / 4; - sli_ph = Min(PHASE_MIDGAME, Max(PHASE_ENDGAME, sli_ph)); // ceiling + Value result = Value(int((mv * sph + ev * (128 - sph)) / 128)); - Value result = Value(int((mv * sli_ph + ev * (128 - sli_ph)) / 128)); return Value(int(result) & ~(GrainSize - 1)); } @@ -1183,43 +1143,53 @@ namespace { } + // helper used in read_weights() + int weight_option(const std::string& opt, int weight) { + + return compute_weight(get_option_value_int(opt), weight); + } + + // init_safety() initizes the king safety evaluation, based on UCI // parameters. It is called from read_weights(). void init_safety() { - double a, b; - int maxSlope, peak, i, j; QueenContactCheckBonus = get_option_value_int("Queen Contact Check Bonus"); - RookContactCheckBonus = get_option_value_int("Rook Contact Check Bonus"); - QueenCheckBonus = get_option_value_int("Queen Check Bonus"); - RookCheckBonus = get_option_value_int("Rook Check Bonus"); - BishopCheckBonus = get_option_value_int("Bishop Check Bonus"); - KnightCheckBonus = get_option_value_int("Knight Check Bonus"); - DiscoveredCheckBonus = get_option_value_int("Discovered Check Bonus"); - MateThreatBonus = get_option_value_int("Mate Threat Bonus"); - - a = get_option_value_int("King Safety Coefficient") / 100.0; - b = get_option_value_int("King Safety X Intercept") * 1.0; - maxSlope = get_option_value_int("King Safety Max Slope"); - peak = (get_option_value_int("King Safety Max Value") * 256) / 100; - - for(i = 0; i < 100; i++) { - if(i < b) SafetyTable[i] = Value(0); - else if(get_option_value_string("King Safety Curve") == "Quadratic") - SafetyTable[i] = Value((int)(a * (i - b) * (i - b))); - else if(get_option_value_string("King Safety Curve") == "Linear") - SafetyTable[i] = Value((int)(100 * a * (i - b))); + RookContactCheckBonus = get_option_value_int("Rook Contact Check Bonus"); + QueenCheckBonus = get_option_value_int("Queen Check Bonus"); + RookCheckBonus = get_option_value_int("Rook Check Bonus"); + BishopCheckBonus = get_option_value_int("Bishop Check Bonus"); + KnightCheckBonus = get_option_value_int("Knight Check Bonus"); + DiscoveredCheckBonus = get_option_value_int("Discovered Check Bonus"); + MateThreatBonus = get_option_value_int("Mate Threat Bonus"); + + int maxSlope = get_option_value_int("King Safety Max Slope"); + int peak = get_option_value_int("King Safety Max Value") * 256 / 100; + double a = get_option_value_int("King Safety Coefficient") / 100.0; + double b = get_option_value_int("King Safety X Intercept"); + bool quad = (get_option_value_string("King Safety Curve") == "Quadratic"); + bool linear = (get_option_value_string("King Safety Curve") == "Linear"); + + for (int i = 0; i < 100; i++) + { + if (i < b) + SafetyTable[i] = Value(0); + else if(quad) + SafetyTable[i] = Value((int)(a * (i - b) * (i - b))); + else if(linear) + SafetyTable[i] = Value((int)(100 * a * (i - b))); } - for(i = 0; i < 100; i++) - if(SafetyTable[i+1] - SafetyTable[i] > maxSlope) { - for(j = i + 1; j < 100; j++) - SafetyTable[j] = SafetyTable[j-1] + Value(maxSlope); - } - for(i = 0; i < 100; i++) - if(SafetyTable[i] > Value(peak)) - SafetyTable[i] = Value(peak); + for (int i = 0; i < 100; i++) + { + if (SafetyTable[i+1] - SafetyTable[i] > maxSlope) + for (int j = i + 1; j < 100; j++) + SafetyTable[j] = SafetyTable[j-1] + Value(maxSlope); + + if (SafetyTable[i] > Value(peak)) + SafetyTable[i] = Value(peak); + } } }