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