X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fpawns.cpp;h=b9d112f08c5e95772f0bf70437801df48a4daa5e;hp=a09fe68337d8aa7ab3bbbd5f93dc86023e901fc1;hb=a9e55d43262d11a916bdfa68cd1de0174d884cd3;hpb=ab29d8df678adb97e2bc40b04f13e4f17577ada0 diff --git a/src/pawns.cpp b/src/pawns.cpp index a09fe683..b9d112f0 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -7,12 +7,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. - + 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. - + You should have received a copy of the GNU General Public License along with this program. If not, see . */ @@ -26,6 +26,7 @@ #include #include "pawns.h" +#include "position.h" //// @@ -72,13 +73,13 @@ namespace { Value(32), Value(32), Value(32), Value(28) }; - // Pawn chain membership bonus by file, middle game. + // Pawn chain membership bonus by file, middle game. const Value ChainMidgameBonus[8] = { Value(14), Value(16), Value(17), Value(18), Value(18), Value(17), Value(16), Value(14) }; - // Pawn chain membership bonus by file, endgame. + // Pawn chain membership bonus by file, endgame. const Value ChainEndgameBonus[8] = { Value(16), Value(16), Value(16), Value(16), Value(16), Value(16), Value(16), Value(16) @@ -96,9 +97,6 @@ namespace { Value(80), Value(180), Value(0), Value( 0) }; - // Evaluate pawn storms? - const bool EvaluatePawnStorms = true; - // Pawn storm tables for positions with opposite castling: const int QStormTable[64] = { 0, 0, 0, 0, 0, 0, 0, 0, @@ -110,7 +108,7 @@ namespace { 31, 40, 40, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - + const int KStormTable[64] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-4,-13,-22,-27,-27, @@ -122,14 +120,12 @@ namespace { 0, 0, 0, 0, 0, 0, 0, 0 }; - // Pawn storm open file bonuses by file: - const int KStormOpenFileBonus[8] = { - 45, 45, 30, 0, 0, 0, 0, 0 - }; + // Pawn storm open file bonuses by file + const int KStormOpenFileBonus[8] = { 45, 45, 30, 0, 0, 0, 0, 0 }; + const int QStormOpenFileBonus[8] = { 0, 0, 0, 0, 0, 30, 45, 30 }; - const int QStormOpenFileBonus[8] = { - 0, 0, 0, 0, 0, 30, 45, 30 - }; + // Pawn storm lever bonuses by file + const int StormLeverBonus[8] = { 20, 20, 10, 0, 0, 10, 20, 20 }; } @@ -170,7 +166,7 @@ void PawnInfoTable::clear() { /// PawnInfoTable::get_pawn_info() takes a position object as input, computes -/// a PawnInfo object, and returns a pointer to it. The result is also +/// a PawnInfo object, and returns a pointer to it. The result is also /// stored in a hash table, so we don't have to recompute everything when /// the same pawn structure occurs again. @@ -182,7 +178,7 @@ PawnInfo *PawnInfoTable::get_pawn_info(const Position &pos) { int index = int(key & (size - 1)); PawnInfo *pi = entries + index; - // If pi->key matches the position's pawn hash key, it means that we + // If pi->key matches the position's pawn hash key, it means that we // have analysed this pawn structure before, and we can simply return the // information we found the last time instead of recomputing it if (pi->key == key) @@ -202,15 +198,15 @@ PawnInfo *PawnInfoTable::get_pawn_info(const Position &pos) { Bitboard ourPawns = pos.pawns(us); Bitboard theirPawns = pos.pawns(them); Bitboard pawns = ourPawns; + int bonus; // Initialize pawn storm scores by giving bonuses for open files - if (EvaluatePawnStorms) - for(File f = FILE_A; f <= FILE_H; f++) - if(pos.file_is_half_open(us, f)) - { - pi->ksStormValue[us] += KStormOpenFileBonus[f]; - pi->qsStormValue[us] += QStormOpenFileBonus[f]; - } + for (File f = FILE_A; f <= FILE_H; f++) + if (pos.file_is_half_open(us, f)) + { + pi->ksStormValue[us] += KStormOpenFileBonus[f]; + pi->qsStormValue[us] += QStormOpenFileBonus[f]; + } // Loop through all pawns of the current color and score each pawn while (pawns) @@ -220,7 +216,7 @@ PawnInfo *PawnInfoTable::get_pawn_info(const Position &pos) { File f = square_file(s); Rank r = square_rank(s); - assert(pos.piece_on(s) == pawn_of_color(us)); + assert(pos.piece_on(s) == piece_of_color_and_type(us, PAWN)); // The file containing the pawn is not half open pi->halfOpenFiles[us] &= ~(1 << f); @@ -230,57 +226,66 @@ PawnInfo *PawnInfoTable::get_pawn_info(const Position &pos) { isolated = pos.pawn_is_isolated(us, s); doubled = pos.pawn_is_doubled(us, s); - if (EvaluatePawnStorms) + // We calculate kingside and queenside pawn storm + // scores for both colors. These are used when evaluating + // middle game positions with opposite side castling. + // + // Each pawn is given a base score given by a piece square table + // (KStormTable[] or QStormTable[]). Pawns which seem to have good + // chances of creating an open file by exchanging itself against an + // enemy pawn on an adjacent file gets an additional bonus. + + // Kingside pawn storms + bonus = KStormTable[relative_square(us, s)]; + if (f >= FILE_F) { - // We calculate kingside and queenside pawn storm scores - // for both colors. These are used when evaluating middle - // game positions with opposite side castling. - // - // Each pawn is given a base score given by a piece square table - // (KStormTable[] or QStormTable[]). This score is increased if - // there are enemy pawns on adjacent files in front of the pawn. - // This is because we want to be able to open files against the - // enemy king, and to avoid blocking the pawn structure (e.g. white - // pawns on h6, g5, black pawns on h7, g6, f7). - - // Kingside and queenside pawn storms - int KBonus = KStormTable[relative_square(us, s)]; - int QBonus = QStormTable[relative_square(us, s)]; - bool outPost = (KBonus > 0 && (outpost_mask(us, s) & theirPawns)); - bool passed = (QBonus > 0 && (passed_pawn_mask(us, s) & theirPawns)); - - switch (f) { - - case FILE_A: - QBonus += passed * QBonus / 2; - break; - - case FILE_B: - QBonus += passed * (QBonus / 2 + QBonus / 4); - break; - - case FILE_C: - QBonus += passed * QBonus / 2; - break; - - case FILE_F: - KBonus += outPost * KBonus / 4; - break; - - case FILE_G: - KBonus += outPost * (KBonus / 2 + KBonus / 4); - break; - - case FILE_H: - KBonus += outPost * KBonus / 2; - break; - - default: - break; + Bitboard b = outpost_mask(us, s) & theirPawns & (FileFBB | FileGBB | FileHBB); + while (b) + { + Square s2 = pop_1st_bit(&b); + if (!(theirPawns & neighboring_files_bb(s2) & rank_bb(s2))) + { + // The enemy pawn has no pawn beside itself, which makes it + // particularly vulnerable. Big bonus, especially against a + // weakness on the rook file. + if (square_file(s2) == FILE_H) + bonus += 4*StormLeverBonus[f] - 8*square_distance(s, s2); + else + bonus += 2*StormLeverBonus[f] - 4*square_distance(s, s2); + } else + // There is at least one enemy pawn beside the enemy pawn we look + // at, which means that the pawn has somewhat better chances of + // defending itself by advancing. Smaller bonus. + bonus += StormLeverBonus[f] - 2*square_distance(s, s2); } - pi->ksStormValue[us] += KBonus; - pi->qsStormValue[us] += QBonus; } + pi->ksStormValue[us] += bonus; + + // Queenside pawn storms + bonus = QStormTable[relative_square(us, s)]; + if (f <= FILE_C) + { + Bitboard b = outpost_mask(us, s) & theirPawns & (FileABB | FileBBB | FileCBB); + while (b) + { + Square s2 = pop_1st_bit(&b); + if (!(theirPawns & neighboring_files_bb(s2) & rank_bb(s2))) + { + // The enemy pawn has no pawn beside itself, which makes it + // particularly vulnerable. Big bonus, especially against a + // weakness on the rook file. + if (square_file(s2) == FILE_A) + bonus += 4*StormLeverBonus[f] - 16*square_distance(s, s2); + else + bonus += 2*StormLeverBonus[f] - 8*square_distance(s, s2); + } else + // There is at least one enemy pawn beside the enemy pawn we look + // at, which means that the pawn has somewhat better chances of + // defending itself by advancing. Smaller bonus. + bonus += StormLeverBonus[f] - 4*square_distance(s, s2); + } + } + pi->qsStormValue[us] += bonus; // Member of a pawn chain (but not the backward one)? We could speed up // the test a little by introducing an array of masks indexed by color @@ -377,7 +382,7 @@ PawnInfo *PawnInfoTable::get_pawn_info(const Position &pos) { mgValue[us] += mv; egValue[us] += ev; - + // If the pawn is passed, set the square of the pawn in the passedPawns // bitboard if (passed)