]> git.sesse.net Git - stockfish/blob - src/pawns.cpp
Unroll color loops in get_pawn_info
[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(13), Value(20), Value(23), Value(23),
44     Value(23), Value(23), Value(20), Value(13)
45   };
46
47   // Doubled pawn penalty by file, endgame
48   const Value DoubledPawnEndgamePenalty[8] = {
49     Value(43), Value(48), Value(48), Value(48),
50     Value(48), Value(48), Value(48), Value(43)
51   };
52
53   // Isolated pawn penalty by file, middle game
54   const Value IsolatedPawnMidgamePenalty[8] = {
55     Value(25), Value(36), Value(40), Value(40),
56     Value(40), Value(40), Value(36), Value(25)
57   };
58
59   // Isolated pawn penalty by file, endgame
60   const Value IsolatedPawnEndgamePenalty[8] = {
61     Value(30), Value(35), Value(35), Value(35),
62     Value(35), Value(35), Value(35), Value(30)
63   };
64
65   // Backward pawn penalty by file, middle game
66   const Value BackwardPawnMidgamePenalty[8] = {
67     Value(20), Value(29), Value(33), Value(33),
68     Value(33), Value(33), Value(29), Value(20)
69   };
70
71   // Backward pawn penalty by file, endgame
72   const Value BackwardPawnEndgamePenalty[8] = {
73     Value(28), Value(31), Value(31), Value(31),
74     Value(31), Value(31), Value(31), Value(28)
75   };
76
77   // Pawn chain membership bonus by file, middle game
78   const Value ChainMidgameBonus[8] = {
79     Value(11), Value(13), Value(13), Value(14),
80     Value(14), Value(13), Value(13), Value(11)
81   };
82
83   // Pawn chain membership bonus by file, endgame
84   const Value ChainEndgameBonus[8] = {
85     Value(-1), Value(-1), Value(-1), Value(-1),
86     Value(-1), Value(-1), Value(-1), Value(-1)
87   };
88
89   // Candidate passed pawn bonus by rank, middle game
90   const Value CandidateMidgameBonus[8] = {
91     Value( 0), Value( 6), Value(6), Value(14),
92     Value(34), Value(83), Value(0), Value( 0)
93   };
94
95   // Candidate passed pawn bonus by rank, endgame
96   const Value CandidateEndgameBonus[8] = {
97     Value( 0), Value( 13), Value(13), Value(29),
98     Value(68), Value(166), 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,-14,-6, 0, 0, 0,
105    -6,-10,-10,-10,-6, 0, 0, 0,
106     4, 12, 16, 12, 4, 0, 0, 0,
107    16, 23, 23, 16, 0, 0, 0, 0,
108    23, 31, 31, 23, 0, 0, 0, 0,
109    23, 31, 31, 23, 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,-10,-19,-28,-33,-33,
116     0, 0, 0,-10,-15,-19,-24,-24,
117     0, 0, 0,  0,  1,  1,  1,  1,
118     0, 0, 0,  0,  1, 10, 19, 19,
119     0, 0, 0,  0,  1, 19, 31, 27,
120     0, 0, 0,  0,  0, 22, 31, 22,
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] = { 31, 31, 18, 0, 0, 0, 0, 0 };
126   const int16_t QStormOpenFileBonus[8] = { 0, 0, 0, 0, 0, 26, 42, 26 };
127
128   // Pawn storm lever bonuses by file
129   const int StormLeverBonus[8] = { -8, -8, -13, 0, 0, -13, -8, -8 };
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)
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 }
151
152
153 /// Destructor
154
155 PawnInfoTable::~PawnInfoTable() {
156   delete [] entries;
157 }
158
159
160 /// PawnInfo::clear() resets to zero the PawnInfo entry. Note that
161 /// kingSquares[] is initialized to SQ_NONE instead.
162
163 void PawnInfo::clear() {
164
165   memset(this, 0, sizeof(PawnInfo));
166   kingSquares[WHITE] = kingSquares[BLACK] = SQ_NONE;
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
177   assert(pos.is_ok());
178
179   Key key = pos.get_pawn_key();
180   int index = int(key & (size - 1));
181   PawnInfo* pi = entries + index;
182
183   // If pi->key matches the position's pawn hash key, it means that we
184   // have analysed this pawn structure before, and we can simply return
185   // the information we found the last time instead of recomputing it.
186   if (pi->key == key)
187       return pi;
188
189   // Clear the PawnInfo object, and set the key
190   pi->clear();
191   pi->key = key;
192
193   // Calculate pawn attacks
194   Bitboard whitePawns = pos.pieces(PAWN, WHITE);
195   Bitboard blackPawns = pos.pieces(PAWN, BLACK);
196   pi->pawnAttacks[WHITE] = ((whitePawns << 9) & ~FileABB) | ((whitePawns << 7) & ~FileHBB);
197   pi->pawnAttacks[BLACK] = ((blackPawns >> 7) & ~FileABB) | ((blackPawns >> 9) & ~FileHBB);
198
199   // Evaluate pawns for both colors
200   Values whiteValues = evaluate_pawns<WHITE>(pos, whitePawns, blackPawns, pi);
201   Values blackValues = evaluate_pawns<BLACK>(pos, blackPawns, whitePawns, pi);
202
203   pi->mgValue = int16_t(whiteValues.first - blackValues.first);
204   pi->egValue = int16_t(whiteValues.second - blackValues.second);
205   return pi;
206 }
207
208
209 /// PawnInfoTable::evaluate_pawns() evaluates each pawn of the given color
210
211 template<Color Us>
212 PawnInfoTable::Values PawnInfoTable::evaluate_pawns(const Position& pos, Bitboard ourPawns,
213                                                     Bitboard theirPawns, PawnInfo* pi) {
214   Square s;
215   File f;
216   Rank r;
217   bool passed, isolated, doubled, chain, backward, candidate;
218   int bonus;
219   Value mgValue = Value(0);
220   Value egValue = Value(0);
221   Bitboard pawns = ourPawns;
222
223   // Initialize pawn storm scores by giving bonuses for open files
224   for (File f = FILE_A; f <= FILE_H; f++)
225       if (!(ourPawns & file_bb(f)))
226       {
227           pi->ksStormValue[Us] += KStormOpenFileBonus[f];
228           pi->qsStormValue[Us] += QStormOpenFileBonus[f];
229           pi->halfOpenFiles[Us] |= (1 << f);
230       }
231
232   // Loop through all pawns of the current color and score each pawn
233   while (pawns)
234   {
235       s = pop_1st_bit(&pawns);
236       f = square_file(s);
237       r = square_rank(s);
238
239       assert(pos.piece_on(s) == piece_of_color_and_type(Us, PAWN));
240
241       // Passed, isolated or doubled pawn?
242       passed   = Position::pawn_is_passed(theirPawns, Us, s);
243       isolated = Position::pawn_is_isolated(ourPawns, s);
244       doubled  = Position::pawn_is_doubled(ourPawns, Us, s);
245
246       // We calculate kingside and queenside pawn storm
247       // scores for both colors. These are used when evaluating
248       // middle game positions with opposite side castling.
249       //
250       // Each pawn is given a base score given by a piece square table
251       // (KStormTable[] or QStormTable[]). Pawns which seem to have good
252       // chances of creating an open file by exchanging itself against an
253       // enemy pawn on an adjacent file gets an additional bonus.
254
255       // Kingside pawn storms
256       bonus = KStormTable[relative_square(Us, s)];
257       if (f >= FILE_F)
258       {
259           Bitboard b = outpost_mask(Us, s) & theirPawns & (FileFBB | FileGBB | FileHBB);
260           while (b)
261           {
262               Square s2 = pop_1st_bit(&b);
263               if (!(theirPawns & neighboring_files_bb(s2) & rank_bb(s2)))
264               {
265                   // The enemy pawn has no pawn beside itself, which makes it
266                   // particularly vulnerable. Big bonus, especially against a
267                   // weakness on the rook file.
268                   if (square_file(s2) == FILE_H)
269                       bonus += 4*StormLeverBonus[f] - 8*square_distance(s, s2);
270                   else
271                       bonus += 2*StormLeverBonus[f] - 4*square_distance(s, s2);
272               } else
273                   // There is at least one enemy pawn beside the enemy pawn we look
274                   // at, which means that the pawn has somewhat better chances of
275                   // defending itself by advancing. Smaller bonus.
276                   bonus += StormLeverBonus[f] - 2*square_distance(s, s2);
277           }
278       }
279       pi->ksStormValue[Us] += bonus;
280
281       // Queenside pawn storms
282       bonus = QStormTable[relative_square(Us, s)];
283       if (f <= FILE_C)
284       {
285           Bitboard b = outpost_mask(Us, s) & theirPawns & (FileABB | FileBBB | FileCBB);
286           while (b)
287           {
288               Square s2 = pop_1st_bit(&b);
289               if (!(theirPawns & neighboring_files_bb(s2) & rank_bb(s2)))
290               {
291                   // The enemy pawn has no pawn beside itself, which makes it
292                   // particularly vulnerable. Big bonus, especially against a
293                   // weakness on the rook file.
294                   if (square_file(s2) == FILE_A)
295                       bonus += 4*StormLeverBonus[f] - 16*square_distance(s, s2);
296                   else
297                       bonus += 2*StormLeverBonus[f] - 8*square_distance(s, s2);
298               } else
299                   // There is at least one enemy pawn beside the enemy pawn we look
300                   // at, which means that the pawn has somewhat better chances of
301                   // defending itself by advancing. Smaller bonus.
302                   bonus += StormLeverBonus[f] - 4*square_distance(s, s2);
303           }
304       }
305       pi->qsStormValue[Us] += bonus;
306
307       // Member of a pawn chain (but not the backward one)? We could speed up
308       // the test a little by introducing an array of masks indexed by color
309       // and square for doing the test, but because everything is hashed,
310       // it probably won't make any noticable difference.
311       chain =  ourPawns
312              & neighboring_files_bb(f)
313              & (rank_bb(r) | rank_bb(r - (Us == WHITE ? 1 : -1)));
314
315       // Test for backward pawn
316       //
317       // If the pawn is passed, isolated, or member of a pawn chain
318       // it cannot be backward. If can capture an enemy pawn or if
319       // there are friendly pawns behind on neighboring files it cannot
320       // be backward either.
321       if (   (passed | isolated | chain)
322           || (ourPawns & behind_bb(Us, r) & neighboring_files_bb(f))
323           || (pos.attacks_from<PAWN>(s, Us) & theirPawns))
324           backward = false;
325       else
326       {
327           // We now know that there are no friendly pawns beside or behind this
328           // pawn on neighboring files. We now check whether the pawn is
329           // backward by looking in the forward direction on the neighboring
330           // files, and seeing whether we meet a friendly or an enemy pawn first.
331           Bitboard b = pos.attacks_from<PAWN>(s, Us);
332
333           // Note that we are sure to find something because pawn is not passed
334           // nor isolated, so loop is potentially infinite, but it isn't.
335           while (!(b & (ourPawns | theirPawns)))
336               Us == WHITE ? b <<= 8 : b >>= 8;
337
338           // The friendly pawn needs to be at least two ranks closer than the enemy
339           // pawn in order to help the potentially backward pawn advance.
340           backward = (b | (Us == WHITE ? b << 8 : b >> 8)) & theirPawns;
341       }
342
343       // Test for candidate passed pawn
344       candidate =   !passed
345                  && !(theirPawns & file_bb(f))
346                  && (  count_1s_max_15(neighboring_files_bb(f) & (behind_bb(Us, r) | rank_bb(r)) & ourPawns)
347                      - count_1s_max_15(neighboring_files_bb(f) & in_front_bb(Us, r)              & theirPawns)
348                      >= 0);
349
350       // In order to prevent doubled passed pawns from receiving a too big
351       // bonus, only the frontmost passed pawn on each file is considered as
352       // a true passed pawn.
353       if (passed && (ourPawns & squares_in_front_of(Us, s)))
354           passed = false;
355
356       // Score this pawn
357       if (passed)
358           set_bit(&(pi->passedPawns), s);
359
360       if (isolated)
361       {
362           mgValue -= IsolatedPawnMidgamePenalty[f];
363           egValue -= IsolatedPawnEndgamePenalty[f];
364           if (!(theirPawns & file_bb(f)))
365           {
366               mgValue -= IsolatedPawnMidgamePenalty[f] / 2;
367               egValue -= IsolatedPawnEndgamePenalty[f] / 2;
368           }
369       }
370       if (doubled)
371       {
372           mgValue -= DoubledPawnMidgamePenalty[f];
373           egValue -= DoubledPawnEndgamePenalty[f];
374       }
375       if (backward)
376       {
377           mgValue -= BackwardPawnMidgamePenalty[f];
378           egValue -= BackwardPawnEndgamePenalty[f];
379           if (!(theirPawns & file_bb(f)))
380           {
381               mgValue -= BackwardPawnMidgamePenalty[f] / 2;
382               egValue -= BackwardPawnEndgamePenalty[f] / 2;
383           }
384       }
385       if (chain)
386       {
387           mgValue += ChainMidgameBonus[f];
388           egValue += ChainEndgameBonus[f];
389       }
390       if (candidate)
391       {
392           mgValue += CandidateMidgameBonus[relative_rank(Us, s)];
393           egValue += CandidateEndgameBonus[relative_rank(Us, s)];
394       }
395   } // while (pawns)
396
397   return Values(mgValue, egValue);
398 }
399
400
401 /// PawnInfo::updateShelter calculates and caches king shelter. It is called
402 /// only when king square changes, about 20% of total get_king_shelter() calls.
403 int PawnInfo::updateShelter(const Position& pos, Color c, Square ksq) {
404
405   unsigned shelter = 0;
406   Bitboard pawns = pos.pieces(PAWN, c) & this_and_neighboring_files_bb(ksq);
407   unsigned r = ksq & (7 << 3);
408   for (int i = 1, k = (c ? -8 : 8); i < 4; i++)
409   {
410       r += k;
411       shelter += BitCount8Bit[(pawns >> r) & 0xFF] * (128 >> i);
412   }
413   kingSquares[c] = ksq;
414   kingShelters[c] = shelter;
415   return shelter;
416 }