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