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