]> git.sesse.net Git - stockfish/blob - src/pawns.cpp
Last touches to movegen.cpp
[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 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 "pawns.h"
29
30
31 ////
32 //// Local definitions
33 ////
34
35 namespace {
36
37   /// Constants and variables
38
39   // Doubled pawn penalty by file, middle game.
40   const Value DoubledPawnMidgamePenalty[8] = {
41     Value(20), Value(30), Value(34), Value(34),
42     Value(34), Value(34), Value(30), Value(20)
43   };
44
45   // Doubled pawn penalty by file, endgame.
46   const Value DoubledPawnEndgamePenalty[8] = {
47     Value(35), Value(40), Value(40), Value(40),
48     Value(40), Value(40), Value(40), Value(35)
49   };
50
51   // Isolated pawn penalty by file, middle game.
52   const Value IsolatedPawnMidgamePenalty[8] = {
53     Value(20), Value(30), Value(34), Value(34),
54     Value(34), Value(34), Value(30), Value(20)
55   };
56
57   // Isolated pawn penalty by file, endgame.
58   const Value IsolatedPawnEndgamePenalty[8] = {
59     Value(35), Value(40), Value(40), Value(40),
60     Value(40), Value(40), Value(40), Value(35)
61   };
62
63   // Backward pawn penalty by file, middle game.
64   const Value BackwardPawnMidgamePenalty[8] = {
65     Value(16), Value(24), Value(27), Value(27),
66     Value(27), Value(27), Value(24), Value(16)
67   };
68
69   // Backward pawn penalty by file, endgame.
70   const Value BackwardPawnEndgamePenalty[8] = {
71     Value(28), Value(32), Value(32), Value(32),
72     Value(32), Value(32), Value(32), Value(28)
73   };
74
75   // Pawn chain membership bonus by file, middle game.
76   const Value ChainMidgameBonus[8] = {
77     Value(14), Value(16), Value(17), Value(18),
78     Value(18), Value(17), Value(16), Value(14)
79   };
80
81   // Pawn chain membership bonus by file, endgame.
82   const Value ChainEndgameBonus[8] = {
83     Value(16), Value(16), Value(16), Value(16),
84     Value(16), Value(16), Value(16), Value(16)
85   };
86
87   // Candidate passed pawn bonus by rank, middle game.
88   const Value CandidateMidgameBonus[8] = {
89     Value( 0), Value(12), Value(12), Value(20),
90     Value(40), Value(90), Value( 0), Value( 0)
91   };
92
93   // Candidate passed pawn bonus by rank, endgame.
94   const Value CandidateEndgameBonus[8] = {
95     Value( 0), Value(24), Value(24), Value(40),
96     Value(80), Value(180), Value(0), Value( 0)
97   };
98
99   // Pawn storm tables for positions with opposite castling:
100   const int QStormTable[64] = {
101     0,  0,  0,  0, 0, 0, 0, 0,
102   -22,-22,-22,-13,-4, 0, 0, 0,
103    -4, -9, -9, -9,-4, 0, 0, 0,
104     9, 18, 22, 18, 9, 0, 0, 0,
105    22, 31, 31, 22, 0, 0, 0, 0,
106    31, 40, 40, 31, 0, 0, 0, 0,
107    31, 40, 40, 31, 0, 0, 0, 0,
108     0,  0,  0,  0, 0, 0, 0, 0
109   };
110
111   const int KStormTable[64] = {
112     0, 0, 0, 0,  0,  0,  0,  0,
113     0, 0, 0,-4,-13,-22,-27,-27,
114     0, 0, 0,-4, -9,-13,-18,-18,
115     0, 0, 0, 0,  9,  9,  9,  9,
116     0, 0, 0, 0,  9, 18, 27, 27,
117     0, 0, 0, 0,  9, 27, 40, 36,
118     0, 0, 0, 0,  0, 31, 40, 31,
119     0, 0, 0, 0,  0,  0,  0,  0
120   };
121
122   // Pawn storm open file bonuses by file:
123   const int KStormOpenFileBonus[8] = {
124     45, 45, 30, 0, 0, 0, 0, 0
125   };
126
127   const int QStormOpenFileBonus[8] = {
128     0, 0, 0, 0, 0, 30, 45, 30
129   };
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 == NULL)
145   {
146       std::cerr << "Failed to allocate " << (numOfEntries * sizeof(PawnInfo))
147                 << " bytes for pawn hash table." << std::endl;
148       exit(EXIT_FAILURE);
149   }
150   clear();
151 }
152
153
154 /// Destructor
155
156 PawnInfoTable::~PawnInfoTable() {
157   delete [] entries;
158 }
159
160
161 /// PawnInfoTable::clear() clears the pawn hash table by setting all
162 /// entries to 0.
163
164 void PawnInfoTable::clear() {
165   memset(entries, 0, size * sizeof(PawnInfo));
166 }
167
168
169 /// PawnInfoTable::get_pawn_info() takes a position object as input, computes
170 /// a PawnInfo object, and returns a pointer to it.  The result is also
171 /// stored in a hash table, so we don't have to recompute everything when
172 /// the same pawn structure occurs again.
173
174 PawnInfo *PawnInfoTable::get_pawn_info(const Position &pos) {
175
176   assert(pos.is_ok());
177
178   Key key = pos.get_pawn_key();
179   int index = int(key & (size - 1));
180   PawnInfo *pi = entries + index;
181
182   // If pi->key matches the position's pawn hash key, it means that we
183   // have analysed this pawn structure before, and we can simply return the
184   // information we found the last time instead of recomputing it
185   if (pi->key == key)
186       return pi;
187
188   // Clear the PawnInfo object, and set the key
189   pi->clear();
190   pi->key = key;
191
192   Value mgValue[2] = {Value(0), Value(0)};
193   Value egValue[2] = {Value(0), Value(0)};
194
195   // Loop through the pawns for both colors
196   for (Color us = WHITE; us <= BLACK; us++)
197   {
198     Color them = opposite_color(us);
199     Bitboard ourPawns = pos.pawns(us);
200     Bitboard theirPawns = pos.pawns(them);
201     Bitboard pawns = ourPawns;
202
203     // Initialize pawn storm scores by giving bonuses for open files
204     for (File f = FILE_A; f <= FILE_H; f++)
205         if (pos.file_is_half_open(us, f))
206         {
207             pi->ksStormValue[us] += KStormOpenFileBonus[f];
208             pi->qsStormValue[us] += QStormOpenFileBonus[f];
209         }
210
211     // Loop through all pawns of the current color and score each pawn
212     while (pawns)
213     {
214         bool passed, doubled, isolated, backward, chain, candidate;
215         Square s = pop_1st_bit(&pawns);
216         File f = square_file(s);
217         Rank r = square_rank(s);
218
219         assert(pos.piece_on(s) == pawn_of_color(us));
220
221         // The file containing the pawn is not half open
222         pi->halfOpenFiles[us] &= ~(1 << f);
223
224         // Passed, isolated or doubled pawn?
225         passed = pos.pawn_is_passed(us, s);
226         isolated = pos.pawn_is_isolated(us, s);
227         doubled = pos.pawn_is_doubled(us, s);
228
229         // We calculate kingside and queenside pawn storm scores
230         // for both colors. These are used when evaluating middle
231         // game positions with opposite side castling.
232         //
233         // Each pawn is given a base score given by a piece square table
234         // (KStormTable[] or QStormTable[]). This score is increased if
235         // there are enemy pawns on adjacent files in front of the pawn.
236         // This is because we want to be able to open files against the
237         // enemy king, and to avoid blocking the pawn structure (e.g. white
238         // pawns on h6, g5, black pawns on h7, g6, f7).
239
240         // Kingside and queenside pawn storms
241         int KBonus = KStormTable[relative_square(us, s)];
242         int QBonus = QStormTable[relative_square(us, s)];
243         bool outPostFlag = (KBonus > 0 && (outpost_mask(us, s) & theirPawns));
244         bool passedFlag = (QBonus > 0 && (passed_pawn_mask(us, s) & theirPawns));
245
246         switch (f) {
247
248         case FILE_A:
249             QBonus += passedFlag * QBonus / 2;
250             break;
251
252         case FILE_B:
253             QBonus += passedFlag * (QBonus / 2 + QBonus / 4);
254             break;
255
256         case FILE_C:
257             QBonus += passedFlag * QBonus / 2;
258             break;
259
260         case FILE_F:
261             KBonus += outPostFlag * KBonus / 4;
262             break;
263
264         case FILE_G:
265             KBonus += outPostFlag * (KBonus / 2 + KBonus / 4);
266             break;
267
268         case FILE_H:
269             KBonus += outPostFlag * KBonus / 2;
270             break;
271
272         default:
273             break;
274         }
275         pi->ksStormValue[us] += KBonus;
276         pi->qsStormValue[us] += QBonus;
277
278         // Member of a pawn chain (but not the backward one)? We could speed up
279         // the test a little by introducing an array of masks indexed by color
280         // and square for doing the test, but because everything is hashed,
281         // it probably won't make any noticable difference.
282         chain =  ourPawns
283                & neighboring_files_bb(f)
284                & (rank_bb(r) | rank_bb(r - (us == WHITE ? 1 : -1)));
285
286         // Test for backward pawn
287         //
288         // If the pawn is passed, isolated, or member of a pawn chain
289         // it cannot be backward. If can capture an enemy pawn or if
290         // there are friendly pawns behind on neighboring files it cannot
291         // be backward either.
292         if (   passed
293             || isolated
294             || chain
295             || (pos.pawn_attacks(us, s) & theirPawns)
296             || (ourPawns & behind_bb(us, r) & neighboring_files_bb(f)))
297             backward = false;
298         else
299         {
300             // We now know that there are no friendly pawns beside or behind this
301             // pawn on neighboring files. We now check whether the pawn is
302             // backward by looking in the forward direction on the neighboring
303             // files, and seeing whether we meet a friendly or an enemy pawn first.
304             Bitboard b;
305             if (us == WHITE)
306             {
307                 for (b = pos.pawn_attacks(us, s); !(b & (ourPawns | theirPawns)); b <<= 8);
308                 backward = (b | (b << 8)) & theirPawns;
309             }
310             else
311             {
312                 for (b = pos.pawn_attacks(us, s); !(b & (ourPawns | theirPawns)); b >>= 8);
313                 backward = (b | (b >> 8)) & theirPawns;
314             }
315         }
316
317         // Test for candidate passed pawn
318         candidate =    !passed
319                      && pos.file_is_half_open(them, f)
320                      && (  count_1s_max_15(neighboring_files_bb(f) & (behind_bb(us, r) | rank_bb(r)) & ourPawns)
321                          - count_1s_max_15(neighboring_files_bb(f) & in_front_bb(us, r)              & theirPawns)
322                          >= 0);
323
324         // In order to prevent doubled passed pawns from receiving a too big
325         // bonus, only the frontmost passed pawn on each file is considered as
326         // a true passed pawn.
327         if (passed && (ourPawns & squares_in_front_of(us, s)))
328         {
329             // candidate = true;
330             passed = false;
331         }
332
333         // Score this pawn
334         Value mv = Value(0), ev = Value(0);
335         if (isolated)
336         {
337             mv -= IsolatedPawnMidgamePenalty[f];
338             ev -= IsolatedPawnEndgamePenalty[f];
339             if (pos.file_is_half_open(them, f))
340             {
341                 mv -= IsolatedPawnMidgamePenalty[f] / 2;
342                 ev -= IsolatedPawnEndgamePenalty[f] / 2;
343             }
344         }
345         if (doubled)
346         {
347             mv -= DoubledPawnMidgamePenalty[f];
348             ev -= DoubledPawnEndgamePenalty[f];
349         }
350         if (backward)
351         {
352             mv -= BackwardPawnMidgamePenalty[f];
353             ev -= BackwardPawnEndgamePenalty[f];
354             if (pos.file_is_half_open(them, f))
355             {
356                 mv -= BackwardPawnMidgamePenalty[f] / 2;
357                 ev -= BackwardPawnEndgamePenalty[f] / 2;
358             }
359         }
360         if (chain)
361         {
362             mv += ChainMidgameBonus[f];
363             ev += ChainEndgameBonus[f];
364         }
365         if (candidate)
366         {
367             mv += CandidateMidgameBonus[relative_rank(us, s)];
368             ev += CandidateEndgameBonus[relative_rank(us, s)];
369         }
370
371         mgValue[us] += mv;
372         egValue[us] += ev;
373
374         // If the pawn is passed, set the square of the pawn in the passedPawns
375         // bitboard
376         if (passed)
377             set_bit(&(pi->passedPawns), s);
378     } // while(pawns)
379   } // for(colors)
380
381   pi->mgValue = int16_t(mgValue[WHITE] - mgValue[BLACK]);
382   pi->egValue = int16_t(egValue[WHITE] - egValue[BLACK]);
383   return pi;
384 }