X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fevaluate.cpp;h=f4b7fb757dfc3c340ef03229e70dcabd3bdf93b1;hp=74ee58f412e2e127497be66eb7341039b8e6c3d1;hb=f56af8e84db25c0d26fe762fbe171ec5518177bb;hpb=cde7b30b656471f28e1bfbafbf2c4de2c746bd2c diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 74ee58f4..f4b7fb75 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -6,12 +6,12 @@ it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - + Glaurung is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License along with this program. If not, see . */ @@ -44,123 +44,136 @@ namespace { const int GrainSize = 4; // Evaluation weights - int WeightMobilityMidgame = 0x100; - int WeightMobilityEndgame = 0x100; + int WeightMobilityMidgame = 0x100; + int WeightMobilityEndgame = 0x100; int WeightPawnStructureMidgame = 0x100; int WeightPawnStructureEndgame = 0x100; - int WeightPassedPawnsMidgame = 0x100; - int WeightPassedPawnsEndgame = 0x100; + int WeightPassedPawnsMidgame = 0x100; + int WeightPassedPawnsEndgame = 0x100; int WeightKingSafety[2] = { 0x100, 0x100 }; // Internal evaluation weights. These are applied on top of the evaluation // weights read from UCI parameters. The purpose is to be able to change // the evaluation weights while keeping the default values of the UCI // parameters at 100, which looks prettier. - const int WeightMobilityMidgameInternal = 0x100; - const int WeightMobilityEndgameInternal = 0x100; + const int WeightMobilityMidgameInternal = 0x100; + const int WeightMobilityEndgameInternal = 0x100; const int WeightPawnStructureMidgameInternal = 0x100; const int WeightPawnStructureEndgameInternal = 0x100; - const int WeightPassedPawnsMidgameInternal = 0x100; - const int WeightPassedPawnsEndgameInternal = 0x100; - const int WeightKingSafetyInternal = 0x100; + const int WeightPassedPawnsMidgameInternal = 0x100; + const int WeightPassedPawnsEndgameInternal = 0x100; + const int WeightKingSafetyInternal = 0x100; + + // Visually better to define tables constants + typedef Value V; // Knight mobility bonus in middle game and endgame, indexed by the number // of attacked squares not occupied by friendly piecess. const Value MidgameKnightMobilityBonus[] = { - Value(-30), Value(-20), Value(-10), Value(0), Value(10), - Value(20), Value(25), Value(30), Value(30) + // 0 1 2 3 4 5 6 7 8 + V(-30), V(-20),V(-10), V(0), V(10), V(20), V(25), V(30), V(30) }; const Value EndgameKnightMobilityBonus[] = { - Value(-30), Value(-20), Value(-10), Value(0), Value(10), - Value(20), Value(25), Value(30), Value(30) + // 0 1 2 3 4 5 6 7 8 + V(-30), V(-20),V(-10), V(0), V(10), V(20), V(25), V(30), V(30) }; // Bishop mobility bonus in middle game and endgame, indexed by the number // of attacked squares not occupied by friendly pieces. X-ray attacks through // queens are also included. const Value MidgameBishopMobilityBonus[] = { - Value(-30), Value(-15), Value(0), Value(15), Value(30), Value(45), - Value(58), Value(66), Value(72), Value(76), Value(78), Value(80), - Value(81), Value(82), Value(83), Value(83) + // 0 1 2 3 4 5 6 7 + V(-30), V(-15), V(0), V(15), V(30), V(45), V(58), V(66), + // 8 9 10 11 12 13 14 15 + V( 72), V( 76), V(78), V(80), V(81), V(82), V(83), V(83) }; const Value EndgameBishopMobilityBonus[] = { - Value(-30), Value(-15), Value(0), Value(15), Value(30), Value(45), - Value(58), Value(66), Value(72), Value(76), Value(78), Value(80), - Value(81), Value(82), Value(83), Value(83) + // 0 1 2 3 4 5 6 7 + V(-30), V(-15), V(0), V(15), V(30), V(45), V(58), V(66), + // 8 9 10 11 12 13 14 15 + V( 72), V( 76), V(78), V(80), V(81), V(82), V(83), V(83) }; // Rook mobility bonus in middle game and endgame, indexed by the number // of attacked squares not occupied by friendly pieces. X-ray attacks through // queens and rooks are also included. const Value MidgameRookMobilityBonus[] = { - Value(-18), Value(-12), Value(-6), Value(0), Value(6), Value(12), - Value(16), Value(21), Value(24), Value(27), Value(28), Value(29), - Value(30), Value(31), Value(32), Value(33) + // 0 1 2 3 4 5 6 7 + V(-18), V(-12), V(-6), V(0), V(6), V(12), V(16), V(21), + // 8 9 10 11 12 13 14 15 + V( 24), V( 27), V(28), V(29), V(30), V(31), V(32), V(33) }; - + const Value EndgameRookMobilityBonus[] = { - Value(-30), Value(-18), Value(-6), Value(6), Value(18), Value(30), - Value(42), Value(54), Value(66), Value(74), Value(78), Value(80), - Value(81), Value(82), Value(83), Value(83) + // 0 1 2 3 4 5 6 7 + V(-30), V(-18), V(-6), V(6), V(18), V(30), V(42), V(54), + // 8 9 10 11 12 13 14 15 + V( 66), V( 74), V(78), V(80), V(81), V(82), V(83), V(83) }; // Queen mobility bonus in middle game and endgame, indexed by the number // of attacked squares not occupied by friendly pieces. const Value MidgameQueenMobilityBonus[] = { - Value(-10), Value(-8), Value(-6), Value(-4), Value(-2), Value(0), Value(2), - Value(4), Value(6), Value(8), Value(10), Value(12), Value(13), Value(14), - Value(15), Value(16), Value(16), Value(16), Value(16), Value(16), - Value(16), Value(16), Value(16), Value(16), Value(16), Value(16), - Value(16), Value(16), Value(16), Value(16), Value(16), Value(16) + // 0 1 2 3 4 5 6 7 + V(-10), V(-8), V(-6), V(-4), V(-2), V( 0), V( 2), V( 4), + // 8 9 10 11 12 13 14 15 + V( 6), V( 8), V(10), V(12), V(13), V(14), V(15), V(16), + // 16 17 18 19 20 21 22 23 + V( 16), V(16), V(16), V(16), V(16), V(16), V(16), V(16), + // 24 25 26 27 28 29 30 31 + V( 16), V(16), V(16), V(16), V(16), V(16), V(16), V(16) }; const Value EndgameQueenMobilityBonus[] = { - Value(-20), Value(-15), Value(-10), Value(-5), Value(0), Value(5), - Value(10), Value(15), Value(19), Value(23), Value(27), Value(29), - Value(30), Value(30), Value(30), Value(30), Value(30), Value(30), - Value(30), Value(30), Value(30), Value(30), Value(30), Value(30), - Value(30), Value(30), Value(30), Value(30), Value(30), Value(30), - Value(30), Value(30) + // 0 1 2 3 4 5 6 7 + V(-20),V(-15),V(-10), V(-5), V( 0), V( 5), V(10), V(15), + // 8 9 10 11 12 13 14 15 + V( 19), V(23), V(27), V(29), V(30), V(30), V(30), V(30), + // 16 17 18 19 20 21 22 23 + V( 30), V(30), V(30), V(30), V(30), V(30), V(30), V(30), + // 24 25 26 27 28 29 30 31 + V( 30), V(30), V(30), V(30), V(30), V(30), V(30), V(30) }; - // Outpost bonuses for knights and bishops, indexed by square (from white's // point of view). const Value KnightOutpostBonus[64] = { - Value(0),Value(0),Value(0),Value(0),Value(0),Value(0),Value(0),Value(0), - Value(0),Value(0),Value(0),Value(0),Value(0),Value(0),Value(0),Value(0), - Value(0),Value(0),Value(5),Value(10),Value(10),Value(5),Value(0),Value(0), - Value(0),Value(5),Value(20),Value(30),Value(30),Value(20),Value(5),Value(0), - Value(0),Value(10),Value(30),Value(40),Value(40),Value(30),Value(10),Value(0), - Value(0),Value(5),Value(20),Value(20),Value(20),Value(20),Value(5),Value(0), - Value(0),Value(0),Value(0),Value(0),Value(0),Value(0),Value(0),Value(0), - Value(0),Value(0),Value(0),Value(0),Value(0),Value(0),Value(0),Value(0) + // A B C D E F G H + V(0), V(0), V(0), V(0), V(0), V(0), V(0), V(0), // 1 + V(0), V(0), V(0), V(0), V(0), V(0), V(0), V(0), // 2 + V(0), V(0), V(5),V(10),V(10), V(5), V(0), V(0), // 3 + V(0), V(5),V(20),V(30),V(30),V(20), V(5), V(0), // 4 + V(0),V(10),V(30),V(40),V(40),V(30),V(10), V(0), // 5 + V(0), V(5),V(20),V(20),V(20),V(20), V(5), V(0), // 6 + V(0), V(0), V(0), V(0), V(0), V(0), V(0), V(0), // 7 + V(0), V(0), V(0), V(0), V(0), V(0), V(0), V(0) // 8 }; const Value BishopOutpostBonus[64] = { - Value(0),Value(0),Value(0),Value(0),Value(0),Value(0),Value(0),Value(0), - Value(0),Value(0),Value(0),Value(0),Value(0),Value(0),Value(0),Value(0), - Value(0),Value(0),Value(5),Value(5),Value(5),Value(5),Value(0),Value(0), - Value(0),Value(5),Value(10),Value(10),Value(10),Value(10),Value(5),Value(0), - Value(0),Value(10),Value(20),Value(20),Value(20),Value(20),Value(10),Value(0), - Value(0),Value(5),Value(8),Value(8),Value(8),Value(8),Value(5),Value(0), - Value(0),Value(0),Value(0),Value(0),Value(0),Value(0),Value(0),Value(0), - Value(0),Value(0),Value(0),Value(0),Value(0),Value(0),Value(0),Value(0) + // A B C D E F G H + V(0), V(0), V(0), V(0), V(0), V(0), V(0), V(0), // 1 + V(0), V(0), V(0), V(0), V(0), V(0), V(0), V(0), // 2 + V(0), V(0), V(5), V(5), V(5), V(5), V(0), V(0), // 3 + V(0), V(5),V(10),V(10),V(10),V(10), V(5), V(0), // 4 + V(0),V(10),V(20),V(20),V(20),V(20),V(10), V(0), // 5 + V(0), V(5), V(8), V(8), V(8), V(8), V(5), V(0), // 6 + V(0), V(0), V(0), V(0), V(0), V(0), V(0), V(0), // 7 + V(0), V(0), V(0), V(0), V(0), V(0), V(0), V(0) // 8 }; // Bonus for unstoppable passed pawns: const Value UnstoppablePawnValue = Value(0x500); // Rooks and queens on the 7th rank: - const Value MidgameRookOn7thBonus = Value(50); - const Value EndgameRookOn7thBonus = Value(100); + const Value MidgameRookOn7thBonus = Value(50); + const Value EndgameRookOn7thBonus = Value(100); const Value MidgameQueenOn7thBonus = Value(25); const Value EndgameQueenOn7thBonus = Value(50); // Rooks on open files: - const Value RookOpenFileBonus = Value(40); + const Value RookOpenFileBonus = Value(40); const Value RookHalfOpenFileBonus = Value(20); // Penalty for rooks trapped inside a friendly king which has lost the @@ -188,26 +201,25 @@ namespace { ((1ULL << SQ_A8) | (1ULL << SQ_H8)) }; - /// King safety constants and variables. The king safety scores are taken /// from the array SafetyTable[]. Various little "meta-bonuses" measuring /// the strength of the attack are added up into an integer, which is used /// as an index to SafetyTable[]. // Attack weights for each piece type. - const int QueenAttackWeight = 5; - const int RookAttackWeight = 3; + const int QueenAttackWeight = 5; + const int RookAttackWeight = 3; const int BishopAttackWeight = 2; const int KnightAttackWeight = 2; - // Bonuses for safe checks for each piece type. + // Bonuses for safe checks for each piece type. int QueenContactCheckBonus = 4; - int RookContactCheckBonus = 2; - int QueenCheckBonus = 2; - int RookCheckBonus = 1; - int BishopCheckBonus = 1; - int KnightCheckBonus = 1; - int DiscoveredCheckBonus = 3; + int RookContactCheckBonus = 2; + int QueenCheckBonus = 2; + int RookCheckBonus = 1; + int BishopCheckBonus = 1; + int KnightCheckBonus = 1; + int DiscoveredCheckBonus = 3; // Scan for queen contact mates? const bool QueenContactMates = true; @@ -218,20 +230,20 @@ namespace { // InitKingDanger[] contains bonuses based on the position of the defending // king. const int InitKingDanger[64] = { - 2, 0, 2, 5, 5, 2, 0, 2, - 2, 2, 4, 8, 8, 4, 2, 2, - 7, 10, 12, 12, 12, 12, 10, 7, + 2, 0, 2, 5, 5, 2, 0, 2, + 2, 2, 4, 8, 8, 4, 2, 2, + 7, 10, 12, 12, 12, 12, 10, 7, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15 }; // SafetyTable[] contains the actual king safety scores. It is initialized // in init_safety(). Value SafetyTable[100]; - // Pawn and material hash tables, indexed by the current thread id: PawnInfoTable *PawnTable[8] = {0, 0, 0, 0, 0, 0, 0, 0}; MaterialInfoTable *MaterialTable[8] = {0, 0, 0, 0, 0, 0, 0, 0}; @@ -256,7 +268,7 @@ namespace { void evaluate_trapped_bishop_a1h1(const Position &pos, Square s, Color us, EvalInfo &ei); - Value apply_weight(Value v, int w); + inline Value apply_weight(Value v, int w); Value scale_by_game_phase(Value mv, Value ev, Phase ph, ScaleFactor sf[]); int count_1s_8bit(Bitboard b); @@ -340,7 +352,7 @@ Value evaluate(const Position &pos, EvalInfo &ei, int threadID) { s = pos.knight_list(c, i); evaluate_knight(pos, s, c, ei); } - + // Bishops for(int i = 0; i < pos.bishop_count(c); i++) { s = pos.bishop_list(c, i); @@ -378,8 +390,8 @@ Value evaluate(const Position &pos, EvalInfo &ei, int threadID) { } ei.attackedBy[c][0] = - ei.attackedBy[c][PAWN] | ei.attackedBy[c][KNIGHT] - | ei.attackedBy[c][BISHOP] | ei.attackedBy[c][ROOK] + ei.attackedBy[c][PAWN] | ei.attackedBy[c][KNIGHT] + | ei.attackedBy[c][BISHOP] | ei.attackedBy[c][ROOK] | ei.attackedBy[c][QUEEN] | ei.attackedBy[c][KING]; } @@ -408,7 +420,7 @@ Value evaluate(const Position &pos, EvalInfo &ei, int threadID) { ei.pi->kingside_storm_value(BLACK); else if(square_file(pos.king_square(WHITE)) <= FILE_D && square_file(pos.king_square(BLACK)) >= FILE_E) - ei.mgValue += + ei.mgValue += ei.pi->kingside_storm_value(WHITE) - ei.pi->queenside_storm_value(BLACK); } @@ -471,7 +483,7 @@ Value quick_evaluate(const Position &pos) { Value mgValue, egValue; ScaleFactor factor[2] = {SCALE_FACTOR_NORMAL, SCALE_FACTOR_NORMAL}; Phase phase; - + assert(pos.is_ok()); stm = pos.side_to_move(); @@ -484,32 +496,32 @@ Value quick_evaluate(const Position &pos) { return Sign[stm] * value; } - + /// init_eval() initializes various tables used by the evaluation function. void init_eval(int threads) { + assert(threads <= THREAD_MAX); - - for(int i = 0; i < threads; i++) { - if(PawnTable[i] == NULL) - PawnTable[i] = new PawnInfoTable(PawnTableSize); - if(MaterialTable[i] == NULL) - MaterialTable[i] = new MaterialInfoTable(MaterialTableSize); - } - for(int i = threads; i < THREAD_MAX; i++) { - if(PawnTable[i] != NULL) { - delete PawnTable[i]; - PawnTable[i] = NULL; - } - if(MaterialTable[i] != NULL) { - delete MaterialTable[i]; - MaterialTable[i] = NULL; + + for (int i = 0; i < THREAD_MAX; i++) + { + if (i >= threads) + { + delete PawnTable[i]; + delete MaterialTable[i]; + PawnTable[i] = NULL; + MaterialTable[i] = NULL; + continue; } + if (!PawnTable[i]) + PawnTable[i] = new PawnInfoTable(PawnTableSize); + if (!MaterialTable[i]) + MaterialTable[i] = new MaterialInfoTable(MaterialTableSize); } - for(Bitboard b = 0ULL; b < 256ULL; b++) - BitCount8Bit[b] = count_1s(b); + for (Bitboard b = 0ULL; b < 256ULL; b++) + BitCount8Bit[b] = count_1s(b); } @@ -559,215 +571,179 @@ void read_weights(Color sideToMove) { namespace { - // 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) { + // 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, + Square s = SQ_NONE, const Value* OutpostBonus = NULL) { Color them = opposite_color(us); - Bitboard b = p.knight_attacks(s); - ei.attackedBy[us][KNIGHT] |= b; // King attack - if(b & ei.attackZone[us]) { + if (b & ei.attackZone[us]) + { ei.attackCount[us]++; - ei.attackWeight[us] += KnightAttackWeight; + ei.attackWeight[us] += AttackWeight; Bitboard bb = (b & ei.attackedBy[them][KING]); - if(bb) ei.attacked[us] += count_1s_max_15(bb); + if (bb) + ei.attacked[us] += count_1s_max_15(bb); } - + // Mobility int mob = count_1s_max_15(b & ~p.pieces_of_color(us)); - ei.mgMobility += Sign[us] * MidgameKnightMobilityBonus[mob]; - ei.egMobility += Sign[us] * EndgameKnightMobilityBonus[mob]; - - // 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; + 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) { + + Bitboard b = p.knight_attacks(s); + ei.attackedBy[us][KNIGHT] |= b; + + // King attack, mobility and outposts + evaluate_common(p, b, us, ei, KnightAttackWeight, MidgameKnightMobilityBonus, + EndgameKnightMobilityBonus, s, KnightOutpostBonus); } // evaluate_bishop() assigns bonuses and penalties to a bishop of a given // color on a given square. - + 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 - if(b & ei.attackZone[us]) { - ei.attackCount[us]++; - ei.attackWeight[us] += BishopAttackWeight; - Bitboard bb = (b & ei.attackedBy[them][KING]); - if(bb) ei.attacked[us] += count_1s_max_15(bb); - } - - // Mobility: - int mob = count_1s_max_15(b & ~p.pieces_of_color(us)); - ei.mgMobility += Sign[us] * MidgameBishopMobilityBonus[mob]; - ei.egMobility += Sign[us] * EndgameBishopMobilityBonus[mob]; - - // 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); } - + // evaluate_rook() assigns bonuses and penalties to a rook of a given // color on a given square. - - void evaluate_rook(const Position &p, Square s, Color us, EvalInfo &ei) { - - 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; - } - } - // 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; - } + 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)); + Bitboard b = rook_attacks_bb(s, p.occupied_squares() & ~p.rooks_and_queens(us)); ei.attackedBy[us][ROOK] |= b; - // King attack - if(b & ei.attackZone[us]) { - ei.attackCount[us]++; - ei.attackWeight[us] += RookAttackWeight; - Bitboard bb = (b & ei.attackedBy[them][KING]); - if(bb) ei.attacked[us] += count_1s_max_15(bb); + // King attack and mobility + int mob = evaluate_common(p, b, us, ei, RookAttackWeight, MidgameRookMobilityBonus, + EndgameRookMobilityBonus); + + // Rook 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] * MidgameRookOn7thBonus; + ei.egValue += Sign[us] * EndgameRookOn7thBonus; } - // Mobility - int mob = count_1s_max_15(b & ~p.pieces_of_color(us)); - ei.mgMobility += Sign[us] * MidgameRookMobilityBonus[mob]; - ei.egMobility += Sign[us] * EndgameRookMobilityBonus[mob]; - - // 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); + // 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 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); + else + { + ei.mgValue += Sign[us] * RookHalfOpenFileBonus; + ei.egValue += Sign[us] * RookHalfOpenFileBonus; } - } + } + + // 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; + + 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); } } // evaluate_queen() assigns bonuses and penalties to a queen of a given // color on a given square. - - 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; - } + void evaluate_queen(const Position &p, Square s, Color us, EvalInfo &ei) { Bitboard b = p.queen_attacks(s); ei.attackedBy[us][QUEEN] |= b; - // King attack - if(b & ei.attackZone[us]) { - ei.attackCount[us]++; - ei.attackWeight[us] += QueenAttackWeight; - Bitboard bb = (b & ei.attackedBy[them][KING]); - if(bb) ei.attacked[us] += count_1s_max_15(bb); + // King attack and mobility + 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; } - - // Mobility - int mob = count_1s(b & ~p.pieces_of_color(us)); - ei.mgMobility += Sign[us] * MidgameQueenMobilityBonus[mob]; - ei.egMobility += Sign[us] * EndgameQueenMobilityBonus[mob]; } // evaluate_king() assigns bonuses and penalties to a king of a given // color on a given square. - + void evaluate_king(const Position &p, Square s, Color us, EvalInfo &ei) { - + 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++) @@ -776,7 +752,7 @@ namespace { } // King safety. This is quite complicated, and is almost certainly far - // from optimally tuned. + // from optimally tuned. Color them = opposite_color(us); if(p.queen_count(them) >= 1 && ei.attackCount[them] >= 2 && p.non_pawn_material(them) >= QueenValueMidgame + RookValueMidgame @@ -784,7 +760,7 @@ namespace { // 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: Bitboard undefended = @@ -857,7 +833,7 @@ namespace { } } } - + // Analyse safe distance checks: if(QueenCheckBonus > 0 || RookCheckBonus > 0) { b = p.rook_attacks(s) & ~p.pieces_of_color(them) & ~ei.attacked_by(us); @@ -939,7 +915,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); @@ -1004,7 +980,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; @@ -1067,7 +1043,7 @@ namespace { // evaluate_trapped_bishop_a7h7() determines whether a bishop on a7/h7 // (a2/h2 for black) is trapped by enemy pawns, and assigns a penalty // if it is. - + void evaluate_trapped_bishop_a7h7(const Position &pos, Square s, Color us, EvalInfo &ei) { Piece pawn = pawn_of_color(opposite_color(us)); @@ -1097,7 +1073,7 @@ namespace { // (a8/h8 for black) is trapped by a friendly pawn on b2/g2 (b7/g7 for // black), and assigns a penalty if it is. This pattern can obviously // only occur in Chess960 games. - + void evaluate_trapped_bishop_a1h1(const Position &pos, Square s, Color us, EvalInfo &ei) { Piece pawn = pawn_of_color(us); @@ -1127,7 +1103,7 @@ namespace { penalty = TrappedBishopA1H1Penalty; else penalty = TrappedBishopA1H1Penalty / 2; - + ei.mgValue -= Sign[us] * penalty; ei.egValue -= Sign[us] * penalty; } @@ -1145,7 +1121,7 @@ namespace { // scale_by_game_phase interpolates between a middle game and an endgame // 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[]) { assert(mv > -VALUE_INFINITE && mv < VALUE_INFINITE); assert(ev > -VALUE_INFINITE && ev < VALUE_INFINITE); @@ -1169,7 +1145,7 @@ namespace { // count_1s_8bit() counts the number of nonzero bits in the 8 least // significant bits of a Bitboard. This function is used by the king // shield evaluation. - + int count_1s_8bit(Bitboard b) { return int(BitCount8Bit[b & 0xFF]); } @@ -1182,15 +1158,15 @@ namespace { uciWeight = (uciWeight * 0x100) / 100; return (uciWeight * internalWeight) / 0x100; } - + // 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"); @@ -1204,7 +1180,7 @@ namespace { 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") @@ -1222,5 +1198,5 @@ namespace { if(SafetyTable[i] > Value(peak)) SafetyTable[i] = Value(peak); } - + }