2 Glaurung, a UCI chess playing engine.
3 Copyright (C) 2004-2008 Tord Romstad
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.
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.
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/>.
30 //// Local definitions
35 /// Constants and variables
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
97 // Evaluate pawn storms?
98 const bool EvaluatePawnStorms = true;
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
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
123 // Pawn storm open file bonuses by file:
124 const int KStormOpenFileBonus[8] = {
125 45, 45, 30, 0, 0, 0, 0, 0
128 const int QStormOpenFileBonus[8] = {
129 0, 0, 0, 0, 0, 30, 45, 30
141 PawnInfoTable::PawnInfoTable(unsigned 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;
155 PawnInfoTable::~PawnInfoTable() {
160 /// PawnInfoTable::clear() clears the pawn hash table by setting all
163 void PawnInfoTable::clear() {
164 memset(entries, 0, size * sizeof(PawnInfo));
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.
173 PawnInfo *PawnInfoTable::get_pawn_info(const Position &pos) {
176 Key key = pos.get_pawn_key();
177 int index = int(key & (size - 1));
178 PawnInfo *pi = entries + index;
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:
186 // Clear the PawnInfo object, and set the key:
190 Value mgValue[2] = {Value(0), Value(0)};
191 Value egValue[2] = {Value(0), Value(0)};
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;
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];
208 // Loop through all pawns of the current color and score each pawn:
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;
216 assert(pos.piece_on(s) == pawn_of_color(us));
218 // The file containing the pawn is not half open:
219 pi->halfOpenFiles[us] &= ~(1 << f);
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);
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.
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).
238 // Kingside pawn storms:
239 bonus = KStormTable[relative_square(us, s)];
240 if(bonus > 0 && outpost_mask(us, s) & theirPawns) {
248 bonus += bonus / 2 + bonus / 4;
259 pi->ksStormValue[us] += bonus;
261 // Queenside pawn storms:
262 bonus = QStormTable[relative_square(us, s)];
263 if(bonus > 0 && passed_pawn_mask(us, s) & theirPawns) {
271 bonus += bonus / 2 + bonus / 4;
282 pi->qsStormValue[us] += bonus;
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)));
294 // Test for backward pawn.
296 // If the pawn is isolated, passed, or member of a pawn chain, it cannot
298 if(passed || isolated || chain)
300 // If the pawn can capture an enemy pawn, it's not backward:
301 else if(pos.pawn_attacks(us, s) & theirPawns)
303 // Check for friendly pawns behind on neighboring files:
304 else if(ourPawns & in_front_bb(them, r) & neighboring_files_bb(f))
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.
313 for(b=pos.pawn_attacks(us, s); !(b&(ourPawns|theirPawns)); b<<=8);
314 backward = (b | (b << 8)) & theirPawns;
317 for(b=pos.pawn_attacks(us, s); !(b&(ourPawns|theirPawns)); b>>=8);
318 backward = (b | (b >> 8)) & theirPawns;
322 // Test for candidate passed pawn.
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))
328 - count_1s_max_15(neighboring_files_bb(f) & in_front_bb(us, r)
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))) {
341 Value mv = Value(0), ev = Value(0);
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;
351 mv -= DoubledPawnMidgamePenalty[f];
352 ev -= DoubledPawnEndgamePenalty[f];
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;
363 mv += ChainMidgameBonus[f];
364 ev += ChainEndgameBonus[f];
367 mv += CandidateMidgameBonus[relative_rank(us, s)];
368 ev += CandidateEndgameBonus[relative_rank(us, s)];
374 // If the pawn is passed, set the square of the pawn in the passedPawns
377 set_bit(&(pi->passedPawns), s);
381 pi->mgValue = int16_t(mgValue[WHITE] - mgValue[BLACK]);
382 pi->egValue = int16_t(egValue[WHITE] - egValue[BLACK]);