X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fevaluate.cpp;h=a63b40ae98403a69153a2782c1bd066c75f2d153;hp=3379725c2b193cbeeb519c52664aacdca83ff93f;hb=24dac5ccd309837c6767dcf6b145be385eea2e21;hpb=6a79d5d10eb4313fd71abe249a64aaed6bba1e67 diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 3379725c..a63b40ae 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -2,6 +2,7 @@ Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad + Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -32,7 +33,7 @@ namespace { namespace Trace { - enum Term { // First 8 entries are for PieceType + enum Term { // The first 8 entries are for PieceType MATERIAL = 8, IMBALANCE, MOBILITY, THREAT, PASSED, SPACE, TOTAL, TERM_NB }; @@ -88,7 +89,7 @@ namespace { // which attack a square in the kingRing of the enemy king. int kingAttackersCount[COLOR_NB]; - // kingAttackersWeight[color] is the sum of the "weight" of the pieces of the + // kingAttackersWeight[color] is the sum of the "weights" of the pieces of the // given color which attack a square in the kingRing of the enemy king. The // weights of the individual piece types are given by the elements in the // KingAttackWeights array. @@ -106,18 +107,6 @@ namespace { Pawns::Entry* pi; }; - - // Evaluation weights, indexed by the corresponding evaluation term - enum { PawnStructure, PassedPawns, Space, KingSafety }; - - const struct Weight { int mg, eg; } Weights[] = { - {214, 203}, {193, 262}, {47, 0}, {330, 0} }; - - Score operator*(Score s, const Weight& w) { - return make_score(mg_value(s) * w.mg / 256, eg_value(s) * w.eg / 256); - } - - #define V(v) Value(v) #define S(mg, eg) make_score(mg, eg) @@ -160,33 +149,33 @@ namespace { const Score RookOnFile[2] = { S(19, 10), S(43, 21) }; // ThreatBySafePawn[PieceType] contains bonuses according to which piece - // type is attacked by a pawn which is protected or not attacked. + // type is attacked by a pawn which is protected or is not attacked. const Score ThreatBySafePawn[PIECE_TYPE_NB] = { S(0, 0), S(0, 0), S(176, 139), S(131, 127), S(217, 218), S(203, 215) }; - + // Threat[by minor/by rook][attacked PieceType] contains // bonuses according to which piece type attacks which one. - // Attacks on lesser pieces which are pawn defended are not considered. + // Attacks on lesser pieces which are pawn-defended are not considered. const Score Threat[][PIECE_TYPE_NB] = { { S(0, 0), S(0, 33), S(45, 43), S(46, 47), S(72,107), S(48,118) }, // by Minor { S(0, 0), S(0, 25), S(40, 62), S(40, 59), S( 0, 34), S(35, 48) } // by Rook }; // ThreatByKing[on one/on many] contains bonuses for King attacks on - // pawns or pieces which are not pawn defended. + // pawns or pieces which are not pawn-defended. const Score ThreatByKing[2] = { S(3, 62), S(9, 138) }; // 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) } + { V(5), V( 5), V(31), V(73), V(166), V(252) }, + { V(7), V(14), V(38), V(73), V(166), V(252) } }; // PassedFile[File] contains a bonus according to the file of a passed pawn const Score PassedFile[FILE_NB] = { - S( 12, 10), S( 3, 10), S( 1, -8), S(-27,-12), - S(-27,-12), S( 1, -8), S( 3, 10), S( 12, 10) + S( 9, 10), S( 2, 10), S( 1, -8), S(-20,-12), + S(-20,-12), S( 1, -8), S( 2, 10), S( 9, 10) }; // Assorted bonuses and penalties used by evaluation @@ -196,6 +185,7 @@ namespace { const Score TrappedRook = S(92, 0); const Score Checked = S(20, 20); const Score ThreatByHangingPawn = S(70, 63); + const Score LooseEnemies = S( 0, 25); const Score Hanging = S(48, 28); const Score ThreatByPawnPush = S(31, 19); const Score Unstoppable = S( 0, 20); @@ -225,7 +215,7 @@ namespace { const int KnightCheck = 14; - // eval_init() initializes king and attack bitboards for given color + // eval_init() initializes king and attack bitboards for a given color // adding pawn attacks. To be done at the beginning of the evaluation. template @@ -318,7 +308,7 @@ namespace { && (pos.pieces(PAWN) & (s + pawn_push(Us)))) score += MinorBehindPawn; - // Penalty for pawns on same color square of bishop + // Penalty for pawns on the same color square as the bishop if (Pt == BISHOP) score -= BishopPawns * ei.pi->pawns_on_same_color_squares(Us, s); @@ -351,7 +341,7 @@ namespace { if (ei.pi->semiopen_file(Us, file_of(s))) score += RookOnFile[!!ei.pi->semiopen_file(Them, file_of(s))]; - // Penalize when trapped by the king, even more if king cannot castle + // Penalize when trapped by the king, even more if the king cannot castle else if (mob <= 3) { Square ksq = pos.square(Us); @@ -367,7 +357,7 @@ namespace { if (DoTrace) Trace::add(Pt, Us, score); - // Recursively call evaluate_pieces() of next piece type until KING excluded + // Recursively call evaluate_pieces() of next piece type until KING is excluded return score - evaluate_pieces(pos, ei, mobility, mobilityArea); } @@ -435,39 +425,23 @@ namespace { b2 = pos.attacks_from(ksq) & safe; // Enemy queen safe checks - b = (b1 | b2) & ei.attackedBy[Them][QUEEN]; - if (b) - { - attackUnits += QueenCheck * popcount(b); - score -= Checked; - } + if ((b1 | b2) & ei.attackedBy[Them][QUEEN]) + attackUnits += QueenCheck, score -= Checked; // Enemy rooks safe checks - b = b1 & ei.attackedBy[Them][ROOK]; - if (b) - { - attackUnits += RookCheck * popcount(b); - score -= Checked; - } + if (b1 & ei.attackedBy[Them][ROOK]) + attackUnits += RookCheck, score -= Checked; // Enemy bishops safe checks - b = b2 & ei.attackedBy[Them][BISHOP]; - if (b) - { - attackUnits += BishopCheck * popcount(b); - score -= Checked; - } + if (b2 & ei.attackedBy[Them][BISHOP]) + attackUnits += BishopCheck, score -= Checked; // Enemy knights safe checks - b = pos.attacks_from(ksq) & ei.attackedBy[Them][KNIGHT] & safe; - if (b) - { - attackUnits += KnightCheck * popcount(b); - score -= Checked; - } + if (pos.attacks_from(ksq) & ei.attackedBy[Them][KNIGHT] & safe) + attackUnits += KnightCheck, score -= Checked; // Finally, extract the king danger score from the KingDanger[] - // array and subtract the score from evaluation. + // array and subtract the score from the evaluation. score -= KingDanger[std::max(std::min(attackUnits, 399), 0)]; } @@ -478,8 +452,8 @@ namespace { } - // evaluate_threats() assigns bonuses according to the type of attacking piece - // and the type of attacked one. + // evaluate_threats() assigns bonuses according to the types of the attacking + // and the attacked pieces. template Score evaluate_threats(const Position& pos, const EvalInfo& ei) { @@ -496,6 +470,11 @@ namespace { Bitboard b, weak, defended, safeThreats; Score score = SCORE_ZERO; + // Small bonus if the opponent has loose pawns or pieces + if ( (pos.pieces(Them) ^ pos.pieces(Them, QUEEN, KING)) + & ~(ei.attackedBy[Us][ALL_PIECES] | ei.attackedBy[Them][ALL_PIECES])) + score += LooseEnemies; + // Non-pawn enemies attacked by a pawn weak = (pos.pieces(Them) ^ pos.pieces(Them, PAWN)) & ei.attackedBy[Us][PAWN]; @@ -618,7 +597,7 @@ namespace { // assign a smaller bonus if the block square isn't attacked. int k = !unsafeSquares ? 18 : !(unsafeSquares & blockSq) ? 8 : 0; - // If the path to queen is fully defended, assign a big bonus. + // If the path to the queen is fully defended, assign a big bonus. // Otherwise assign a smaller bonus if the block square is defended. if (defendedSquares == squaresToQueen) k += 6; @@ -629,7 +608,7 @@ namespace { mbonus += k * rr, ebonus += k * rr; } else if (pos.pieces(Us) & blockSq) - mbonus += rr * 3 + r * 2 + 3, ebonus += rr + r * 2; + mbonus += rr + r * 2, ebonus += rr + r * 2; } // rr != 0 if (pos.count(Us) < pos.count(Them)) @@ -639,10 +618,10 @@ namespace { } if (DoTrace) - Trace::add(PASSED, Us, score * Weights[PassedPawns]); + Trace::add(PASSED, Us, score); // Add the scores to the middlegame and endgame eval - return score * Weights[PassedPawns]; + return score; } @@ -681,20 +660,21 @@ namespace { int weight = pos.count(Us) + pos.count(Us) + pos.count(Them) + pos.count(Them); - return make_score(bonus * weight * weight, 0); + return make_score(bonus * weight * weight * 2 / 11, 0); } // evaluate_initiative() computes the initiative correction value for the - // position, i.e. second order bonus/malus based on the known attacking/defending + // position, i.e., second order bonus/malus based on the known attacking/defending // status of the players. Score evaluate_initiative(const Position& pos, int asymmetry, Value eg) { - int kingDistance = distance(pos.square(WHITE), pos.square(BLACK)); + int kingDistance = distance(pos.square(WHITE), pos.square(BLACK)) + - distance(pos.square(WHITE), pos.square(BLACK)); int pawns = pos.count(WHITE) + pos.count(BLACK); // Compute the initiative bonus for the attacking side - int initiative = 8 * (pawns + asymmetry + kingDistance - 15); + int initiative = 8 * (asymmetry + kingDistance - 15) + 12 * pawns; // Now apply the bonus: note that we find the attacking side by extracting // the sign of the endgame value, and that we carefully cap the bonus so @@ -706,9 +686,9 @@ namespace { // evaluate_scale_factor() computes the scale factor for the winning side - ScaleFactor evaluate_scale_factor(const Position& pos, const EvalInfo& ei, Score score) { + ScaleFactor evaluate_scale_factor(const Position& pos, const EvalInfo& ei, Value eg) { - Color strongSide = eg_value(score) > VALUE_DRAW ? WHITE : BLACK; + Color strongSide = eg > VALUE_DRAW ? WHITE : BLACK; ScaleFactor sf = ei.me->scale_factor(pos, strongSide); // If we don't already have an unusual scale factor, check for certain @@ -719,7 +699,7 @@ namespace { 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. + // is almost a draw, in case of KBP vs KB, it 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(31) : ScaleFactor(9); @@ -731,7 +711,7 @@ namespace { } // Endings where weaker side can place his king in front of the opponent's // pawns are drawish. - else if ( abs(eg_value(score)) <= BishopValueEg + else if ( abs(eg) <= BishopValueEg && ei.pi->pawn_span(strongSide) <= 1 && !pos.pawn_passed(~strongSide, pos.square(~strongSide))) sf = ei.pi->pawn_span(strongSide) ? ScaleFactor(51) : ScaleFactor(37); @@ -770,7 +750,7 @@ Value Eval::evaluate(const Position& pos) { // Probe the pawn hash table ei.pi = Pawns::probe(pos); - score += ei.pi->pawns_score() * Weights[PawnStructure]; + score += ei.pi->pawns_score(); // Initialize attack and king safety bitboards ei.attackedBy[WHITE][ALL_PIECES] = ei.attackedBy[BLACK][ALL_PIECES] = 0; @@ -820,14 +800,14 @@ Value Eval::evaluate(const Position& pos) { // Evaluate space for both sides, only during opening if (pos.non_pawn_material(WHITE) + pos.non_pawn_material(BLACK) >= 12222) - score += ( evaluate_space(pos, ei) - - evaluate_space(pos, ei)) * Weights[Space]; + score += evaluate_space(pos, ei) + - evaluate_space(pos, ei); // Evaluate position potential for the winning side score += evaluate_initiative(pos, ei.pi->pawn_asymmetry(), eg_value(score)); // Evaluate scale factor for the winning side - ScaleFactor sf = evaluate_scale_factor(pos, ei, score); + ScaleFactor sf = evaluate_scale_factor(pos, ei, eg_value(score)); // Interpolate between a middlegame and a (scaled by 'sf') endgame score Value v = mg_value(score) * int(ei.me->game_phase()) @@ -840,10 +820,10 @@ Value Eval::evaluate(const Position& pos) { { Trace::add(MATERIAL, pos.psq_score()); Trace::add(IMBALANCE, ei.me->imbalance()); - Trace::add(PAWN, ei.pi->pawns_score() * Weights[PawnStructure]); + Trace::add(PAWN, ei.pi->pawns_score()); Trace::add(MOBILITY, mobility[WHITE], mobility[BLACK]); - Trace::add(SPACE, evaluate_space(pos, ei) * Weights[Space] - , evaluate_space(pos, ei) * Weights[Space]); + Trace::add(SPACE, evaluate_space(pos, ei) + , evaluate_space(pos, ei)); Trace::add(TOTAL, score); } @@ -896,13 +876,13 @@ std::string Eval::trace(const Position& pos) { void Eval::init() { - const int MaxSlope = 8700; - const int Peak = 1280000; + const int MaxSlope = 322; + const int Peak = 47410; 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]; + t = std::min(Peak, std::min(i * i - 16, t + MaxSlope)); + KingDanger[i] = make_score(t * 268 / 7700, 0); } }