]> git.sesse.net Git - stockfish/blob - src/pawns.cpp
Disable per-square MVV/LVA for now
[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   size = numOfEntries;
145   entries = new PawnInfo[size];
146   if(entries == NULL) {
147     std::cerr << "Failed to allocate " << (numOfEntries * sizeof(PawnInfo))
148               << " bytes for pawn hash table." << std::endl;
149     exit(EXIT_FAILURE);
150   }
151   this->clear();
152 }
153
154
155 /// Destructor
156
157 PawnInfoTable::~PawnInfoTable() {
158   delete [] entries;
159 }
160
161
162 /// PawnInfoTable::clear() clears the pawn hash table by setting all
163 /// entries to 0.
164
165 void PawnInfoTable::clear() {
166   memset(entries, 0, size * sizeof(PawnInfo));
167 }
168
169
170 /// PawnInfoTable::get_pawn_info() takes a position object as input, computes
171 /// a PawnInfo object, and returns a pointer to it.  The result is also 
172 /// stored in a hash table, so we don't have to recompute everything when
173 /// the same pawn structure occurs again.
174
175 PawnInfo *PawnInfoTable::get_pawn_info(const Position &pos) {
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     Color them = opposite_color(us);
198     Bitboard ourPawns = pos.pawns(us);
199     Bitboard theirPawns = pos.pawns(them);
200     Bitboard pawns = ourPawns;
201
202     // Initialize pawn storm scores by giving bonuses for open files:
203     if(EvaluatePawnStorms)
204       for(File f = FILE_A; f <= FILE_H; f++)
205         if(pos.file_is_half_open(us, f)) {
206           pi->ksStormValue[us] += KStormOpenFileBonus[f];
207           pi->qsStormValue[us] += QStormOpenFileBonus[f];
208         }
209
210     // Loop through all pawns of the current color and score each pawn:
211     while(pawns) {
212       Square s = pop_1st_bit(&pawns);
213       File f = square_file(s);
214       Rank r = square_rank(s);
215       bool passed, doubled, isolated, backward, chain, candidate;
216       int bonus;
217
218       assert(pos.piece_on(s) == pawn_of_color(us));
219
220       // The file containing the pawn is not half open:
221       pi->halfOpenFiles[us] &= ~(1 << f);
222
223       // Passed, isolated or doubled pawn?
224       passed = pos.pawn_is_passed(us, s);
225       isolated = pos.pawn_is_isolated(us, s);
226       doubled = pos.pawn_is_doubled(us, s);
227
228       if(EvaluatePawnStorms) {
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[]).  This score is increased if
235         // there are enemy pawns on adjacent files in front of the pawn.
236         // This is because we want to be able to open files against the
237         // enemy king, and to avoid blocking the pawn structure (e.g. white
238         // pawns on h6, g5, black pawns on h7, g6, f7).
239         
240         // Kingside pawn storms:
241         bonus = KStormTable[relative_square(us, s)];
242         if(bonus > 0 && outpost_mask(us, s) & theirPawns) {
243           switch(f) {
244
245           case FILE_F:
246             bonus += bonus / 4;
247             break;
248
249           case FILE_G:
250             bonus += bonus / 2 + bonus / 4;
251             break;
252
253           case FILE_H:
254             bonus += bonus / 2;
255             break;
256
257           default:
258             break;
259           }
260         }
261         pi->ksStormValue[us] += bonus;
262
263         // Queenside pawn storms:
264         bonus = QStormTable[relative_square(us, s)];
265         if(bonus > 0 && passed_pawn_mask(us, s) & theirPawns) {
266           switch(f) {
267
268           case FILE_A:
269             bonus += bonus / 2;
270             break;
271
272           case FILE_B:
273             bonus += bonus / 2 + bonus / 4;
274             break;
275
276           case FILE_C:
277             bonus += bonus / 2;
278             break;
279
280           default:
281             break;
282           }
283         }
284         pi->qsStormValue[us] += bonus;
285       }
286       
287       // Member of a pawn chain?  We could speed up the test a little by 
288       // introducing an array of masks indexed by color and square for doing
289       // the test, but because everything is hashed, it probably won't make
290       // any noticable difference.
291       chain = (us == WHITE)?
292         (ourPawns & neighboring_files_bb(f) & (rank_bb(r) | rank_bb(r-1))) :
293         (ourPawns & neighboring_files_bb(f) & (rank_bb(r) | rank_bb(r+1)));
294
295
296       // Test for backward pawn.
297
298       // If the pawn is isolated, passed, or member of a pawn chain, it cannot
299       // be backward:
300       if(passed || isolated || chain)
301         backward = false;
302       // If the pawn can capture an enemy pawn, it's not backward:
303       else if(pos.pawn_attacks(us, s) & theirPawns)
304         backward = false;
305       // Check for friendly pawns behind on neighboring files:
306       else if(ourPawns & in_front_bb(them, r) & neighboring_files_bb(f))
307         backward = false;
308       else {
309         // We now know that there is no friendly pawns beside or behind this
310         // pawn on neighboring files.  We now check whether the pawn is
311         // backward by looking in the forward direction on the neighboring
312         // files, and seeing whether we meet a friendly or an enemy pawn first.
313         Bitboard b;
314         if(us == WHITE) {
315           for(b=pos.pawn_attacks(us, s); !(b&(ourPawns|theirPawns)); b<<=8);
316           backward = (b | (b << 8)) & theirPawns;
317         }
318         else {
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 =
326         (!passed && pos.file_is_half_open(them, f) &&
327          count_1s_max_15(neighboring_files_bb(f)
328                          & (in_front_bb(them, r) | rank_bb(r))
329                          & ourPawns)
330          - count_1s_max_15(neighboring_files_bb(f) & in_front_bb(us, r)
331                            & theirPawns)
332          >= 0);
333
334       // In order to prevent doubled passed pawns from receiving a too big
335       // bonus, only the frontmost passed pawn on each file is considered as
336       // a true passed pawn.
337       if(passed && (ourPawns & squares_in_front_of(us, s))) {
338         // candidate = true;
339         passed = false;
340       }
341
342       // Score this pawn:
343       Value mv = Value(0), ev = Value(0);
344       if(isolated) {
345         mv -= IsolatedPawnMidgamePenalty[f];
346         ev -= IsolatedPawnEndgamePenalty[f];
347         if(pos.file_is_half_open(them, f)) {
348           mv -= IsolatedPawnMidgamePenalty[f] / 2;
349           ev -= IsolatedPawnEndgamePenalty[f] / 2;
350         }
351       }
352       if(doubled)  {
353         mv -= DoubledPawnMidgamePenalty[f];
354         ev -= DoubledPawnEndgamePenalty[f];
355       }
356       if(backward)  {
357         mv -= BackwardPawnMidgamePenalty[f];
358         ev -= BackwardPawnEndgamePenalty[f];
359         if(pos.file_is_half_open(them, f)) {
360           mv -= BackwardPawnMidgamePenalty[f] / 2;
361           ev -= BackwardPawnEndgamePenalty[f] / 2;
362         }
363       }
364       if(chain) {
365         mv += ChainMidgameBonus[f];
366         ev += ChainEndgameBonus[f];
367       }
368       if(candidate) {
369         mv += CandidateMidgameBonus[relative_rank(us, s)];
370         ev += CandidateEndgameBonus[relative_rank(us, s)];
371       }
372
373       mgValue[us] += mv;
374       egValue[us] += ev;
375         
376       // If the pawn is passed, set the square of the pawn in the passedPawns
377       // bitboard:
378       if(passed)
379         set_bit(&(pi->passedPawns), s);
380     }
381   }
382
383   pi->mgValue = int16_t(mgValue[WHITE] - mgValue[BLACK]);
384   pi->egValue = int16_t(egValue[WHITE] - egValue[BLACK]);
385
386   return pi;
387 }