]> git.sesse.net Git - stockfish/blob - src/pawns.cpp
Simplify king shelter cache handling
[stockfish] / src / pawns.cpp
1 /*
2   Stockfish, a UCI chess playing engine derived from Glaurung 2.1
3   Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
4   Copyright (C) 2008-2009 Marco Costalba
5
6   Stockfish is free software: you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation, either version 3 of the License, or
9   (at your option) any later version.
10
11   Stockfish is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   GNU General Public License for more details.
15
16   You should have received a copy of the GNU General Public License
17   along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20
21 ////
22 //// Includes
23 ////
24
25 #include <cassert>
26
27 #include "bitcount.h"
28 #include "pawns.h"
29 #include "position.h"
30
31
32 ////
33 //// Local definitions
34 ////
35
36 namespace {
37
38   /// Constants and variables
39
40   // Doubled pawn penalty by file, middle game.
41   const Value DoubledPawnMidgamePenalty[8] = {
42     Value(13), Value(20), Value(23), Value(23),
43     Value(23), Value(23), Value(20), Value(13)
44   };
45
46   // Doubled pawn penalty by file, endgame.
47   const Value DoubledPawnEndgamePenalty[8] = {
48     Value(43), Value(48), Value(48), Value(48),
49     Value(48), Value(48), Value(48), Value(43)
50   };
51
52   // Isolated pawn penalty by file, middle game.
53   const Value IsolatedPawnMidgamePenalty[8] = {
54     Value(25), Value(36), Value(40), Value(40),
55     Value(40), Value(40), Value(36), Value(25)
56   };
57
58   // Isolated pawn penalty by file, endgame.
59   const Value IsolatedPawnEndgamePenalty[8] = {
60     Value(30), Value(35), Value(35), Value(35),
61     Value(35), Value(35), Value(35), Value(30)
62   };
63
64   // Backward pawn penalty by file, middle game.
65   const Value BackwardPawnMidgamePenalty[8] = {
66     Value(20), Value(29), Value(33), Value(33),
67     Value(33), Value(33), Value(29), Value(20)
68   };
69
70   // Backward pawn penalty by file, endgame.
71   const Value BackwardPawnEndgamePenalty[8] = {
72     Value(28), Value(31), Value(31), Value(31),
73     Value(31), Value(31), Value(31), Value(28)
74   };
75
76   // Pawn chain membership bonus by file, middle game.
77   const Value ChainMidgameBonus[8] = {
78     Value(11), Value(13), Value(13), Value(14),
79     Value(14), Value(13), Value(13), Value(11)
80   };
81
82   // Pawn chain membership bonus by file, endgame.
83   const Value ChainEndgameBonus[8] = {
84     Value(-1), Value(-1), Value(-1), Value(-1),
85     Value(-1), Value(-1), Value(-1), Value(-1)
86   };
87
88   // Candidate passed pawn bonus by rank, middle game.
89   const Value CandidateMidgameBonus[8] = {
90     Value( 0), Value( 6), Value(6), Value(14),
91     Value(34), Value(83), Value(0), Value( 0)
92   };
93
94   // Candidate passed pawn bonus by rank, endgame.
95   const Value CandidateEndgameBonus[8] = {
96     Value( 0), Value( 13), Value(13), Value(29),
97     Value(68), Value(166), Value( 0), Value( 0)
98   };
99
100   // Pawn storm tables for positions with opposite castling:
101   const int QStormTable[64] = {
102     0,  0,  0,  0, 0, 0, 0, 0,
103   -22,-22,-22,-14,-6, 0, 0, 0,
104    -6,-10,-10,-10,-6, 0, 0, 0,
105     4, 12, 16, 12, 4, 0, 0, 0,
106    16, 23, 23, 16, 0, 0, 0, 0,
107    23, 31, 31, 23, 0, 0, 0, 0,
108    23, 31, 31, 23, 0, 0, 0, 0,
109     0,  0,  0,  0, 0, 0, 0, 0
110   };
111
112   const int KStormTable[64] = {
113     0, 0, 0,  0,  0,  0,  0,  0,
114     0, 0, 0,-10,-19,-28,-33,-33,
115     0, 0, 0,-10,-15,-19,-24,-24,
116     0, 0, 0,  0,  1,  1,  1,  1,
117     0, 0, 0,  0,  1, 10, 19, 19,
118     0, 0, 0,  0,  1, 19, 31, 27,
119     0, 0, 0,  0,  0, 22, 31, 22,
120     0, 0, 0,  0,  0,  0,  0,  0
121   };
122
123   // Pawn storm open file bonuses by file
124   const int16_t KStormOpenFileBonus[8] = { 31, 31, 18, 0, 0, 0, 0, 0 };
125   const int16_t QStormOpenFileBonus[8] = { 0, 0, 0, 0, 0, 26, 42, 26 };
126
127   // Pawn storm lever bonuses by file
128   const int StormLeverBonus[8] = { -8, -8, -13, 0, 0, -13, -8, -8 };
129
130 }
131
132
133 ////
134 //// Functions
135 ////
136
137 /// Constructor
138
139 PawnInfoTable::PawnInfoTable(unsigned numOfEntries) {
140
141   size = numOfEntries;
142   entries = new PawnInfo[size];
143   if (entries == NULL)
144   {
145       std::cerr << "Failed to allocate " << (numOfEntries * sizeof(PawnInfo))
146                 << " bytes for pawn hash table." << std::endl;
147       Application::exit_with_failure();
148   }
149 }
150
151
152 /// Destructor
153
154 PawnInfoTable::~PawnInfoTable() {
155   delete [] entries;
156 }
157
158
159 /// PawnInfoTable::get_pawn_info() takes a position object as input, computes
160 /// a PawnInfo object, and returns a pointer to it.  The result is also
161 /// stored in a hash table, so we don't have to recompute everything when
162 /// the same pawn structure occurs again.
163
164 PawnInfo *PawnInfoTable::get_pawn_info(const Position &pos) {
165
166   assert(pos.is_ok());
167
168   Key key = pos.get_pawn_key();
169   int index = int(key & (size - 1));
170   PawnInfo *pi = entries + index;
171
172   // If pi->key matches the position's pawn hash key, it means that we
173   // have analysed this pawn structure before, and we can simply return the
174   // information we found the last time instead of recomputing it
175   if (pi->key == key)
176       return pi;
177
178   // Clear the PawnInfo object, and set the key
179   pi->clear();
180   pi->key = key;
181
182   Value mgValue[2] = {Value(0), Value(0)};
183   Value egValue[2] = {Value(0), Value(0)};
184
185   // Loop through the pawns for both colors
186   for (Color us = WHITE; us <= BLACK; us++)
187   {
188     Color them = opposite_color(us);
189     Bitboard ourPawns = pos.pawns(us);
190     Bitboard theirPawns = pos.pawns(them);
191     Bitboard pawns = ourPawns;
192     int bonus;
193
194     // Initialize pawn storm scores by giving bonuses for open files
195     for (File f = FILE_A; f <= FILE_H; f++)
196         if (Position::file_is_half_open(ourPawns, f))
197         {
198             pi->ksStormValue[us] += KStormOpenFileBonus[f];
199             pi->qsStormValue[us] += QStormOpenFileBonus[f];
200         }
201
202     // Loop through all pawns of the current color and score each pawn
203     while (pawns)
204     {
205         bool passed, doubled, isolated, backward, chain, candidate;
206         Square s = pop_1st_bit(&pawns);
207         File f = square_file(s);
208         Rank r = square_rank(s);
209
210         assert(pos.piece_on(s) == piece_of_color_and_type(us, PAWN));
211
212         // The file containing the pawn is not half open
213         pi->halfOpenFiles[us] &= ~(1 << f);
214
215         // Passed, isolated or doubled pawn?
216         passed = Position::pawn_is_passed(theirPawns, us, s);
217         isolated = Position::pawn_is_isolated(ourPawns, s);
218         doubled = Position::pawn_is_doubled(ourPawns, us, s);
219
220         // We calculate kingside and queenside pawn storm
221         // scores for both colors. These are used when evaluating
222         // middle game positions with opposite side castling.
223         //
224         // Each pawn is given a base score given by a piece square table
225         // (KStormTable[] or QStormTable[]). Pawns which seem to have good
226         // chances of creating an open file by exchanging itself against an
227         // enemy pawn on an adjacent file gets an additional bonus.
228
229         // Kingside pawn storms
230         bonus = KStormTable[relative_square(us, s)];
231         if (f >= FILE_F)
232         {
233             Bitboard b = outpost_mask(us, s) & theirPawns & (FileFBB | FileGBB | FileHBB);
234             while (b)
235             {
236                 Square s2 = pop_1st_bit(&b);
237                 if (!(theirPawns & neighboring_files_bb(s2) & rank_bb(s2)))
238                 {
239                     // The enemy pawn has no pawn beside itself, which makes it
240                     // particularly vulnerable. Big bonus, especially against a
241                     // weakness on the rook file.
242                     if (square_file(s2) == FILE_H)
243                         bonus += 4*StormLeverBonus[f] - 8*square_distance(s, s2);
244                     else
245                         bonus += 2*StormLeverBonus[f] - 4*square_distance(s, s2);
246                 } else
247                     // There is at least one enemy pawn beside the enemy pawn we look
248                     // at, which means that the pawn has somewhat better chances of
249                     // defending itself by advancing. Smaller bonus.
250                     bonus += StormLeverBonus[f] - 2*square_distance(s, s2);
251             }
252         }
253         pi->ksStormValue[us] += bonus;
254
255         // Queenside pawn storms
256         bonus = QStormTable[relative_square(us, s)];
257         if (f <= FILE_C)
258         {
259             Bitboard b = outpost_mask(us, s) & theirPawns & (FileABB | FileBBB | FileCBB);
260             while (b)
261             {
262                 Square s2 = pop_1st_bit(&b);
263                 if (!(theirPawns & neighboring_files_bb(s2) & rank_bb(s2)))
264                 {
265                     // The enemy pawn has no pawn beside itself, which makes it
266                     // particularly vulnerable. Big bonus, especially against a
267                     // weakness on the rook file.
268                     if (square_file(s2) == FILE_A)
269                         bonus += 4*StormLeverBonus[f] - 16*square_distance(s, s2);
270                     else
271                         bonus += 2*StormLeverBonus[f] - 8*square_distance(s, s2);
272                 } else
273                     // There is at least one enemy pawn beside the enemy pawn we look
274                     // at, which means that the pawn has somewhat better chances of
275                     // defending itself by advancing. Smaller bonus.
276                     bonus += StormLeverBonus[f] - 4*square_distance(s, s2);
277             }
278         }
279         pi->qsStormValue[us] += bonus;
280
281         // Member of a pawn chain (but not the backward one)? We could speed up
282         // the test a little by introducing an array of masks indexed by color
283         // and square for doing the test, but because everything is hashed,
284         // it probably won't make any noticable difference.
285         chain =  ourPawns
286                & neighboring_files_bb(f)
287                & (rank_bb(r) | rank_bb(r - (us == WHITE ? 1 : -1)));
288
289         // Test for backward pawn
290         //
291         // If the pawn is passed, isolated, or member of a pawn chain
292         // it cannot be backward. If can capture an enemy pawn or if
293         // there are friendly pawns behind on neighboring files it cannot
294         // be backward either.
295         if (   passed
296             || isolated
297             || chain
298             || (pos.pawn_attacks(us, s) & theirPawns)
299             || (ourPawns & behind_bb(us, r) & neighboring_files_bb(f)))
300             backward = false;
301         else
302         {
303             // We now know that there are no friendly pawns beside or behind this
304             // pawn on neighboring files. We now check whether the pawn is
305             // backward by looking in the forward direction on the neighboring
306             // files, and seeing whether we meet a friendly or an enemy pawn first.
307             Bitboard b;
308             if (us == WHITE)
309             {
310                 for (b = pos.pawn_attacks(us, s); !(b & (ourPawns | theirPawns)); b <<= 8);
311                 backward = (b | (b << 8)) & theirPawns;
312             }
313             else
314             {
315                 for (b = pos.pawn_attacks(us, s); !(b & (ourPawns | theirPawns)); b >>= 8);
316                 backward = (b | (b >> 8)) & theirPawns;
317             }
318         }
319
320         // Test for candidate passed pawn
321         candidate =    !passed
322                      && Position::file_is_half_open(theirPawns, f)
323                      && (  count_1s_max_15(neighboring_files_bb(f) & (behind_bb(us, r) | rank_bb(r)) & ourPawns)
324                          - count_1s_max_15(neighboring_files_bb(f) & in_front_bb(us, r)              & theirPawns)
325                          >= 0);
326
327         // In order to prevent doubled passed pawns from receiving a too big
328         // bonus, only the frontmost passed pawn on each file is considered as
329         // a true passed pawn.
330         if (passed && (ourPawns & squares_in_front_of(us, s)))
331         {
332             // candidate = true;
333             passed = false;
334         }
335
336         // Score this pawn
337         Value mv = Value(0), ev = Value(0);
338         if (isolated)
339         {
340             mv -= IsolatedPawnMidgamePenalty[f];
341             ev -= IsolatedPawnEndgamePenalty[f];
342             if (Position::file_is_half_open(theirPawns, f))
343             {
344                 mv -= IsolatedPawnMidgamePenalty[f] / 2;
345                 ev -= IsolatedPawnEndgamePenalty[f] / 2;
346             }
347         }
348         if (doubled)
349         {
350             mv -= DoubledPawnMidgamePenalty[f];
351             ev -= DoubledPawnEndgamePenalty[f];
352         }
353         if (backward)
354         {
355             mv -= BackwardPawnMidgamePenalty[f];
356             ev -= BackwardPawnEndgamePenalty[f];
357             if (Position::file_is_half_open(theirPawns, f))
358             {
359                 mv -= BackwardPawnMidgamePenalty[f] / 2;
360                 ev -= BackwardPawnEndgamePenalty[f] / 2;
361             }
362         }
363         if (chain)
364         {
365             mv += ChainMidgameBonus[f];
366             ev += ChainEndgameBonus[f];
367         }
368         if (candidate)
369         {
370             mv += CandidateMidgameBonus[relative_rank(us, s)];
371             ev += CandidateEndgameBonus[relative_rank(us, s)];
372         }
373
374         mgValue[us] += mv;
375         egValue[us] += ev;
376
377         // If the pawn is passed, set the square of the pawn in the passedPawns
378         // bitboard
379         if (passed)
380             set_bit(&(pi->passedPawns), s);
381     } // while(pawns)
382   } // for(colors)
383
384   pi->mgValue = int16_t(mgValue[WHITE] - mgValue[BLACK]);
385   pi->egValue = int16_t(egValue[WHITE] - egValue[BLACK]);
386   return pi;
387 }
388
389
390 /// PawnInfo::updateShelter calculates and caches king shelter. It is called
391 /// only when king square changes, about 20% of total get_king_shelter() calls.
392 int PawnInfo::updateShelter(const Position& pos, Color c, Square ksq) {
393
394   int shelter = 0;
395   Bitboard pawns = pos.pawns(c) & this_and_neighboring_files_bb(ksq);
396   unsigned r = ksq & (7 << 3);
397   for (int i = 1, k = (c ? -8 : 8); i < 4; i++)
398   {
399       r += k;
400       shelter += BitCount8Bit[(pawns >> r) & 0xFF] * (128 >> i);
401   }
402   kingSquares[c] = ksq;
403   kingShelters[c] = shelter;
404   return shelter;
405 }