]> git.sesse.net Git - stockfish/blob - src/pawns.cpp
Space inflate generate_castle_moves()
[stockfish] / src / pawns.cpp
1 /*
2   Glaurung, a UCI chess playing engine.
3   Copyright (C) 2004-2008 Tord Romstad
4
5   Glaurung is free software: you can redistribute it and/or modify
6   it under the terms of the GNU General Public License as published by
7   the Free Software Foundation, either version 3 of the License, or
8   (at your option) any later version.
9   
10   Glaurung is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   GNU General Public License for more details.
14   
15   You should have received a copy of the GNU General Public License
16   along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18
19
20 ////
21 //// Includes
22 ////
23
24 #include <cassert>
25
26 #include "pawns.h"
27
28
29 ////
30 //// Local definitions
31 ////
32
33 namespace {
34
35   /// Constants and variables
36
37   // Doubled pawn penalty by file, middle game.
38   const Value DoubledPawnMidgamePenalty[8] = {
39     Value(20), Value(30), Value(34), Value(34),
40     Value(34), Value(34), Value(30), Value(20)
41   };
42
43   // Doubled pawn penalty by file, endgame.
44   const Value DoubledPawnEndgamePenalty[8] = {
45     Value(35), Value(40), Value(40), Value(40),
46     Value(40), Value(40), Value(40), Value(35)
47   };
48
49   // Isolated pawn penalty by file, middle game.
50   const Value IsolatedPawnMidgamePenalty[8] = {
51     Value(20), Value(30), Value(34), Value(34),
52     Value(34), Value(34), Value(30), Value(20)
53   };
54
55   // Isolated pawn penalty by file, endgame.
56   const Value IsolatedPawnEndgamePenalty[8] = {
57     Value(35), Value(40), Value(40), Value(40),
58     Value(40), Value(40), Value(40), Value(35)
59   };
60
61   // Backward pawn penalty by file, middle game.
62   const Value BackwardPawnMidgamePenalty[8] = {
63     Value(16), Value(24), Value(27), Value(27),
64     Value(27), Value(27), Value(24), Value(16)
65   };
66
67   // Backward pawn penalty by file, endgame.
68   const Value BackwardPawnEndgamePenalty[8] = {
69     Value(28), Value(32), Value(32), Value(32),
70     Value(32), Value(32), Value(32), Value(28)
71   };
72
73   // Pawn chain membership bonus by file, middle game. 
74   const Value ChainMidgameBonus[8] = {
75     Value(14), Value(16), Value(17), Value(18),
76     Value(18), Value(17), Value(16), Value(14)
77   };
78
79   // Pawn chain membership bonus by file, endgame. 
80   const Value ChainEndgameBonus[8] = {
81     Value(16), Value(16), Value(16), Value(16),
82     Value(16), Value(16), Value(16), Value(16)
83   };
84
85   // Candidate passed pawn bonus by rank, middle game.
86   const Value CandidateMidgameBonus[8] = {
87     Value(0), Value(12), Value(12), Value(20),
88     Value(40), Value(90), Value(0), Value(0)
89   };
90
91   // Candidate passed pawn bonus by rank, endgame.
92   const Value CandidateEndgameBonus[8] = {
93     Value(0), Value(24), Value(24), Value(40),
94     Value(80), Value(180), Value(0), Value(0)
95   };
96
97   // Evaluate pawn storms?
98   const bool EvaluatePawnStorms = true;
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   size = numOfEntries;
143   entries = new PawnInfo[size];
144   if(entries == NULL) {
145     std::cerr << "Failed to allocate " << (numOfEntries * sizeof(PawnInfo))
146               << " bytes for pawn hash table." << std::endl;
147     exit(EXIT_FAILURE);
148   }
149   this->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   assert(pos.is_ok());
175
176   Key key = pos.get_pawn_key();
177   int index = int(key & (size - 1));
178   PawnInfo *pi = entries + index;
179
180   // If pi->key matches the position's pawn hash key, it means that we 
181   // have analysed this pawn structure before, and we can simply return the
182   // information we found the last time instead of recomputing it:
183   if(pi->key == key)
184     return pi;
185
186   // Clear the PawnInfo object, and set the key:
187   pi->clear();
188   pi->key = key;
189
190   Value mgValue[2] = {Value(0), Value(0)};
191   Value egValue[2] = {Value(0), Value(0)};
192
193   // Loop through the pawns for both colors:
194   for(Color us = WHITE; us <= BLACK; us++) {
195     Color them = opposite_color(us);
196     Bitboard ourPawns = pos.pawns(us);
197     Bitboard theirPawns = pos.pawns(them);
198     Bitboard pawns = ourPawns;
199
200     // Initialize pawn storm scores by giving bonuses for open files:
201     if(EvaluatePawnStorms)
202       for(File f = FILE_A; f <= FILE_H; f++)
203         if(pos.file_is_half_open(us, f)) {
204           pi->ksStormValue[us] += KStormOpenFileBonus[f];
205           pi->qsStormValue[us] += QStormOpenFileBonus[f];
206         }
207
208     // Loop through all pawns of the current color and score each pawn:
209     while(pawns) {
210       Square s = pop_1st_bit(&pawns);
211       File f = square_file(s);
212       Rank r = square_rank(s);
213       bool passed, doubled, isolated, backward, chain, candidate;
214       int bonus;
215
216       assert(pos.piece_on(s) == pawn_of_color(us));
217
218       // The file containing the pawn is not half open:
219       pi->halfOpenFiles[us] &= ~(1 << f);
220
221       // Passed, isolated or doubled pawn?
222       passed = pos.pawn_is_passed(us, s);
223       isolated = pos.pawn_is_isolated(us, s);
224       doubled = pos.pawn_is_doubled(us, s);
225
226       if(EvaluatePawnStorms) {
227         // We calculate kingside and queenside pawn storm
228         // scores for both colors.  These are used when evaluating
229         // middle game positions with opposite side castling.
230         //
231         // Each pawn is given a base score given by a piece square table
232         // (KStormTable[] or QStormTable[]).  This score is increased if
233         // there are enemy pawns on adjacent files in front of the pawn.
234         // This is because we want to be able to open files against the
235         // enemy king, and to avoid blocking the pawn structure (e.g. white
236         // pawns on h6, g5, black pawns on h7, g6, f7).
237         
238         // Kingside pawn storms:
239         bonus = KStormTable[relative_square(us, s)];
240         if(bonus > 0 && outpost_mask(us, s) & theirPawns) {
241           switch(f) {
242
243           case FILE_F:
244             bonus += bonus / 4;
245             break;
246
247           case FILE_G:
248             bonus += bonus / 2 + bonus / 4;
249             break;
250
251           case FILE_H:
252             bonus += bonus / 2;
253             break;
254
255           default:
256             break;
257           }
258         }
259         pi->ksStormValue[us] += bonus;
260
261         // Queenside pawn storms:
262         bonus = QStormTable[relative_square(us, s)];
263         if(bonus > 0 && passed_pawn_mask(us, s) & theirPawns) {
264           switch(f) {
265
266           case FILE_A:
267             bonus += bonus / 2;
268             break;
269
270           case FILE_B:
271             bonus += bonus / 2 + bonus / 4;
272             break;
273
274           case FILE_C:
275             bonus += bonus / 2;
276             break;
277
278           default:
279             break;
280           }
281         }
282         pi->qsStormValue[us] += bonus;
283       }
284       
285       // Member of a pawn chain?  We could speed up the test a little by 
286       // introducing an array of masks indexed by color and square for doing
287       // the test, but because everything is hashed, it probably won't make
288       // any noticable difference.
289       chain = (us == WHITE)?
290         (ourPawns & neighboring_files_bb(f) & (rank_bb(r) | rank_bb(r-1))) :
291         (ourPawns & neighboring_files_bb(f) & (rank_bb(r) | rank_bb(r+1)));
292
293
294       // Test for backward pawn.
295
296       // If the pawn is isolated, passed, or member of a pawn chain, it cannot
297       // be backward:
298       if(passed || isolated || chain)
299         backward = false;
300       // If the pawn can capture an enemy pawn, it's not backward:
301       else if(pos.pawn_attacks(us, s) & theirPawns)
302         backward = false;
303       // Check for friendly pawns behind on neighboring files:
304       else if(ourPawns & in_front_bb(them, r) & neighboring_files_bb(f))
305         backward = false;
306       else {
307         // We now know that there is 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           for(b=pos.pawn_attacks(us, s); !(b&(ourPawns|theirPawns)); b<<=8);
314           backward = (b | (b << 8)) & theirPawns;
315         }
316         else {
317           for(b=pos.pawn_attacks(us, s); !(b&(ourPawns|theirPawns)); b>>=8);
318           backward = (b | (b >> 8)) & theirPawns;
319         }
320       }
321
322       // Test for candidate passed pawn.
323       candidate =
324         (!passed && pos.file_is_half_open(them, f) &&
325          count_1s_max_15(neighboring_files_bb(f)
326                          & (in_front_bb(them, r) | rank_bb(r))
327                          & ourPawns)
328          - count_1s_max_15(neighboring_files_bb(f) & in_front_bb(us, r)
329                            & theirPawns)
330          >= 0);
331
332       // In order to prevent doubled passed pawns from receiving a too big
333       // bonus, only the frontmost passed pawn on each file is considered as
334       // a true passed pawn.
335       if(passed && (ourPawns & squares_in_front_of(us, s))) {
336         // candidate = true;
337         passed = false;
338       }
339
340       // Score this pawn:
341       Value mv = Value(0), ev = Value(0);
342       if(isolated) {
343         mv -= IsolatedPawnMidgamePenalty[f];
344         ev -= IsolatedPawnEndgamePenalty[f];
345         if(pos.file_is_half_open(them, f)) {
346           mv -= IsolatedPawnMidgamePenalty[f] / 2;
347           ev -= IsolatedPawnEndgamePenalty[f] / 2;
348         }
349       }
350       if(doubled)  {
351         mv -= DoubledPawnMidgamePenalty[f];
352         ev -= DoubledPawnEndgamePenalty[f];
353       }
354       if(backward)  {
355         mv -= BackwardPawnMidgamePenalty[f];
356         ev -= BackwardPawnEndgamePenalty[f];
357         if(pos.file_is_half_open(them, f)) {
358           mv -= BackwardPawnMidgamePenalty[f] / 2;
359           ev -= BackwardPawnEndgamePenalty[f] / 2;
360         }
361       }
362       if(chain) {
363         mv += ChainMidgameBonus[f];
364         ev += ChainEndgameBonus[f];
365       }
366       if(candidate) {
367         mv += CandidateMidgameBonus[relative_rank(us, s)];
368         ev += CandidateEndgameBonus[relative_rank(us, s)];
369       }
370
371       mgValue[us] += mv;
372       egValue[us] += ev;
373         
374       // If the pawn is passed, set the square of the pawn in the passedPawns
375       // bitboard:
376       if(passed)
377         set_bit(&(pi->passedPawns), s);
378     }
379   }
380
381   pi->mgValue = int16_t(mgValue[WHITE] - mgValue[BLACK]);
382   pi->egValue = int16_t(egValue[WHITE] - egValue[BLACK]);
383
384   return pi;
385 }