X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fevaluate.cpp;h=12329fcdceef82a7872aa2f43af3c8dfd1344e2f;hp=30ed08793e948744db4bef81500057b3de5e3bde;hb=e4fd9a2df7d0977cc279d73d94e79a866daddb2f;hpb=d0e51bc0f0c77f93323aaa86c9c2485c41d38271 diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 30ed0879..12329fcd 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -1,13 +1,14 @@ /* - Glaurung, a UCI chess playing engine. - Copyright (C) 2004-2008 Tord Romstad + Stockfish, a UCI chess playing engine derived from Glaurung 2.1 + Copyright (C) 2004-2008 Tord Romstad (Glaurung author) + Copyright (C) 2008 Marco Costalba - Glaurung is free software: you can redistribute it and/or modify + Stockfish is free software: you can redistribute it and/or modify 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, + Stockfish 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. @@ -51,6 +52,7 @@ namespace { int WeightPassedPawnsMidgame = 0x100; int WeightPassedPawnsEndgame = 0x100; int WeightKingSafety[2] = { 0x100, 0x100 }; + int WeightSpace; // Internal evaluation weights. These are applied on top of the evaluation // weights read from UCI parameters. The purpose is to be able to change @@ -62,8 +64,9 @@ namespace { const int WeightPawnStructureEndgameInternal = 0x100; const int WeightPassedPawnsMidgameInternal = 0x100; const int WeightPassedPawnsEndgameInternal = 0x100; - const int WeightKingSafetyInternal = 0x100; - const int WeightKingOppSafetyInternal = 0x100; + const int WeightKingSafetyInternal = 0x110; + const int WeightKingOppSafetyInternal = 0x110; + const int WeightSpaceInternal = 0x30; // Visually better to define tables constants typedef Value V; @@ -202,6 +205,19 @@ namespace { ((1ULL << SQ_A8) | (1ULL << SQ_H8)) }; + // The SpaceMask[color] contains area of the board which is consdered by + // the space evaluation. In the middle game, each side is given a bonus + // based on how many squares inside this area are safe and available for + // friendly minor pieces. + const Bitboard SpaceMask[2] = { + (1ULL<kingside_storm_value(WHITE) - ei.pi->queenside_storm_value(BLACK); + + // Evaluate space for both sides + if (ei.mi->space_weight() > 0) + { + evaluate_space(pos, WHITE, ei); + evaluate_space(pos, BLACK, ei); + } } // Mobility @@ -413,7 +436,7 @@ Value evaluate(const Position &pos, EvalInfo &ei, int threadID) { ei.egValue += apply_weight(ei.egMobility, WeightMobilityEndgame); // If we don't already have an unusual scale factor, check for opposite - // colored bishop endgames, and use a lower scale for those: + // colored bishop endgames, and use a lower scale for those if ( phase < PHASE_MIDGAME && pos.opposite_colored_bishops() && ( (factor[WHITE] == SCALE_FACTOR_NORMAL && ei.egValue > Value(0)) @@ -526,6 +549,7 @@ void read_weights(Color us) { WeightKingSafety[us] = weight_option("Cowardice", WeightKingSafetyInternal); WeightKingSafety[them] = weight_option("Aggressiveness", WeightKingOppSafetyInternal); + WeightSpace = weight_option("Space", WeightSpaceInternal); init_safety(); } @@ -612,7 +636,6 @@ 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; @@ -743,14 +766,14 @@ namespace { Bitboard occ = p.occupied_squares(), b, b2; // Initialize the 'attackUnits' variable, which is used later on as an - // index to the SafetyTable[] array. The initial is based on the number - // and types of the attacking pieces, the number of attacked and + // index to the SafetyTable[] array. The initial value is based on the + // number and types of the attacking pieces, the number of attacked and // 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.kingAdjacentZoneAttacksCount[them] + count_1s_max_15(undefended)) * 3 - + InitKingDanger[relative_square(us, s)] - shelter / 32; + + InitKingDanger[relative_square(us, s)] - (shelter >> 5); // Analyse safe queen contact checks b = undefended & ei.attacked_by(them, QUEEN) & ~p.pieces_of_color(them); @@ -777,7 +800,7 @@ namespace { while (b) { Square from, to = pop_1st_bit(&b); - if (!(escapeSquares & ~queen_attacks_bb(to, occ & clear_mask_bb(s)))) + if (!(escapeSquares & ~queen_attacks_bb(to, occ & ClearMaskBB[s]))) { // We have a mate, unless the queen is pinned or there // is an X-ray attack through the queen. @@ -786,8 +809,8 @@ namespace { from = p.piece_list(them, QUEEN, 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))) + && !(rook_attacks_bb(to, occ & ClearMaskBB[from]) & p.rooks_and_queens(us)) + && !(rook_attacks_bb(to, occ & ClearMaskBB[from]) & p.rooks_and_queens(us))) ei.mateThreat[them] = make_move(from, to); } @@ -796,25 +819,8 @@ namespace { } } } - // 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)); - } - } - } - // Analyse safe distance checks: + + // Analyse safe distance checks if (QueenCheckBonus > 0 || RookCheckBonus > 0) { b = p.piece_attacks(s) & ~p.pieces_of_color(them) & ~ei.attacked_by(us); @@ -930,6 +936,13 @@ namespace { b2 = squares_in_front_of(us, s); b3 = b2 & ei.attacked_by(them); b4 = b2 & ei.attacked_by(us); + + // If there is an enemy rook or queen attacking the pawn from behind, + // add all X-ray attacks by the rook or queen. + if(bit_is_set(ei.attacked_by(them,ROOK)|ei.attacked_by(them,QUEEN),s) + && squares_behind(us, s) & pos.rooks_and_queens(them)) + b3 = b2; + if((b2 & pos.pieces_of_color(them)) == EmptyBoardBB) { // There are no enemy pieces in the pawn's path! Are any of the // squares in the pawn's path attacked by the enemy? @@ -1100,14 +1113,54 @@ namespace { } - // apply_weight applies an evaluation weight to a value. + // evaluate_space() computes the space evaluation for a given side. The + // space evaluation is a simple bonus based on the number of safe squares + // available for minor pieces on the central four files on ranks 2--4. Safe + // squares one, two or three squares behind a friendly pawn are counted + // twice. Finally, the space bonus is scaled by a weight taken from the + // material hash table. + + void evaluate_space(const Position &pos, Color us, EvalInfo &ei) { + + Color them = opposite_color(us); + + // Find the safe squares for our pieces inside the area defined by + // SpaceMask[us]. A square is unsafe it is attacked by an enemy + // pawn, or if it is undefended and attacked by an enemy piece. + + Bitboard safeSquares = + SpaceMask[us] & ~pos.pawns(us) & ~ei.attacked_by(them, PAWN) + & ~(~ei.attacked_by(us) & ei.attacked_by(them)); + + // Find all squares which are at most three squares behind some friendly + // pawn. + Bitboard behindFriendlyPawns = pos.pawns(us); + if(us == WHITE) { + behindFriendlyPawns |= (behindFriendlyPawns >> 8); + behindFriendlyPawns |= (behindFriendlyPawns >> 16); + } + else { + behindFriendlyPawns |= (behindFriendlyPawns << 8); + behindFriendlyPawns |= (behindFriendlyPawns << 16); + } + + int space = + count_1s_max_15(safeSquares) + + count_1s_max_15(behindFriendlyPawns & safeSquares); + + ei.mgValue += Sign[us] * + apply_weight(Value(space * ei.mi->space_weight()), WeightSpace); + } + + + // apply_weight() applies an evaluation weight to a value inline Value apply_weight(Value v, int w) { return (v*w) / 0x100; } - // scale_by_game_phase interpolates between a middle game and an endgame + // 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. @@ -1119,13 +1172,7 @@ namespace { 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)); - - Value result = Value(int((mv * sph + ev * (128 - sph)) / 128)); - + Value result = Value(int((mv * ph + ev * (128 - ph)) / 128)); return Value(int(result) & ~(GrainSize - 1)); } @@ -1161,7 +1208,6 @@ namespace { void init_safety() { 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");