]> git.sesse.net Git - stockfish/blob - src/pawns.cpp
Use compiler name lookup to simplify code
[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(20), Value(30), Value(34), Value(34),
44     Value(34), Value(34), Value(30), Value(20)
45   };
46
47   // Doubled pawn penalty by file, endgame.
48   const Value DoubledPawnEndgamePenalty[8] = {
49     Value(35), Value(40), Value(40), Value(40),
50     Value(40), Value(40), Value(40), Value(35)
51   };
52
53   // Isolated pawn penalty by file, middle game.
54   const Value IsolatedPawnMidgamePenalty[8] = {
55     Value(20), Value(30), Value(34), Value(34),
56     Value(34), Value(34), Value(30), Value(20)
57   };
58
59   // Isolated pawn penalty by file, endgame.
60   const Value IsolatedPawnEndgamePenalty[8] = {
61     Value(35), Value(40), Value(40), Value(40),
62     Value(40), Value(40), Value(40), Value(35)
63   };
64
65   // Backward pawn penalty by file, middle game.
66   const Value BackwardPawnMidgamePenalty[8] = {
67     Value(16), Value(24), Value(27), Value(27),
68     Value(27), Value(27), Value(24), Value(16)
69   };
70
71   // Backward pawn penalty by file, endgame.
72   const Value BackwardPawnEndgamePenalty[8] = {
73     Value(28), Value(32), Value(32), Value(32),
74     Value(32), Value(32), Value(32), Value(28)
75   };
76
77   // Pawn chain membership bonus by file, middle game.
78   const Value ChainMidgameBonus[8] = {
79     Value(14), Value(16), Value(17), Value(18),
80     Value(18), Value(17), Value(16), Value(14)
81   };
82
83   // Pawn chain membership bonus by file, endgame.
84   const Value ChainEndgameBonus[8] = {
85     Value(16), Value(16), Value(16), Value(16),
86     Value(16), Value(16), Value(16), Value(16)
87   };
88
89   // Candidate passed pawn bonus by rank, middle game.
90   const Value CandidateMidgameBonus[8] = {
91     Value( 0), Value(12), Value(12), Value(20),
92     Value(40), Value(90), Value( 0), Value( 0)
93   };
94
95   // Candidate passed pawn bonus by rank, endgame.
96   const Value CandidateEndgameBonus[8] = {
97     Value( 0), Value(24), Value(24), Value(40),
98     Value(80), Value(180), 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,-13,-4, 0, 0, 0,
105    -4, -9, -9, -9,-4, 0, 0, 0,
106     9, 18, 22, 18, 9, 0, 0, 0,
107    22, 31, 31, 22, 0, 0, 0, 0,
108    31, 40, 40, 31, 0, 0, 0, 0,
109    31, 40, 40, 31, 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,-4,-13,-22,-27,-27,
116     0, 0, 0,-4, -9,-13,-18,-18,
117     0, 0, 0, 0,  9,  9,  9,  9,
118     0, 0, 0, 0,  9, 18, 27, 27,
119     0, 0, 0, 0,  9, 27, 40, 36,
120     0, 0, 0, 0,  0, 31, 40, 31,
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] = { 45, 45, 30, 0, 0, 0, 0, 0 };
126   const int16_t QStormOpenFileBonus[8] = { 0, 0, 0, 0, 0, 30, 45, 30 };
127
128   // Pawn storm lever bonuses by file
129   const int StormLeverBonus[8] = { 20, 20, 10, 0, 0, 10, 20, 20 };
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       Application::exit_with_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     int bonus;
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
231         // scores for both colors. These are used when evaluating
232         // middle 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[]). Pawns which seem to have good
236         // chances of creating an open file by exchanging itself against an
237         // enemy pawn on an adjacent file gets an additional bonus.
238
239         // Kingside pawn storms
240         bonus = KStormTable[relative_square(us, s)];
241         if (f >= FILE_F)
242         {
243             Bitboard b = outpost_mask(us, s) & theirPawns & (FileFBB | FileGBB | FileHBB);
244             while (b)
245             {
246                 Square s2 = pop_1st_bit(&b);
247                 if (!(theirPawns & neighboring_files_bb(s2) & rank_bb(s2)))
248                 {
249                     // The enemy pawn has no pawn beside itself, which makes it
250                     // particularly vulnerable. Big bonus, especially against a
251                     // weakness on the rook file.
252                     if (square_file(s2) == FILE_H)
253                         bonus += 4*StormLeverBonus[f] - 8*square_distance(s, s2);
254                     else
255                         bonus += 2*StormLeverBonus[f] - 4*square_distance(s, s2);
256                 } else
257                     // There is at least one enemy pawn beside the enemy pawn we look
258                     // at, which means that the pawn has somewhat better chances of
259                     // defending itself by advancing. Smaller bonus.
260                     bonus += StormLeverBonus[f] - 2*square_distance(s, s2);
261             }
262         }
263         pi->ksStormValue[us] += bonus;
264
265         // Queenside pawn storms
266         bonus = QStormTable[relative_square(us, s)];
267         if (f <= FILE_C)
268         {
269             Bitboard b = outpost_mask(us, s) & theirPawns & (FileABB | FileBBB | FileCBB);
270             while (b)
271             {
272                 Square s2 = pop_1st_bit(&b);
273                 if (!(theirPawns & neighboring_files_bb(s2) & rank_bb(s2)))
274                 {
275                     // The enemy pawn has no pawn beside itself, which makes it
276                     // particularly vulnerable. Big bonus, especially against a
277                     // weakness on the rook file.
278                     if (square_file(s2) == FILE_A)
279                         bonus += 4*StormLeverBonus[f] - 16*square_distance(s, s2);
280                     else
281                         bonus += 2*StormLeverBonus[f] - 8*square_distance(s, s2);
282                 } else
283                     // There is at least one enemy pawn beside the enemy pawn we look
284                     // at, which means that the pawn has somewhat better chances of
285                     // defending itself by advancing. Smaller bonus.
286                     bonus += StormLeverBonus[f] - 4*square_distance(s, s2);
287             }
288         }
289         pi->qsStormValue[us] += bonus;
290
291         // Member of a pawn chain (but not the backward one)? We could speed up
292         // the test a little by introducing an array of masks indexed by color
293         // and square for doing the test, but because everything is hashed,
294         // it probably won't make any noticable difference.
295         chain =  ourPawns
296                & neighboring_files_bb(f)
297                & (rank_bb(r) | rank_bb(r - (us == WHITE ? 1 : -1)));
298
299         // Test for backward pawn
300         //
301         // If the pawn is passed, isolated, or member of a pawn chain
302         // it cannot be backward. If can capture an enemy pawn or if
303         // there are friendly pawns behind on neighboring files it cannot
304         // be backward either.
305         if (   passed
306             || isolated
307             || chain
308             || (pos.pawn_attacks(us, s) & theirPawns)
309             || (ourPawns & behind_bb(us, r) & neighboring_files_bb(f)))
310             backward = false;
311         else
312         {
313             // We now know that there are no friendly pawns beside or behind this
314             // pawn on neighboring files. We now check whether the pawn is
315             // backward by looking in the forward direction on the neighboring
316             // files, and seeing whether we meet a friendly or an enemy pawn first.
317             Bitboard b;
318             if (us == WHITE)
319             {
320                 for (b = pos.pawn_attacks(us, s); !(b & (ourPawns | theirPawns)); b <<= 8);
321                 backward = (b | (b << 8)) & theirPawns;
322             }
323             else
324             {
325                 for (b = pos.pawn_attacks(us, s); !(b & (ourPawns | theirPawns)); b >>= 8);
326                 backward = (b | (b >> 8)) & theirPawns;
327             }
328         }
329
330         // Test for candidate passed pawn
331         candidate =    !passed
332                      && pos.file_is_half_open(them, f)
333                      && (  count_1s_max_15(neighboring_files_bb(f) & (behind_bb(us, r) | rank_bb(r)) & ourPawns)
334                          - count_1s_max_15(neighboring_files_bb(f) & in_front_bb(us, r)              & theirPawns)
335                          >= 0);
336
337         // In order to prevent doubled passed pawns from receiving a too big
338         // bonus, only the frontmost passed pawn on each file is considered as
339         // a true passed pawn.
340         if (passed && (ourPawns & squares_in_front_of(us, s)))
341         {
342             // candidate = true;
343             passed = false;
344         }
345
346         // Score this pawn
347         Value mv = Value(0), ev = Value(0);
348         if (isolated)
349         {
350             mv -= IsolatedPawnMidgamePenalty[f];
351             ev -= IsolatedPawnEndgamePenalty[f];
352             if (pos.file_is_half_open(them, f))
353             {
354                 mv -= IsolatedPawnMidgamePenalty[f] / 2;
355                 ev -= IsolatedPawnEndgamePenalty[f] / 2;
356             }
357         }
358         if (doubled)
359         {
360             mv -= DoubledPawnMidgamePenalty[f];
361             ev -= DoubledPawnEndgamePenalty[f];
362         }
363         if (backward)
364         {
365             mv -= BackwardPawnMidgamePenalty[f];
366             ev -= BackwardPawnEndgamePenalty[f];
367             if (pos.file_is_half_open(them, f))
368             {
369                 mv -= BackwardPawnMidgamePenalty[f] / 2;
370                 ev -= BackwardPawnEndgamePenalty[f] / 2;
371             }
372         }
373         if (chain)
374         {
375             mv += ChainMidgameBonus[f];
376             ev += ChainEndgameBonus[f];
377         }
378         if (candidate)
379         {
380             mv += CandidateMidgameBonus[relative_rank(us, s)];
381             ev += CandidateEndgameBonus[relative_rank(us, s)];
382         }
383
384         mgValue[us] += mv;
385         egValue[us] += ev;
386
387         // If the pawn is passed, set the square of the pawn in the passedPawns
388         // bitboard
389         if (passed)
390             set_bit(&(pi->passedPawns), s);
391     } // while(pawns)
392   } // for(colors)
393
394   pi->mgValue = int16_t(mgValue[WHITE] - mgValue[BLACK]);
395   pi->egValue = int16_t(egValue[WHITE] - egValue[BLACK]);
396   return pi;
397 }