]> git.sesse.net Git - stockfish/blob - src/pawns.cpp
Inline Position::move_is_capture()
[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 int16_t KStormOpenFileBonus[8] = { 45, 45, 30, 0, 0, 0, 0, 0 };
125   const int16_t QStormOpenFileBonus[8] = { 0, 0, 0, 0, 0, 30, 45, 30 };
126
127   // Pawn storm lever bonuses by file
128   const int StormLeverBonus[8] = { 20, 20, 10, 0, 0, 10, 20, 20 };
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       exit(EXIT_FAILURE);
148   }
149   clear();
150 }
151
152
153 /// Destructor
154
155 PawnInfoTable::~PawnInfoTable() {
156   delete [] entries;
157 }
158
159
160 /// PawnInfoTable::clear() clears the pawn hash table by setting all
161 /// entries to 0.
162
163 void PawnInfoTable::clear() {
164   memset(entries, 0, size * sizeof(PawnInfo));
165 }
166
167
168 /// PawnInfoTable::get_pawn_info() takes a position object as input, computes
169 /// a PawnInfo object, and returns a pointer to it.  The result is also
170 /// stored in a hash table, so we don't have to recompute everything when
171 /// the same pawn structure occurs again.
172
173 PawnInfo *PawnInfoTable::get_pawn_info(const Position &pos) {
174
175   assert(pos.is_ok());
176
177   Key key = pos.get_pawn_key();
178   int index = int(key & (size - 1));
179   PawnInfo *pi = entries + index;
180
181   // If pi->key matches the position's pawn hash key, it means that we
182   // have analysed this pawn structure before, and we can simply return the
183   // information we found the last time instead of recomputing it
184   if (pi->key == key)
185       return pi;
186
187   // Clear the PawnInfo object, and set the key
188   pi->clear();
189   pi->key = key;
190
191   Value mgValue[2] = {Value(0), Value(0)};
192   Value egValue[2] = {Value(0), Value(0)};
193
194   // Loop through the pawns for both colors
195   for (Color us = WHITE; us <= BLACK; us++)
196   {
197     Color them = opposite_color(us);
198     Bitboard ourPawns = pos.pawns(us);
199     Bitboard theirPawns = pos.pawns(them);
200     Bitboard pawns = ourPawns;
201     int bonus;
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) == piece_of_color_and_type(us, PAWN));
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
230         // scores for both colors. These are used when evaluating
231         // middle 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[]). Pawns which seem to have good
235         // chances of creating an open file by exchanging itself against an
236         // enemy pawn on an adjacent file gets an additional bonus.
237
238         // Kingside pawn storms
239         bonus = KStormTable[relative_square(us, s)];
240         if (f >= FILE_F)
241         {
242             Bitboard b = outpost_mask(us, s) & theirPawns & (FileFBB | FileGBB | FileHBB);
243             while (b)
244             {
245                 Square s2 = pop_1st_bit(&b);
246                 if (!(theirPawns & neighboring_files_bb(s2) & rank_bb(s2)))
247                 {
248                     // The enemy pawn has no pawn beside itself, which makes it
249                     // particularly vulnerable. Big bonus, especially against a
250                     // weakness on the rook file.
251                     if (square_file(s2) == FILE_H)
252                         bonus += 4*StormLeverBonus[f] - 8*square_distance(s, s2);
253                     else
254                         bonus += 2*StormLeverBonus[f] - 4*square_distance(s, s2);
255                 } else
256                     // There is at least one enemy pawn beside the enemy pawn we look
257                     // at, which means that the pawn has somewhat better chances of
258                     // defending itself by advancing. Smaller bonus.
259                     bonus += StormLeverBonus[f] - 2*square_distance(s, s2);
260             }
261         }
262         pi->ksStormValue[us] += bonus;
263
264         // Queenside pawn storms
265         bonus = QStormTable[relative_square(us, s)];
266         if (f <= FILE_C)
267         {
268             Bitboard b = outpost_mask(us, s) & theirPawns & (FileABB | FileBBB | FileCBB);
269             while (b)
270             {
271                 Square s2 = pop_1st_bit(&b);
272                 if (!(theirPawns & neighboring_files_bb(s2) & rank_bb(s2)))
273                 {
274                     // The enemy pawn has no pawn beside itself, which makes it
275                     // particularly vulnerable. Big bonus, especially against a
276                     // weakness on the rook file.
277                     if (square_file(s2) == FILE_A)
278                         bonus += 4*StormLeverBonus[f] - 16*square_distance(s, s2);
279                     else
280                         bonus += 2*StormLeverBonus[f] - 8*square_distance(s, s2);
281                 } else
282                     // There is at least one enemy pawn beside the enemy pawn we look
283                     // at, which means that the pawn has somewhat better chances of
284                     // defending itself by advancing. Smaller bonus.
285                     bonus += StormLeverBonus[f] - 4*square_distance(s, s2);
286             }
287         }
288         pi->qsStormValue[us] += bonus;
289
290         // Member of a pawn chain (but not the backward one)? We could speed up
291         // the test a little by introducing an array of masks indexed by color
292         // and square for doing the test, but because everything is hashed,
293         // it probably won't make any noticable difference.
294         chain =  ourPawns
295                & neighboring_files_bb(f)
296                & (rank_bb(r) | rank_bb(r - (us == WHITE ? 1 : -1)));
297
298         // Test for backward pawn
299         //
300         // If the pawn is passed, isolated, or member of a pawn chain
301         // it cannot be backward. If can capture an enemy pawn or if
302         // there are friendly pawns behind on neighboring files it cannot
303         // be backward either.
304         if (   passed
305             || isolated
306             || chain
307             || (pos.pawn_attacks(us, s) & theirPawns)
308             || (ourPawns & behind_bb(us, r) & neighboring_files_bb(f)))
309             backward = false;
310         else
311         {
312             // We now know that there are no friendly pawns beside or behind this
313             // pawn on neighboring files. We now check whether the pawn is
314             // backward by looking in the forward direction on the neighboring
315             // files, and seeing whether we meet a friendly or an enemy pawn first.
316             Bitboard b;
317             if (us == WHITE)
318             {
319                 for (b = pos.pawn_attacks(us, s); !(b & (ourPawns | theirPawns)); b <<= 8);
320                 backward = (b | (b << 8)) & theirPawns;
321             }
322             else
323             {
324                 for (b = pos.pawn_attacks(us, s); !(b & (ourPawns | theirPawns)); b >>= 8);
325                 backward = (b | (b >> 8)) & theirPawns;
326             }
327         }
328
329         // Test for candidate passed pawn
330         candidate =    !passed
331                      && pos.file_is_half_open(them, f)
332                      && (  count_1s_max_15(neighboring_files_bb(f) & (behind_bb(us, r) | rank_bb(r)) & ourPawns)
333                          - count_1s_max_15(neighboring_files_bb(f) & in_front_bb(us, r)              & theirPawns)
334                          >= 0);
335
336         // In order to prevent doubled passed pawns from receiving a too big
337         // bonus, only the frontmost passed pawn on each file is considered as
338         // a true passed pawn.
339         if (passed && (ourPawns & squares_in_front_of(us, s)))
340         {
341             // candidate = true;
342             passed = false;
343         }
344
345         // Score this pawn
346         Value mv = Value(0), ev = Value(0);
347         if (isolated)
348         {
349             mv -= IsolatedPawnMidgamePenalty[f];
350             ev -= IsolatedPawnEndgamePenalty[f];
351             if (pos.file_is_half_open(them, f))
352             {
353                 mv -= IsolatedPawnMidgamePenalty[f] / 2;
354                 ev -= IsolatedPawnEndgamePenalty[f] / 2;
355             }
356         }
357         if (doubled)
358         {
359             mv -= DoubledPawnMidgamePenalty[f];
360             ev -= DoubledPawnEndgamePenalty[f];
361         }
362         if (backward)
363         {
364             mv -= BackwardPawnMidgamePenalty[f];
365             ev -= BackwardPawnEndgamePenalty[f];
366             if (pos.file_is_half_open(them, f))
367             {
368                 mv -= BackwardPawnMidgamePenalty[f] / 2;
369                 ev -= BackwardPawnEndgamePenalty[f] / 2;
370             }
371         }
372         if (chain)
373         {
374             mv += ChainMidgameBonus[f];
375             ev += ChainEndgameBonus[f];
376         }
377         if (candidate)
378         {
379             mv += CandidateMidgameBonus[relative_rank(us, s)];
380             ev += CandidateEndgameBonus[relative_rank(us, s)];
381         }
382
383         mgValue[us] += mv;
384         egValue[us] += ev;
385
386         // If the pawn is passed, set the square of the pawn in the passedPawns
387         // bitboard
388         if (passed)
389             set_bit(&(pi->passedPawns), s);
390     } // while(pawns)
391   } // for(colors)
392
393   pi->mgValue = int16_t(mgValue[WHITE] - mgValue[BLACK]);
394   pi->egValue = int16_t(egValue[WHITE] - egValue[BLACK]);
395   return pi;
396 }