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