Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
99 | pmbaty | 1 | /* |
2 | Texel - A UCI chess engine. |
||
3 | Copyright (C) 2012-2014 Peter Ă–sterlund, peterosterlund2@gmail.com |
||
4 | |||
5 | This program 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 | This program 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 | * evaluate.cpp |
||
21 | * |
||
22 | * Created on: Feb 25, 2012 |
||
23 | * Author: petero |
||
24 | */ |
||
25 | |||
26 | #include "evaluate.hpp" |
||
27 | #include "endGameEval.hpp" |
||
28 | #include <vector> |
||
29 | |||
30 | int Evaluate::pieceValueOrder[Piece::nPieceTypes] = { |
||
31 | 0, |
||
32 | 5, 4, 3, 2, 2, 1, |
||
33 | 5, 4, 3, 2, 2, 1 |
||
34 | }; |
||
35 | |||
36 | |||
37 | static const int empty[64] = { 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, |
||
38 | 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, |
||
39 | 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, |
||
40 | 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0}; |
||
41 | |||
42 | int Evaluate::castleMaskFactor[256]; |
||
43 | |||
44 | static StaticInitializer<Evaluate> evInit; |
||
45 | |||
46 | |||
47 | /** Get bitboard mask for a square translated (dx,dy). Return 0 if square outside board. */ |
||
48 | static inline U64 getMask(int sq, int dx, int dy) { |
||
49 | int x = Position::getX(sq) + dx; |
||
50 | int y = Position::getY(sq) + dy; |
||
51 | if (x >= 0 && x < 8 && y >= 0 && y < 8) |
||
52 | return 1ULL << Position::getSquare(x, y); |
||
53 | else |
||
54 | return 0; |
||
55 | } |
||
56 | |||
57 | void |
||
58 | Evaluate::staticInitialize() { |
||
59 | psTab1[Piece::EMPTY] = empty; |
||
60 | psTab1[Piece::WKING] = kt1w.getTable(); |
||
61 | psTab1[Piece::WQUEEN] = qt1w.getTable(); |
||
62 | psTab1[Piece::WROOK] = rt1w.getTable(); |
||
63 | psTab1[Piece::WBISHOP] = bt1w.getTable(); |
||
64 | psTab1[Piece::WKNIGHT] = nt1w.getTable(); |
||
65 | psTab1[Piece::WPAWN] = pt1w.getTable(); |
||
66 | psTab1[Piece::BKING] = kt1b.getTable(); |
||
67 | psTab1[Piece::BQUEEN] = qt1b.getTable(); |
||
68 | psTab1[Piece::BROOK] = rt1b.getTable(); |
||
69 | psTab1[Piece::BBISHOP] = bt1b.getTable(); |
||
70 | psTab1[Piece::BKNIGHT] = nt1b.getTable(); |
||
71 | psTab1[Piece::BPAWN] = pt1b.getTable(); |
||
72 | |||
73 | psTab2[Piece::EMPTY] = empty; |
||
74 | psTab2[Piece::WKING] = kt2w.getTable(); |
||
75 | psTab2[Piece::WQUEEN] = qt2w.getTable(); |
||
76 | psTab2[Piece::WROOK] = rt1w.getTable(); |
||
77 | psTab2[Piece::WBISHOP] = bt2w.getTable(); |
||
78 | psTab2[Piece::WKNIGHT] = nt2w.getTable(); |
||
79 | psTab2[Piece::WPAWN] = pt2w.getTable(); |
||
80 | psTab2[Piece::BKING] = kt2b.getTable(); |
||
81 | psTab2[Piece::BQUEEN] = qt2b.getTable(); |
||
82 | psTab2[Piece::BROOK] = rt1b.getTable(); |
||
83 | psTab2[Piece::BBISHOP] = bt2b.getTable(); |
||
84 | psTab2[Piece::BKNIGHT] = nt2b.getTable(); |
||
85 | psTab2[Piece::BPAWN] = pt2b.getTable(); |
||
86 | |||
87 | // Initialize knight/bishop king safety patterns |
||
88 | for (int sq = 0; sq < 64; sq++) { |
||
89 | const int x = Position::getX(sq); |
||
90 | const int y = Position::getY(sq); |
||
91 | int dx = (x < 4) ? -1 : 1; |
||
92 | int dy = (y < 4) ? 1 : -1; |
||
93 | U64 n = getMask(sq, -dx, 0) | getMask(sq, dx, 0) | getMask(sq, 0, dy) | getMask(sq, 0, 2*dy) | getMask(sq, dx, 2*dy); |
||
94 | U64 b = getMask(sq, -dx, 0) | getMask(sq, 0, dy) | getMask(sq, dx, 2*dy); |
||
95 | knightKingProtectPattern[sq] = n; |
||
96 | bishopKingProtectPattern[sq] = b; |
||
97 | } |
||
98 | } |
||
99 | |||
100 | void |
||
101 | Evaluate::updateEvalParams() { |
||
102 | // Castle bonus |
||
103 | for (int i = 0; i < 256; i++) { |
||
104 | int h1Dist = 100; |
||
105 | bool h1Castle = (i & (1<<7)) != 0; |
||
106 | if (h1Castle) |
||
107 | h1Dist = BitBoard::bitCount(i & BitBoard::sqMask(F1,G1)); |
||
108 | int a1Dist = 100; |
||
109 | bool a1Castle = (i & 1) != 0; |
||
110 | if (a1Castle) |
||
111 | a1Dist = BitBoard::bitCount(i & BitBoard::sqMask(B1,C1,D1)); |
||
112 | int dist = std::min(a1Dist, h1Dist); |
||
113 | castleMaskFactor[i] = dist < 4 ? castleFactor[dist] : 0; |
||
114 | } |
||
115 | |||
116 | // Knight mobility scores |
||
117 | for (int sq = 0; sq < 64; sq++) { |
||
118 | int x = Position::getX(sq); |
||
119 | int y = Position::getY(sq); |
||
120 | if (x >= 4) x = 7 - x; |
||
121 | if (y >= 4) y = 7 - y; |
||
122 | if (x < y) std::swap(x, y); |
||
123 | int maxMob = 0; |
||
124 | switch (y*8+x) { |
||
125 | case A1: maxMob = 2; break; |
||
126 | case B1: maxMob = 3; break; |
||
127 | case C1: maxMob = 4; break; |
||
128 | case D1: maxMob = 4; break; |
||
129 | case B2: maxMob = 4; break; |
||
130 | case C2: maxMob = 6; break; |
||
131 | case D2: maxMob = 6; break; |
||
132 | case C3: maxMob = 8; break; |
||
133 | case D3: maxMob = 8; break; |
||
134 | case D4: maxMob = 8; break; |
||
135 | default: |
||
136 | assert(false); |
||
137 | } |
||
138 | for (int m = 0; m <= 8; m++) { |
||
139 | int offs = 0; |
||
140 | switch (maxMob) { |
||
141 | case 2: offs = 0; break; |
||
142 | case 3: offs = 3; break; |
||
143 | case 4: offs = 7; break; |
||
144 | case 6: offs = 12; break; |
||
145 | case 8: offs = 19; break; |
||
146 | } |
||
147 | knightMobScoreA[sq][m] = knightMobScore[offs + std::min(m, maxMob)]; |
||
148 | } |
||
149 | } |
||
150 | } |
||
151 | |||
152 | const int* Evaluate::psTab1[Piece::nPieceTypes]; |
||
153 | const int* Evaluate::psTab2[Piece::nPieceTypes]; |
||
154 | |||
155 | int Evaluate::knightMobScoreA[64][9]; |
||
156 | U64 Evaluate::knightKingProtectPattern[64]; |
||
157 | U64 Evaluate::bishopKingProtectPattern[64]; |
||
158 | |||
159 | Evaluate::Evaluate(EvalHashTables& et) |
||
160 | : pawnHash(et.pawnHash), |
||
161 | materialHash(et.materialHash), |
||
162 | kingSafetyHash(et.kingSafetyHash), |
||
163 | wKingZone(0), bKingZone(0), |
||
164 | wKingAttacks(0), bKingAttacks(0), |
||
165 | wAttacksBB(0), bAttacksBB(0), |
||
166 | wPawnAttacks(0), bPawnAttacks(0) { |
||
167 | } |
||
168 | |||
169 | int |
||
170 | Evaluate::evalPos(const Position& pos) { |
||
171 | return evalPos<false>(pos); |
||
172 | } |
||
173 | |||
174 | int |
||
175 | Evaluate::evalPosPrint(const Position& pos) { |
||
176 | return evalPos<true>(pos); |
||
177 | } |
||
178 | |||
179 | template <bool print> |
||
180 | inline int |
||
181 | Evaluate::evalPos(const Position& pos) { |
||
182 | int score = materialScore(pos, print); |
||
183 | |||
184 | wKingAttacks = bKingAttacks = 0; |
||
185 | wKingZone = BitBoard::kingAttacks[pos.getKingSq(true)]; wKingZone |= wKingZone << 8; |
||
186 | bKingZone = BitBoard::kingAttacks[pos.getKingSq(false)]; bKingZone |= bKingZone >> 8; |
||
187 | wAttacksBB = bAttacksBB = 0L; |
||
188 | |||
189 | U64 pawns = pos.pieceTypeBB(Piece::WPAWN); |
||
190 | wPawnAttacks = ((pawns & BitBoard::maskBToHFiles) << 7) | |
||
191 | ((pawns & BitBoard::maskAToGFiles) << 9); |
||
192 | pawns = pos.pieceTypeBB(Piece::BPAWN); |
||
193 | bPawnAttacks = ((pawns & BitBoard::maskBToHFiles) >> 9) | |
||
194 | ((pawns & BitBoard::maskAToGFiles) >> 7); |
||
195 | |||
196 | score += pieceSquareEval(pos); |
||
197 | if (print) std::cout << "eval pst :" << score << std::endl; |
||
198 | score += pawnBonus(pos); |
||
199 | if (print) std::cout << "eval pawn :" << score << std::endl; |
||
200 | score += castleBonus(pos); |
||
201 | if (print) std::cout << "eval castle :" << score << std::endl; |
||
202 | |||
203 | score += rookBonus(pos); |
||
204 | if (print) std::cout << "eval rook :" << score << std::endl; |
||
205 | score += bishopEval(pos, score); |
||
206 | if (print) std::cout << "eval bishop :" << score << std::endl; |
||
207 | score += knightEval(pos); |
||
208 | if (print) std::cout << "eval knight :" << score << std::endl; |
||
209 | score += threatBonus(pos); |
||
210 | if (print) std::cout << "eval threat :" << score << std::endl; |
||
211 | score += protectBonus(pos); |
||
212 | if (print) std::cout << "eval protect:" << score << std::endl; |
||
213 | score += kingSafety(pos); |
||
214 | if (print) std::cout << "eval king :" << score << std::endl; |
||
215 | if (mhd->endGame) |
||
216 | score = EndGameEval::endGameEval<true>(pos, phd->passedPawns, score); |
||
217 | if (print) std::cout << "eval endgame:" << score << std::endl; |
||
218 | if (pos.pieceTypeBB(Piece::WPAWN, Piece::BPAWN)) { |
||
219 | int hmc = clamp(pos.getHalfMoveClock() / 10, 0, 9); |
||
220 | score = score * halfMoveFactor[hmc] / 128; |
||
221 | } |
||
222 | if (print) std::cout << "eval halfmove:" << score << std::endl; |
||
223 | if (score > 0) { |
||
224 | int nStale = BitBoard::bitCount(BitBoard::southFill(phd->stalePawns & pos.pieceTypeBB(Piece::WPAWN)) & 0xff); |
||
225 | score = score * stalePawnFactor[nStale] / 128; |
||
226 | } else if (score < 0) { |
||
227 | int nStale = BitBoard::bitCount(BitBoard::southFill(phd->stalePawns & pos.pieceTypeBB(Piece::BPAWN)) & 0xff); |
||
228 | score = score * stalePawnFactor[nStale] / 128; |
||
229 | } |
||
230 | if (print) std::cout << "eval staleP :" << score << std::endl; |
||
231 | |||
232 | if (!pos.isWhiteMove()) |
||
233 | score = -score; |
||
234 | return score; |
||
235 | } |
||
236 | |||
237 | /** Compensate for the fact that many knights are stronger compared to queens |
||
238 | * than what the default material scores would predict. */ |
||
239 | static inline int correctionNvsQ(int n, int q) { |
||
240 | if (n <= q+1) |
||
241 | return 0; |
||
242 | int knightBonus = 0; |
||
243 | if (q == 1) |
||
244 | knightBonus = knightVsQueenBonus1; |
||
245 | else if (q == 2) |
||
246 | knightBonus = knightVsQueenBonus2; |
||
247 | else if (q >= 3) |
||
248 | knightBonus = knightVsQueenBonus3; |
||
249 | int corr = knightBonus * (n - q - 1); |
||
250 | return corr; |
||
251 | } |
||
252 | |||
253 | void |
||
254 | Evaluate::computeMaterialScore(const Position& pos, MaterialHashData& mhd, bool print) const { |
||
255 | // Compute material part of score |
||
256 | int score = pos.wMtrl() - pos.bMtrl(); |
||
257 | if (print) std::cout << "eval mtrlraw:" << score << std::endl; |
||
258 | const int nWQ = BitBoard::bitCount(pos.pieceTypeBB(Piece::WQUEEN)); |
||
259 | const int nBQ = BitBoard::bitCount(pos.pieceTypeBB(Piece::BQUEEN)); |
||
260 | const int nWN = BitBoard::bitCount(pos.pieceTypeBB(Piece::WKNIGHT)); |
||
261 | const int nBN = BitBoard::bitCount(pos.pieceTypeBB(Piece::BKNIGHT)); |
||
262 | int wCorr = correctionNvsQ(nWN, nBQ); |
||
263 | int bCorr = correctionNvsQ(nBN, nWQ); |
||
264 | score += wCorr - bCorr; |
||
265 | if (print) std::cout << "eval qncorr :" << score << std::endl; |
||
266 | score += tradeBonus(pos, wCorr, bCorr); |
||
267 | if (print) std::cout << "eval trade :" << score << std::endl; |
||
268 | |||
269 | const int nWR = BitBoard::bitCount(pos.pieceTypeBB(Piece::WROOK)); |
||
270 | const int nBR = BitBoard::bitCount(pos.pieceTypeBB(Piece::BROOK)); |
||
271 | { // Redundancy of major pieces |
||
272 | int wMajor = nWQ + nWR; |
||
273 | int bMajor = nBQ + nBR; |
||
274 | int w = std::min(wMajor, 3); |
||
275 | int b = std::min(bMajor, 3); |
||
276 | score += majorPieceRedundancy[w*4+b]; |
||
277 | } |
||
278 | if (print) std::cout << "eval majred :" << score << std::endl; |
||
279 | |||
280 | const int wMtrl = pos.wMtrl(); |
||
281 | const int bMtrl = pos.bMtrl(); |
||
282 | const int wMtrlPawns = pos.wMtrlPawns(); |
||
283 | const int bMtrlPawns = pos.bMtrlPawns(); |
||
284 | const int wMtrlNoPawns = wMtrl - wMtrlPawns; |
||
285 | const int bMtrlNoPawns = bMtrl - bMtrlPawns; |
||
286 | |||
287 | // Handle imbalances |
||
288 | const int nWB = BitBoard::bitCount(pos.pieceTypeBB(Piece::WBISHOP)); |
||
289 | const int nBB = BitBoard::bitCount(pos.pieceTypeBB(Piece::BBISHOP)); |
||
290 | const int nWP = BitBoard::bitCount(pos.pieceTypeBB(Piece::WPAWN)); |
||
291 | const int nBP = BitBoard::bitCount(pos.pieceTypeBB(Piece::BPAWN)); |
||
292 | { |
||
293 | const int dQ = nWQ - nBQ; |
||
294 | const int dR = nWR - nBR; |
||
295 | const int dB = nWB - nBB; |
||
296 | const int dN = nWN - nBN; |
||
297 | int nMinor = nWB + nWN + nBB + nBN; |
||
298 | if ((dQ == 1) && (dR == -2)) { |
||
299 | score += QvsRRBonus[std::min(4, nMinor)]; |
||
300 | } else if ((dQ == -1) && (dR == 2)) { |
||
301 | score -= QvsRRBonus[std::min(4, nMinor)]; |
||
302 | } |
||
303 | |||
304 | const int dP = nWP - nBP; |
||
305 | if ((dR == 1) && (dB + dN == -1)) { |
||
306 | score += RvsMBonus[clamp(dP, -3, 3)+3]; |
||
307 | if (wMtrlNoPawns == rV && dB == -1 && dP == -1) |
||
308 | score += RvsBPBonus; |
||
309 | } else if ((dR == -1) && (dB + dN == 1)) { |
||
310 | score -= RvsMBonus[clamp(-dP, -3, 3)+3]; |
||
311 | if (bMtrlNoPawns == rV && dB == 1 && dP == 1) |
||
312 | score -= RvsBPBonus; |
||
313 | } |
||
314 | |||
315 | if ((dR == 1) && (dB + dN == -2)) { |
||
316 | score += RvsMMBonus[clamp(dP, -3, 3)+3]; |
||
317 | } else if ((dR == -1) && (dB + dN == 2)) { |
||
318 | score -= RvsMMBonus[clamp(-dP, -3, 3)+3]; |
||
319 | } |
||
320 | |||
321 | if ((dQ == 1) && (dR == -1) && (dB + dN == -1)) { |
||
322 | score += (nWR == 0) ? (int)QvsRMBonus1 : (int)QvsRMBonus2; // Pierre-Marie Baty -- added type cast |
||
323 | } else if ((dQ == -1) && (dR == 1) && (dB + dN == 1)) { |
||
324 | score -= (nBR == 0) ? (int)QvsRMBonus1 : (int)QvsRMBonus2; // Pierre-Marie Baty -- added type cast |
||
325 | } |
||
326 | } |
||
327 | if (print) std::cout << "eval imbala :" << score << std::endl; |
||
328 | mhd.id = pos.materialId(); |
||
329 | mhd.score = score; |
||
330 | mhd.endGame = EndGameEval::endGameEval<false>(pos, 0, 0); |
||
331 | |||
332 | // Compute interpolation factors |
||
333 | { // Pawn |
||
334 | const int loMtrl = pawnLoMtrl; |
||
335 | const int hiMtrl = pawnHiMtrl; |
||
336 | mhd.wPawnIPF = interpolate(bMtrlNoPawns, loMtrl, 0, hiMtrl, IPOLMAX); |
||
337 | mhd.bPawnIPF = interpolate(wMtrlNoPawns, loMtrl, 0, hiMtrl, IPOLMAX); |
||
338 | if (wCorr > 100) |
||
339 | mhd.wPawnIPF = mhd.wPawnIPF * 100 / wCorr; |
||
340 | if (bCorr > 100) |
||
341 | mhd.bPawnIPF = mhd.bPawnIPF * 100 / bCorr; |
||
342 | } |
||
343 | { // Knight/bishop |
||
344 | const int loMtrl = minorLoMtrl; |
||
345 | const int hiMtrl = minorHiMtrl; |
||
346 | mhd.wKnightIPF = interpolate(bMtrl, loMtrl, 0, hiMtrl, IPOLMAX); |
||
347 | mhd.bKnightIPF = interpolate(wMtrl, loMtrl, 0, hiMtrl, IPOLMAX); |
||
348 | } |
||
349 | { // Castle |
||
350 | const int loMtrl = castleLoMtrl; |
||
351 | const int hiMtrl = castleHiMtrl; |
||
352 | const int m = wMtrlNoPawns + bMtrlNoPawns; |
||
353 | mhd.castleIPF = interpolate(m, loMtrl, 0, hiMtrl, IPOLMAX); |
||
354 | } |
||
355 | { |
||
356 | const int loMtrl = queenLoMtrl; |
||
357 | const int hiMtrl = queenHiMtrl; |
||
358 | const int m = wMtrlNoPawns + bMtrlNoPawns; |
||
359 | mhd.queenIPF = interpolate(m, loMtrl, 0, hiMtrl, IPOLMAX); |
||
360 | } |
||
361 | { // Passed pawn |
||
362 | const int loMtrl = passedPawnLoMtrl; |
||
363 | const int hiMtrl = passedPawnHiMtrl; |
||
364 | mhd.wPassedPawnIPF = interpolate(bMtrlNoPawns-nBN*(nV/2), loMtrl, 0, hiMtrl, IPOLMAX); |
||
365 | mhd.bPassedPawnIPF = interpolate(wMtrlNoPawns-nWN*(nV/2), loMtrl, 0, hiMtrl, IPOLMAX); |
||
366 | } |
||
367 | { // King safety |
||
368 | const int loMtrl = kingSafetyLoMtrl; |
||
369 | const int hiMtrl = kingSafetyHiMtrl; |
||
370 | const int m = (wMtrlNoPawns + bMtrlNoPawns) / 2; |
||
371 | mhd.kingSafetyIPF = interpolate(m, loMtrl, 0, hiMtrl, IPOLMAX); |
||
372 | if (wCorr + bCorr > 200) |
||
373 | mhd.kingSafetyIPF = mhd.kingSafetyIPF * 200 / (wCorr + bCorr); |
||
374 | } |
||
375 | { // Different color bishops |
||
376 | const int loMtrl = oppoBishopLoMtrl; |
||
377 | const int hiMtrl = oppoBishopHiMtrl; |
||
378 | const int m = wMtrlNoPawns + bMtrlNoPawns; |
||
379 | mhd.diffColorBishopIPF = interpolate(m, loMtrl, 0, hiMtrl, IPOLMAX); |
||
380 | } |
||
381 | { // Knight outpost |
||
382 | const int loMtrl = knightOutpostLoMtrl; |
||
383 | const int hiMtrl = knightOutpostHiMtrl; |
||
384 | mhd.wKnightOutPostIPF = interpolate(bMtrlPawns, loMtrl, 0, hiMtrl, IPOLMAX); |
||
385 | mhd.bKnightOutPostIPF = interpolate(wMtrlPawns, loMtrl, 0, hiMtrl, IPOLMAX); |
||
386 | } |
||
387 | } |
||
388 | |||
389 | int |
||
390 | Evaluate::tradeBonus(const Position& pos, int wCorr, int bCorr) const { |
||
391 | const int wM = pos.wMtrl() + wCorr; |
||
392 | const int bM = pos.bMtrl() + bCorr; |
||
393 | const int wPawn = pos.wMtrlPawns(); |
||
394 | const int bPawn = pos.bMtrlPawns(); |
||
395 | const int deltaScore = wM - bM; |
||
396 | |||
397 | int pBonus = 0; |
||
398 | pBonus += interpolate((deltaScore > 0) ? wPawn : bPawn, 0, -pawnTradePenalty * deltaScore / 100, pawnTradeThreshold, 0); |
||
399 | pBonus += interpolate((deltaScore > 0) ? bM : wM, 0, pieceTradeBonus * deltaScore / 100, pieceTradeThreshold * 100, 0); |
||
400 | |||
401 | return pBonus; |
||
402 | } |
||
403 | |||
404 | int |
||
405 | Evaluate::pieceSquareEval(const Position& pos) { |
||
406 | int score = 0; |
||
407 | |||
408 | // Kings/pawns |
||
409 | if (pos.wMtrlPawns() + pos.bMtrlPawns() > 0) { |
||
410 | { |
||
411 | const int k1 = pos.psScore1(Piece::WKING) + pos.psScore1(Piece::WPAWN); |
||
412 | const int k2 = pos.psScore2(Piece::WKING) + pos.psScore2(Piece::WPAWN); |
||
413 | score += interpolate(k2, k1, mhd->wPawnIPF); |
||
414 | } |
||
415 | { |
||
416 | const int k1 = pos.psScore1(Piece::BKING) + pos.psScore1(Piece::BPAWN); |
||
417 | const int k2 = pos.psScore2(Piece::BKING) + pos.psScore2(Piece::BPAWN); |
||
418 | score -= interpolate(k2, k1, mhd->bPawnIPF); |
||
419 | } |
||
420 | } else { // Use symmetric tables if no pawns left |
||
421 | if (pos.wMtrl() > pos.bMtrl()) |
||
422 | score += EndGameEval::mateEval(pos.getKingSq(true), pos.getKingSq(false)); |
||
423 | else if (pos.wMtrl() < pos.bMtrl()) |
||
424 | score -= EndGameEval::mateEval(pos.getKingSq(false), pos.getKingSq(true)); |
||
425 | else |
||
426 | score += EndGameEval::winKingTable[pos.getKingSq(true)] - |
||
427 | EndGameEval::winKingTable[pos.getKingSq(false)]; |
||
428 | } |
||
429 | |||
430 | // Knights/bishops |
||
431 | { |
||
432 | int n1 = pos.psScore1(Piece::WKNIGHT) + pos.psScore1(Piece::WBISHOP); |
||
433 | int n2 = pos.psScore2(Piece::WKNIGHT) + pos.psScore2(Piece::WBISHOP); |
||
434 | score += interpolate(n2, n1, mhd->wKnightIPF); |
||
435 | n1 = pos.psScore1(Piece::BKNIGHT) + pos.psScore1(Piece::BBISHOP); |
||
436 | n2 = pos.psScore2(Piece::BKNIGHT) + pos.psScore2(Piece::BBISHOP); |
||
437 | score -= interpolate(n2, n1, mhd->bKnightIPF); |
||
438 | } |
||
439 | |||
440 | // Queens |
||
441 | { |
||
442 | const U64 occupied = pos.occupiedBB(); |
||
443 | int q1 = pos.psScore1(Piece::WQUEEN); |
||
444 | int q2 = pos.psScore2(Piece::WQUEEN); |
||
445 | score += interpolate(q2, q1, mhd->queenIPF); |
||
446 | U64 m = pos.pieceTypeBB(Piece::WQUEEN); |
||
447 | while (m != 0) { |
||
448 | int sq = BitBoard::extractSquare(m); |
||
449 | U64 atk = BitBoard::rookAttacks(sq, occupied) | BitBoard::bishopAttacks(sq, occupied); |
||
450 | wAttacksBB |= atk; |
||
451 | score += queenMobScore[BitBoard::bitCount(atk & ~(pos.whiteBB() | bPawnAttacks))]; |
||
452 | bKingAttacks += BitBoard::bitCount(atk & bKingZone) * 2; |
||
453 | } |
||
454 | q1 = pos.psScore1(Piece::BQUEEN); |
||
455 | q2 = pos.psScore2(Piece::BQUEEN); |
||
456 | score -= interpolate(q2, q1, mhd->queenIPF); |
||
457 | m = pos.pieceTypeBB(Piece::BQUEEN); |
||
458 | while (m != 0) { |
||
459 | int sq = BitBoard::extractSquare(m); |
||
460 | U64 atk = BitBoard::rookAttacks(sq, occupied) | BitBoard::bishopAttacks(sq, occupied); |
||
461 | bAttacksBB |= atk; |
||
462 | score -= queenMobScore[BitBoard::bitCount(atk & ~(pos.blackBB() | wPawnAttacks))]; |
||
463 | wKingAttacks += BitBoard::bitCount(atk & wKingZone) * 2; |
||
464 | } |
||
465 | } |
||
466 | |||
467 | // Rooks |
||
468 | { |
||
469 | int r1 = pos.psScore1(Piece::WROOK); |
||
470 | if (r1 != 0) { |
||
471 | const int nP = BitBoard::bitCount(pos.pieceTypeBB(Piece::BPAWN)); |
||
472 | const int s = r1 * std::min(nP, 6) / 6; |
||
473 | score += s; |
||
474 | } |
||
475 | r1 = pos.psScore1(Piece::BROOK); |
||
476 | if (r1 != 0) { |
||
477 | const int nP = BitBoard::bitCount(pos.pieceTypeBB(Piece::WPAWN)); |
||
478 | const int s = r1 * std::min(nP, 6) / 6; |
||
479 | score -= s; |
||
480 | } |
||
481 | } |
||
482 | |||
483 | return score; |
||
484 | } |
||
485 | |||
486 | int |
||
487 | Evaluate::castleBonus(const Position& pos) { |
||
488 | if (pos.getCastleMask() == 0) return 0; |
||
489 | |||
490 | const int k1 = kt1b[G8] - kt1b[E8]; |
||
491 | const int k2 = kt2b[G8] - kt2b[E8]; |
||
492 | const int ks = interpolate(k2, k1, mhd->castleIPF); |
||
493 | |||
494 | const int castleValue = ks + rt1b[F8] - rt1b[H8]; |
||
495 | if (castleValue <= 0) |
||
496 | return 0; |
||
497 | |||
498 | U64 occupied = pos.occupiedBB(); |
||
499 | int tmp = (int) (occupied & BitBoard::sqMask(B1,C1,D1,F1,G1)); |
||
500 | if (pos.a1Castle()) tmp |= 1; |
||
501 | if (pos.h1Castle()) tmp |= (1 << 7); |
||
502 | const int wBonus = (castleValue * castleMaskFactor[tmp]) >> 7; |
||
503 | |||
504 | tmp = (int) ((occupied >> 56) & BitBoard::sqMask(B1,C1,D1,F1,G1)); |
||
505 | if (pos.a8Castle()) tmp |= 1; |
||
506 | if (pos.h8Castle()) tmp |= (1 << 7); |
||
507 | const int bBonus = (castleValue * castleMaskFactor[tmp]) >> 7; |
||
508 | |||
509 | return wBonus - bBonus; |
||
510 | } |
||
511 | |||
512 | int |
||
513 | Evaluate::pawnBonus(const Position& pos) { |
||
514 | U64 key = pos.pawnZobristHash(); |
||
515 | PawnHashData& phd = getPawnHashEntry(pawnHash, key); |
||
516 | if (phd.key != key) |
||
517 | computePawnHashData(pos, phd); |
||
518 | this->phd = &phd; |
||
519 | int score = phd.score; |
||
520 | |||
521 | // Bonus for own king supporting passed pawns |
||
522 | int passedScore = phd.passedBonusW; |
||
523 | const U64 passedPawnsW = phd.passedPawns & pos.pieceTypeBB(Piece::WPAWN); |
||
524 | U64 m = passedPawnsW; |
||
525 | if (m != 0) { |
||
526 | U64 kMask = pos.pieceTypeBB(Piece::WKING); |
||
527 | int ky = Position::getY(pos.getKingSq(true)); |
||
528 | if ((m << 8) & kMask) |
||
529 | passedScore += kingPPSupportK[0] * kingPPSupportP[ky-1] / 32; |
||
530 | else if ((m << 16) & kMask) |
||
531 | passedScore += kingPPSupportK[1] * kingPPSupportP[ky-2] / 32; |
||
532 | m = ((m & BitBoard::maskAToGFiles) << 1) | ((m & BitBoard::maskBToHFiles) >> 1); |
||
533 | if (m & kMask) |
||
534 | passedScore += kingPPSupportK[2] * kingPPSupportP[ky-0] / 32; |
||
535 | if ((m << 8) & kMask) |
||
536 | passedScore += kingPPSupportK[3] * kingPPSupportP[ky-1] / 32; |
||
537 | if ((m << 16) & kMask) |
||
538 | passedScore += kingPPSupportK[4] * kingPPSupportP[ky-2] / 32; |
||
539 | |||
540 | // Penalty for opponent pieces blocking passed pawns |
||
541 | U64 ppBlockSquares = passedPawnsW << 8; |
||
542 | if (ppBlockSquares & pos.blackBB()) { |
||
543 | passedScore -= BitBoard::bitCount(ppBlockSquares & pos.pieceTypeBB(Piece::BKNIGHT)) * ppBlockerBonus[0]; |
||
544 | passedScore -= BitBoard::bitCount(ppBlockSquares & pos.pieceTypeBB(Piece::BBISHOP)) * ppBlockerBonus[1]; |
||
545 | passedScore -= BitBoard::bitCount(ppBlockSquares & pos.pieceTypeBB(Piece::BROOK)) * ppBlockerBonus[2]; |
||
546 | passedScore -= BitBoard::bitCount(ppBlockSquares & pos.pieceTypeBB(Piece::BQUEEN)) * ppBlockerBonus[3]; |
||
547 | passedScore -= BitBoard::bitCount(ppBlockSquares & pos.pieceTypeBB(Piece::BKING)) * ppBlockerBonus[4]; |
||
548 | } |
||
549 | ppBlockSquares = BitBoard::northFill(passedPawnsW << 16); |
||
550 | if (ppBlockSquares & pos.blackBB()) { |
||
551 | passedScore -= BitBoard::bitCount(ppBlockSquares & pos.pieceTypeBB(Piece::BKNIGHT)) * ppBlockerBonus[5]; |
||
552 | passedScore -= BitBoard::bitCount(ppBlockSquares & pos.pieceTypeBB(Piece::BBISHOP)) * ppBlockerBonus[6]; |
||
553 | passedScore -= BitBoard::bitCount(ppBlockSquares & pos.pieceTypeBB(Piece::BROOK)) * ppBlockerBonus[7]; |
||
554 | passedScore -= BitBoard::bitCount(ppBlockSquares & pos.pieceTypeBB(Piece::BQUEEN)) * ppBlockerBonus[8]; |
||
555 | passedScore -= BitBoard::bitCount(ppBlockSquares & pos.pieceTypeBB(Piece::BKING)) * ppBlockerBonus[9]; |
||
556 | } |
||
557 | |||
558 | // Bonus for rook behind passed pawn |
||
559 | m = BitBoard::southFill(passedPawnsW); |
||
560 | passedScore += RBehindPP1 * BitBoard::bitCount(m & pos.pieceTypeBB(Piece::WROOK)); |
||
561 | passedScore -= RBehindPP2 * BitBoard::bitCount(m & pos.pieceTypeBB(Piece::BROOK)); |
||
562 | } |
||
563 | score += interpolate(passedScore * passedPawnEGFactor / 32, passedScore, mhd->wPassedPawnIPF); |
||
564 | |||
565 | passedScore = phd.passedBonusB; |
||
566 | const U64 passedPawnsB = phd.passedPawns & pos.pieceTypeBB(Piece::BPAWN); |
||
567 | m = passedPawnsB; |
||
568 | if (m != 0) { |
||
569 | U64 kMask = pos.pieceTypeBB(Piece::BKING); |
||
570 | int ky = Position::getY(pos.getKingSq(false)); |
||
571 | if ((m >> 8) & kMask) |
||
572 | passedScore += kingPPSupportK[0] * kingPPSupportP[6-ky] / 32; |
||
573 | else if ((m >> 16) & kMask) |
||
574 | passedScore += kingPPSupportK[1] * kingPPSupportP[5-ky] / 32; |
||
575 | m = ((m & BitBoard::maskAToGFiles) << 1) | ((m & BitBoard::maskBToHFiles) >> 1); |
||
576 | if (m & kMask) |
||
577 | passedScore += kingPPSupportK[2] * kingPPSupportP[7-ky] / 32; |
||
578 | if ((m >> 8) & kMask) |
||
579 | passedScore += kingPPSupportK[3] * kingPPSupportP[6-ky] / 32; |
||
580 | if ((m >> 16) & kMask) |
||
581 | passedScore += kingPPSupportK[4] * kingPPSupportP[5-ky] / 32; |
||
582 | |||
583 | // Penalty for opponent pieces blocking passed pawns |
||
584 | U64 ppBlockSquares = passedPawnsB >> 8; |
||
585 | if (ppBlockSquares & pos.whiteBB()) { |
||
586 | passedScore -= BitBoard::bitCount(ppBlockSquares & pos.pieceTypeBB(Piece::WKNIGHT)) * ppBlockerBonus[0]; |
||
587 | passedScore -= BitBoard::bitCount(ppBlockSquares & pos.pieceTypeBB(Piece::WBISHOP)) * ppBlockerBonus[1]; |
||
588 | passedScore -= BitBoard::bitCount(ppBlockSquares & pos.pieceTypeBB(Piece::WROOK)) * ppBlockerBonus[2]; |
||
589 | passedScore -= BitBoard::bitCount(ppBlockSquares & pos.pieceTypeBB(Piece::WQUEEN)) * ppBlockerBonus[3]; |
||
590 | passedScore -= BitBoard::bitCount(ppBlockSquares & pos.pieceTypeBB(Piece::WKING)) * ppBlockerBonus[4]; |
||
591 | } |
||
592 | ppBlockSquares = BitBoard::southFill(passedPawnsB >> 16); |
||
593 | if (ppBlockSquares && pos.whiteBB()) { |
||
594 | passedScore -= BitBoard::bitCount(ppBlockSquares & pos.pieceTypeBB(Piece::WKNIGHT)) * ppBlockerBonus[5]; |
||
595 | passedScore -= BitBoard::bitCount(ppBlockSquares & pos.pieceTypeBB(Piece::WBISHOP)) * ppBlockerBonus[6]; |
||
596 | passedScore -= BitBoard::bitCount(ppBlockSquares & pos.pieceTypeBB(Piece::WROOK)) * ppBlockerBonus[7]; |
||
597 | passedScore -= BitBoard::bitCount(ppBlockSquares & pos.pieceTypeBB(Piece::WQUEEN)) * ppBlockerBonus[8]; |
||
598 | passedScore -= BitBoard::bitCount(ppBlockSquares & pos.pieceTypeBB(Piece::WKING)) * ppBlockerBonus[9]; |
||
599 | } |
||
600 | |||
601 | // Bonus for rook behind passed pawn |
||
602 | m = BitBoard::northFill(passedPawnsB); |
||
603 | passedScore += RBehindPP1 * BitBoard::bitCount(m & pos.pieceTypeBB(Piece::BROOK)); |
||
604 | passedScore -= RBehindPP2 * BitBoard::bitCount(m & pos.pieceTypeBB(Piece::WROOK)); |
||
605 | } |
||
606 | score -= interpolate(passedScore * passedPawnEGFactor / 32, passedScore, mhd->bPassedPawnIPF); |
||
607 | |||
608 | // Passed pawns are more dangerous if enemy king is far away |
||
609 | const int hiMtrl = passedPawnHiMtrl; |
||
610 | m = passedPawnsW; |
||
611 | int bestWPawnDist = 8; |
||
612 | int bestWPromSq = -1; |
||
613 | if (m != 0) { |
||
614 | int mtrlNoPawns = pos.bMtrl() - pos.bMtrlPawns(); |
||
615 | if (mtrlNoPawns < hiMtrl) { |
||
616 | int kingPos = pos.getKingSq(false); |
||
617 | while (m != 0) { |
||
618 | int sq = BitBoard::extractSquare(m); |
||
619 | int x = Position::getX(sq); |
||
620 | int y = Position::getY(sq); |
||
621 | int pawnDist = std::min(5, 7 - y); |
||
622 | int kingDist = BitBoard::getKingDistance(kingPos, Position::getSquare(x, 7)); |
||
623 | int kScore = kingDist * 4; |
||
624 | if (kingDist > pawnDist) kScore += (kingDist - pawnDist) * (kingDist - pawnDist); |
||
625 | score += interpolate(kScore, 0, mhd->wPassedPawnIPF); |
||
626 | if (!pos.isWhiteMove()) |
||
627 | kingDist--; |
||
628 | if ((pawnDist < kingDist) && (mtrlNoPawns == 0)) { |
||
629 | if (BitBoard::northFill(1ULL<<sq) & (1LL << pos.getKingSq(true))) |
||
630 | pawnDist++; // Own king blocking pawn |
||
631 | if (pawnDist < bestWPawnDist) { |
||
632 | bestWPawnDist = pawnDist; |
||
633 | bestWPromSq = Position::getSquare(x, 7); |
||
634 | } |
||
635 | } |
||
636 | } |
||
637 | } |
||
638 | } |
||
639 | int bestBPawnDist = 8; |
||
640 | int bestBPromSq = -1; |
||
641 | m = passedPawnsB; |
||
642 | if (m != 0) { |
||
643 | int mtrlNoPawns = pos.wMtrl() - pos.wMtrlPawns(); |
||
644 | if (mtrlNoPawns < hiMtrl) { |
||
645 | int kingPos = pos.getKingSq(true); |
||
646 | while (m != 0) { |
||
647 | int sq = BitBoard::extractSquare(m); |
||
648 | int x = Position::getX(sq); |
||
649 | int y = Position::getY(sq); |
||
650 | int pawnDist = std::min(5, y); |
||
651 | int kingDist = BitBoard::getKingDistance(kingPos, Position::getSquare(x, 0)); |
||
652 | int kScore = kingDist * 4; |
||
653 | if (kingDist > pawnDist) kScore += (kingDist - pawnDist) * (kingDist - pawnDist); |
||
654 | score -= interpolate(kScore, 0, mhd->bPassedPawnIPF); |
||
655 | if (pos.isWhiteMove()) |
||
656 | kingDist--; |
||
657 | if ((pawnDist < kingDist) && (mtrlNoPawns == 0)) { |
||
658 | if (BitBoard::southFill(1ULL<<sq) & (1LL << pos.getKingSq(false))) |
||
659 | pawnDist++; // Own king blocking pawn |
||
660 | if (pawnDist < bestBPawnDist) { |
||
661 | bestBPawnDist = pawnDist; |
||
662 | bestBPromSq = Position::getSquare(x, 0); |
||
663 | } |
||
664 | } |
||
665 | } |
||
666 | } |
||
667 | } |
||
668 | |||
669 | // Evaluate pawn races in pawn end games |
||
670 | const int prBonus = pawnRaceBonus; |
||
671 | if (bestWPromSq >= 0) { |
||
672 | if (bestBPromSq >= 0) { |
||
673 | int wPly = bestWPawnDist * 2; if (pos.isWhiteMove()) wPly--; |
||
674 | int bPly = bestBPawnDist * 2; if (!pos.isWhiteMove()) bPly--; |
||
675 | if (wPly < bPly - 1) { |
||
676 | score += prBonus; |
||
677 | } else if (wPly == bPly - 1) { |
||
678 | if (BitBoard::getDirection(bestWPromSq, pos.getKingSq(false))) |
||
679 | score += prBonus; |
||
680 | } else if (wPly == bPly + 1) { |
||
681 | if (BitBoard::getDirection(bestBPromSq, pos.getKingSq(true))) |
||
682 | score -= prBonus; |
||
683 | } else { |
||
684 | score -= prBonus; |
||
685 | } |
||
686 | } else |
||
687 | score += prBonus; |
||
688 | } else if (bestBPromSq >= 0) |
||
689 | score -= prBonus; |
||
690 | |||
691 | return score; |
||
692 | } |
||
693 | |||
694 | template <bool white> |
||
695 | static inline int |
||
696 | evalConnectedPP(int x, int y, U64 ppMask) { |
||
697 | if ((x >= 7) || !(BitBoard::maskFile[x+1] & ppMask)) |
||
698 | return 0; |
||
699 | |||
700 | int y2 = 0; |
||
701 | if (white) { |
||
702 | for (int i = 6; i >= 1; i--) { |
||
703 | int sq = Position::getSquare(x+1, i); |
||
704 | if (ppMask & (1ULL << sq)) { |
||
705 | y2 = i; |
||
706 | break; |
||
707 | } |
||
708 | } |
||
709 | } else { |
||
710 | for (int i = 1; i <= 6; i++) { |
||
711 | int sq = Position::getSquare(x+1, i); |
||
712 | if (ppMask & (1ULL << sq)) { |
||
713 | y2 = i; |
||
714 | break; |
||
715 | } |
||
716 | } |
||
717 | } |
||
718 | if (y2 == 0) |
||
719 | return 0; |
||
720 | |||
721 | if (!white) { |
||
722 | y = 7 - y; |
||
723 | y2 = 7 - y2; |
||
724 | } |
||
725 | return connectedPPBonus[(y-1)*6 + (y2-1)]; |
||
726 | } |
||
727 | |||
728 | /** Compute subset of squares given by mask that white is in control over, ie |
||
729 | * squares that have at least as many white pawn guards as black has pawn |
||
730 | * attacks on the square. */ |
||
731 | static inline U64 |
||
732 | wPawnCtrlSquares(U64 mask, U64 wPawns, U64 bPawns) { |
||
733 | U64 wLAtks = (wPawns & BitBoard::maskBToHFiles) << 7; |
||
734 | U64 wRAtks = (wPawns & BitBoard::maskAToGFiles) << 9; |
||
735 | U64 bLAtks = (bPawns & BitBoard::maskBToHFiles) >> 9; |
||
736 | U64 bRAtks = (bPawns & BitBoard::maskAToGFiles) >> 7; |
||
737 | return ((mask & ~bLAtks & ~bRAtks) | |
||
738 | (mask & (bLAtks ^ bRAtks) & (wLAtks | wRAtks)) | |
||
739 | (mask & wLAtks & wRAtks)); |
||
740 | } |
||
741 | |||
742 | static inline U64 |
||
743 | bPawnCtrlSquares(U64 mask, U64 wPawns, U64 bPawns) { |
||
744 | U64 wLAtks = (wPawns & BitBoard::maskBToHFiles) << 7; |
||
745 | U64 wRAtks = (wPawns & BitBoard::maskAToGFiles) << 9; |
||
746 | U64 bLAtks = (bPawns & BitBoard::maskBToHFiles) >> 9; |
||
747 | U64 bRAtks = (bPawns & BitBoard::maskAToGFiles) >> 7; |
||
748 | return ((mask & ~wLAtks & ~wRAtks) | |
||
749 | (mask & (wLAtks ^ wRAtks) & (bLAtks | bRAtks)) | |
||
750 | (mask & bLAtks & bRAtks)); |
||
751 | } |
||
752 | |||
753 | U64 |
||
754 | Evaluate::computeStalePawns(const Position& pos) { |
||
755 | const U64 wPawns = pos.pieceTypeBB(Piece::WPAWN); |
||
756 | const U64 bPawns = pos.pieceTypeBB(Piece::BPAWN); |
||
757 | |||
758 | // Compute stale white pawns |
||
759 | U64 wStale; |
||
760 | { |
||
761 | U64 wPawnCtrl = wPawnCtrlSquares(wPawns, wPawns, bPawns); |
||
762 | for (int i = 0; i < 4; i++) |
||
763 | wPawnCtrl |= wPawnCtrlSquares((wPawnCtrl << 8) & ~bPawns, wPawnCtrl, bPawns); |
||
764 | wPawnCtrl &= ~BitBoard::maskRow8; |
||
765 | U64 wPawnCtrlLAtk = (wPawnCtrl & BitBoard::maskBToHFiles) << 7; |
||
766 | U64 wPawnCtrlRAtk = (wPawnCtrl & BitBoard::maskAToGFiles) << 9; |
||
767 | |||
768 | U64 bLAtks = (bPawns & BitBoard::maskBToHFiles) >> 9; |
||
769 | U64 bRAtks = (bPawns & BitBoard::maskAToGFiles) >> 7; |
||
770 | U64 wActive = ((bLAtks ^ bRAtks) | |
||
771 | (bLAtks & bRAtks & (wPawnCtrlLAtk | wPawnCtrlRAtk))); |
||
772 | for (int i = 0; i < 4; i++) |
||
773 | wActive |= (wActive & ~(wPawns | bPawns)) >> 8; |
||
774 | wStale = wPawns & ~wActive; |
||
775 | } |
||
776 | |||
777 | // Compute stale black pawns |
||
778 | U64 bStale; |
||
779 | { |
||
780 | U64 bPawnCtrl = bPawnCtrlSquares(bPawns, wPawns, bPawns); |
||
781 | for (int i = 0; i < 4; i++) |
||
782 | bPawnCtrl |= bPawnCtrlSquares((bPawnCtrl >> 8) & ~wPawns, wPawns, bPawnCtrl); |
||
783 | bPawnCtrl &= ~BitBoard::maskRow1; |
||
784 | U64 bPawnCtrlLAtk = (bPawnCtrl & BitBoard::maskBToHFiles) >> 9; |
||
785 | U64 bPawnCtrlRAtk = (bPawnCtrl & BitBoard::maskAToGFiles) >> 7; |
||
786 | |||
787 | U64 wLAtks = (wPawns & BitBoard::maskBToHFiles) << 7; |
||
788 | U64 wRAtks = (wPawns & BitBoard::maskAToGFiles) << 9; |
||
789 | U64 bActive = ((wLAtks ^ wRAtks) | |
||
790 | (wLAtks & wRAtks & (bPawnCtrlLAtk | bPawnCtrlRAtk))); |
||
791 | for (int i = 0; i < 4; i++) |
||
792 | bActive |= (bActive & ~(wPawns | bPawns)) << 8; |
||
793 | bStale = bPawns & ~bActive; |
||
794 | } |
||
795 | |||
796 | return wStale | bStale; |
||
797 | } |
||
798 | |||
799 | void |
||
800 | Evaluate::computePawnHashData(const Position& pos, PawnHashData& ph) { |
||
801 | int score = 0; |
||
802 | |||
803 | // Evaluate double pawns and pawn islands |
||
804 | const U64 wPawns = pos.pieceTypeBB(Piece::WPAWN); |
||
805 | const U64 wPawnFiles = BitBoard::southFill(wPawns) & 0xff; |
||
806 | const int wIslands = BitBoard::bitCount(((~wPawnFiles) >> 1) & wPawnFiles); |
||
807 | |||
808 | const U64 bPawns = pos.pieceTypeBB(Piece::BPAWN); |
||
809 | const U64 bPawnFiles = BitBoard::southFill(bPawns) & 0xff; |
||
810 | const int bIslands = BitBoard::bitCount(((~bPawnFiles) >> 1) & bPawnFiles); |
||
811 | score -= (wIslands - bIslands) * pawnIslandPenalty; |
||
812 | |||
813 | // Evaluate doubled pawns |
||
814 | const U64 wDoubled = BitBoard::northFill(wPawns << 8) & wPawns; |
||
815 | U64 m = wDoubled; |
||
816 | while (m != 0) { |
||
817 | int sq = BitBoard::extractSquare(m); |
||
818 | score -= pawnDoubledPenalty[Position::getX(sq)]; |
||
819 | } |
||
820 | const U64 bDoubled = BitBoard::southFill(bPawns >> 8) & bPawns; |
||
821 | m = bDoubled; |
||
822 | while (m != 0) { |
||
823 | int sq = BitBoard::extractSquare(m); |
||
824 | score += pawnDoubledPenalty[Position::getX(sq)]; |
||
825 | } |
||
826 | |||
827 | // Evaluate isolated pawns |
||
828 | const U64 wIsolated = wPawns & ~BitBoard::northFill(BitBoard::southFill( |
||
829 | ((wPawns & BitBoard::maskAToGFiles) << 1) | |
||
830 | ((wPawns & BitBoard::maskBToHFiles) >> 1))); |
||
831 | m = wIsolated; |
||
832 | while (m != 0) { |
||
833 | int sq = BitBoard::extractSquare(m); |
||
834 | score -= pawnIsolatedPenalty[Position::getX(sq)]; |
||
835 | } |
||
836 | const U64 bIsolated = bPawns & ~BitBoard::northFill(BitBoard::southFill( |
||
837 | ((bPawns & BitBoard::maskAToGFiles) << 1) | |
||
838 | ((bPawns & BitBoard::maskBToHFiles) >> 1))); |
||
839 | m = bIsolated; |
||
840 | while (m != 0) { |
||
841 | int sq = BitBoard::extractSquare(m); |
||
842 | score += pawnIsolatedPenalty[Position::getX(sq)]; |
||
843 | } |
||
844 | |||
845 | // Evaluate backward pawns, defined as a pawn that guards a friendly pawn, |
||
846 | // can't be guarded by friendly pawns, can advance, but can't advance without |
||
847 | // being captured by an enemy pawn. |
||
848 | const U64 bPawnNoAtks = ~BitBoard::southFill(bPawnAttacks); |
||
849 | const U64 wPawnNoAtks = ~BitBoard::northFill(wPawnAttacks); |
||
850 | ph.outPostsW = bPawnNoAtks & wPawnAttacks; |
||
851 | ph.outPostsB = wPawnNoAtks & bPawnAttacks; |
||
852 | |||
853 | U64 wBackward = wPawns & ~((wPawns | bPawns) >> 8) & (bPawnAttacks >> 8) & wPawnNoAtks; |
||
854 | wBackward &= (((wPawns & BitBoard::maskBToHFiles) >> 9) | |
||
855 | ((wPawns & BitBoard::maskAToGFiles) >> 7)); |
||
856 | wBackward &= ~BitBoard::northFill(bPawnFiles); |
||
857 | U64 bBackward = bPawns & ~((wPawns | bPawns) << 8) & (wPawnAttacks << 8) & bPawnNoAtks; |
||
858 | bBackward &= (((bPawns & BitBoard::maskBToHFiles) << 7) | |
||
859 | ((bPawns & BitBoard::maskAToGFiles) << 9)); |
||
860 | bBackward &= ~BitBoard::northFill(wPawnFiles); |
||
861 | score -= (BitBoard::bitCount(wBackward) - BitBoard::bitCount(bBackward)) * pawnBackwardPenalty; |
||
862 | |||
863 | // Evaluate "semi-backward pawns", defined as pawns on 2:nd or 3:rd rank that can advance, |
||
864 | // but the advanced pawn is attacked by an enemy pawn. |
||
865 | U64 wSemiBackward = wPawns & ~((wPawns | bPawns) >> 8) & (bPawnAttacks >> 8); |
||
866 | score -= BitBoard::bitCount(wSemiBackward & BitBoard::maskRow2) * pawnSemiBackwardPenalty1; |
||
867 | score -= BitBoard::bitCount(wSemiBackward & BitBoard::maskRow3) * pawnSemiBackwardPenalty2; |
||
868 | U64 bSemiBackward = bPawns & ~((wPawns | bPawns) << 8) & (wPawnAttacks << 8); |
||
869 | score += BitBoard::bitCount(bSemiBackward & BitBoard::maskRow7) * pawnSemiBackwardPenalty1; |
||
870 | score += BitBoard::bitCount(bSemiBackward & BitBoard::maskRow6) * pawnSemiBackwardPenalty2; |
||
871 | |||
872 | // Evaluate passed pawn bonus, white |
||
873 | U64 passedPawnsW = wPawns & ~BitBoard::southFill(bPawns | bPawnAttacks | (wPawns >> 8)); |
||
874 | int passedBonusW = 0; |
||
875 | if (passedPawnsW != 0) { |
||
876 | U64 m = passedPawnsW; |
||
877 | while (m != 0) { |
||
878 | int sq = BitBoard::extractSquare(m); |
||
879 | int x = Position::getX(sq); |
||
880 | int y = Position::getY(sq); |
||
881 | passedBonusW += passedPawnBonusX[x] + passedPawnBonusY[y]; |
||
882 | passedBonusW += evalConnectedPP<true>(x, y, passedPawnsW); |
||
883 | } |
||
884 | } |
||
885 | |||
886 | // Evaluate passed pawn bonus, black |
||
887 | U64 passedPawnsB = bPawns & ~BitBoard::northFill(wPawns | wPawnAttacks | (bPawns << 8)); |
||
888 | int passedBonusB = 0; |
||
889 | if (passedPawnsB != 0) { |
||
890 | U64 m = passedPawnsB; |
||
891 | while (m != 0) { |
||
892 | int sq = BitBoard::extractSquare(m); |
||
893 | int x = Position::getX(sq); |
||
894 | int y = Position::getY(sq); |
||
895 | passedBonusB += passedPawnBonusX[x] + passedPawnBonusY[7-y]; |
||
896 | passedBonusB += evalConnectedPP<false>(x, y, passedPawnsB); |
||
897 | } |
||
898 | } |
||
899 | |||
900 | // Evaluate candidate passed pawn bonus |
||
901 | const U64 wLeftAtks = (wPawns & BitBoard::maskBToHFiles) << 7; |
||
902 | const U64 wRightAtks = (wPawns & BitBoard::maskAToGFiles) << 9; |
||
903 | const U64 bLeftAtks = (bPawns & BitBoard::maskBToHFiles) >> 9; |
||
904 | const U64 bRightAtks = (bPawns & BitBoard::maskAToGFiles) >> 7; |
||
905 | const U64 bBlockSquares = ((bLeftAtks | bRightAtks) & ~(wLeftAtks | wRightAtks)) | |
||
906 | ((bLeftAtks & bRightAtks) & ~(wLeftAtks & wRightAtks)); |
||
907 | const U64 wCandidates = wPawns & ~BitBoard::southFill(bPawns | (wPawns >> 8) | bBlockSquares) & ~passedPawnsW; |
||
908 | |||
909 | const U64 wBlockSquares = ((wLeftAtks | wRightAtks) & ~(bLeftAtks | bRightAtks)) | |
||
910 | ((wLeftAtks & wRightAtks) & ~(bLeftAtks & bRightAtks)); |
||
911 | const U64 bCandidates = bPawns & ~BitBoard::northFill(wPawns | (bPawns << 8) | wBlockSquares) & ~passedPawnsB; |
||
912 | |||
913 | { |
||
914 | U64 m = wCandidates; |
||
915 | while (m != 0) { |
||
916 | int sq = BitBoard::extractSquare(m); |
||
917 | int y = Position::getY(sq); |
||
918 | passedBonusW += candidatePassedBonus[y]; |
||
919 | } |
||
920 | } |
||
921 | { |
||
922 | U64 m = bCandidates; |
||
923 | while (m != 0) { |
||
924 | int sq = BitBoard::extractSquare(m); |
||
925 | int y = Position::getY(sq); |
||
926 | passedBonusB += candidatePassedBonus[7-y]; |
||
927 | } |
||
928 | } |
||
929 | |||
930 | { // Bonus for pawns protected by pawns |
||
931 | U64 m = wPawnAttacks & wPawns; |
||
932 | while (m != 0) { |
||
933 | int sq = BitBoard::extractSquare(m); |
||
934 | score += protectedPawnBonus[63-sq]; |
||
935 | } |
||
936 | m = bPawnAttacks & bPawns; |
||
937 | while (m != 0) { |
||
938 | int sq = BitBoard::extractSquare(m); |
||
939 | score -= protectedPawnBonus[sq]; |
||
940 | } |
||
941 | } |
||
942 | { // Bonus for pawns attacked by pawns |
||
943 | U64 m = wPawnAttacks & bPawns; |
||
944 | while (m != 0) { |
||
945 | int sq = BitBoard::extractSquare(m); |
||
946 | score += attackedPawnBonus[63-sq]; |
||
947 | } |
||
948 | m = bPawnAttacks & wPawns; |
||
949 | while (m != 0) { |
||
950 | int sq = BitBoard::extractSquare(m); |
||
951 | score -= attackedPawnBonus[sq]; |
||
952 | } |
||
953 | } |
||
954 | |||
955 | ph.key = pos.pawnZobristHash(); |
||
956 | ph.score = score; |
||
957 | ph.passedBonusW = (S16)passedBonusW; |
||
958 | ph.passedBonusB = (S16)passedBonusB; |
||
959 | ph.passedPawns = passedPawnsW | passedPawnsB; |
||
960 | ph.stalePawns = computeStalePawns(pos) & ~passedPawnsW & ~passedPawnsB; |
||
961 | } |
||
962 | |||
963 | int |
||
964 | Evaluate::rookBonus(const Position& pos) { |
||
965 | int score = 0; |
||
966 | const U64 wPawns = pos.pieceTypeBB(Piece::WPAWN); |
||
967 | const U64 bPawns = pos.pieceTypeBB(Piece::BPAWN); |
||
968 | const U64 occupied = pos.occupiedBB(); |
||
969 | U64 m = pos.pieceTypeBB(Piece::WROOK); |
||
970 | while (m != 0) { |
||
971 | int sq = BitBoard::extractSquare(m); |
||
972 | const int x = Position::getX(sq); |
||
973 | if ((wPawns & BitBoard::maskFile[x]) == 0) { // At least half-open file |
||
974 | score += (bPawns & BitBoard::maskFile[x]) == 0 ? (int)rookOpenBonus : (int)rookHalfOpenBonus; // Pierre-Marie Baty -- added type cast |
||
975 | } // Pierre-Marie Baty -- braces fix |
||
976 | U64 atk = BitBoard::rookAttacks(sq, occupied); |
||
977 | wAttacksBB |= atk; |
||
978 | score += rookMobScore[BitBoard::bitCount(atk & ~(pos.whiteBB() | bPawnAttacks))]; |
||
979 | if ((atk & bKingZone) != 0) |
||
980 | bKingAttacks += BitBoard::bitCount(atk & bKingZone); |
||
981 | } |
||
982 | U64 r7 = pos.pieceTypeBB(Piece::WROOK) & BitBoard::maskRow7; |
||
983 | if (((r7 & (r7 - 1)) != 0) && |
||
984 | ((pos.pieceTypeBB(Piece::BKING) & BitBoard::maskRow8) != 0)) |
||
985 | score += rookDouble7thRowBonus; // Two rooks on 7:th row |
||
986 | m = pos.pieceTypeBB(Piece::BROOK); |
||
987 | while (m != 0) { |
||
988 | int sq = BitBoard::extractSquare(m); |
||
989 | const int x = Position::getX(sq); |
||
990 | if ((bPawns & BitBoard::maskFile[x]) == 0) { |
||
991 | score -= (wPawns & BitBoard::maskFile[x]) == 0 ? (int)rookOpenBonus : (int)rookHalfOpenBonus; // Pierre-Marie Baty -- added type cast |
||
992 | } // Pierre-Marie Baty -- braces fix |
||
993 | U64 atk = BitBoard::rookAttacks(sq, occupied); |
||
994 | bAttacksBB |= atk; |
||
995 | score -= rookMobScore[BitBoard::bitCount(atk & ~(pos.blackBB() | wPawnAttacks))]; |
||
996 | if ((atk & wKingZone) != 0) |
||
997 | wKingAttacks += BitBoard::bitCount(atk & wKingZone); |
||
998 | } |
||
999 | r7 = pos.pieceTypeBB(Piece::BROOK) & BitBoard::maskRow2; |
||
1000 | if (((r7 & (r7 - 1)) != 0) && |
||
1001 | ((pos.pieceTypeBB(Piece::WKING) & BitBoard::maskRow1) != 0)) |
||
1002 | score -= rookDouble7thRowBonus; // Two rooks on 2:nd row |
||
1003 | return score; |
||
1004 | } |
||
1005 | |||
1006 | int |
||
1007 | Evaluate::bishopEval(const Position& pos, int oldScore) { |
||
1008 | int score = 0; |
||
1009 | const U64 occupied = pos.occupiedBB(); |
||
1010 | const U64 wBishops = pos.pieceTypeBB(Piece::WBISHOP); |
||
1011 | const U64 bBishops = pos.pieceTypeBB(Piece::BBISHOP); |
||
1012 | if ((wBishops | bBishops) == 0) |
||
1013 | return 0; |
||
1014 | U64 m = wBishops; |
||
1015 | while (m != 0) { |
||
1016 | int sq = BitBoard::extractSquare(m); |
||
1017 | U64 atk = BitBoard::bishopAttacks(sq, occupied); |
||
1018 | wAttacksBB |= atk; |
||
1019 | score += bishMobScore[BitBoard::bitCount(atk & ~(pos.whiteBB() | bPawnAttacks))]; |
||
1020 | if ((atk & bKingZone) != 0) |
||
1021 | bKingAttacks += BitBoard::bitCount(atk & bKingZone); |
||
1022 | } |
||
1023 | m = bBishops; |
||
1024 | while (m != 0) { |
||
1025 | int sq = BitBoard::extractSquare(m); |
||
1026 | U64 atk = BitBoard::bishopAttacks(sq, occupied); |
||
1027 | bAttacksBB |= atk; |
||
1028 | score -= bishMobScore[BitBoard::bitCount(atk & ~(pos.blackBB() | wPawnAttacks))]; |
||
1029 | if ((atk & wKingZone) != 0) |
||
1030 | wKingAttacks += BitBoard::bitCount(atk & wKingZone); |
||
1031 | } |
||
1032 | |||
1033 | bool whiteDark = (wBishops & BitBoard::maskDarkSq ) != 0; |
||
1034 | bool whiteLight = (wBishops & BitBoard::maskLightSq) != 0; |
||
1035 | bool blackDark = (bBishops & BitBoard::maskDarkSq ) != 0; |
||
1036 | bool blackLight = (bBishops & BitBoard::maskLightSq) != 0; |
||
1037 | int numWhite = (whiteDark ? 1 : 0) + (whiteLight ? 1 : 0); |
||
1038 | int numBlack = (blackDark ? 1 : 0) + (blackLight ? 1 : 0); |
||
1039 | |||
1040 | // Bishop pair bonus |
||
1041 | if (numWhite == 2) { |
||
1042 | int numMinors = BitBoard::bitCount(pos.pieceTypeBB(Piece::BBISHOP, Piece::BKNIGHT)); |
||
1043 | const int numPawns = BitBoard::bitCount(pos.pieceTypeBB(Piece::WPAWN)); |
||
1044 | score += bishopPairValue[std::min(numMinors,3)] - numPawns * bishopPairPawnPenalty; |
||
1045 | } |
||
1046 | if (numBlack == 2) { |
||
1047 | int numMinors = BitBoard::bitCount(pos.pieceTypeBB(Piece::WBISHOP, Piece::WKNIGHT)); |
||
1048 | const int numPawns = BitBoard::bitCount(pos.pieceTypeBB(Piece::BPAWN)); |
||
1049 | score -= bishopPairValue[std::min(numMinors,3)] - numPawns * bishopPairPawnPenalty; |
||
1050 | } |
||
1051 | |||
1052 | if ((numWhite == 1) && (numBlack == 1) && (whiteDark != blackDark) && |
||
1053 | (pos.wMtrl() - pos.wMtrlPawns() == pos.bMtrl() - pos.bMtrlPawns())) { |
||
1054 | const int penalty = (oldScore + score) * oppoBishopPenalty / 128; |
||
1055 | score -= interpolate(penalty, 0, mhd->diffColorBishopIPF); |
||
1056 | } else { |
||
1057 | if (numWhite == 1) { |
||
1058 | U64 bishColorMask = whiteDark ? BitBoard::maskDarkSq : BitBoard::maskLightSq; |
||
1059 | U64 m = pos.pieceTypeBB(Piece::WPAWN) & bishColorMask; |
||
1060 | m |= (m << 8) & pos.pieceTypeBB(Piece::BPAWN); |
||
1061 | score -= 2 * BitBoard::bitCount(m); |
||
1062 | } |
||
1063 | if (numBlack == 1) { |
||
1064 | U64 bishColorMask = blackDark ? BitBoard::maskDarkSq : BitBoard::maskLightSq; |
||
1065 | U64 m = pos.pieceTypeBB(Piece::BPAWN) & bishColorMask; |
||
1066 | m |= (m >> 8) & pos.pieceTypeBB(Piece::WPAWN); |
||
1067 | score += 2 * BitBoard::bitCount(m); |
||
1068 | } |
||
1069 | } |
||
1070 | |||
1071 | // Penalty for bishop trapped behind pawn at a2/h2/a7/h7 |
||
1072 | if (((wBishops | bBishops) & BitBoard::sqMask(A2,H2,A7,H7)) != 0) { |
||
1073 | const int bTrapped = trappedBishopPenalty; |
||
1074 | if ((pos.getPiece(A7) == Piece::WBISHOP) && |
||
1075 | (pos.getPiece(B6) == Piece::BPAWN) && |
||
1076 | (pos.getPiece(C7) == Piece::BPAWN)) |
||
1077 | score -= bTrapped; |
||
1078 | if ((pos.getPiece(H7) == Piece::WBISHOP) && |
||
1079 | (pos.getPiece(G6) == Piece::BPAWN) && |
||
1080 | (pos.getPiece(F7) == Piece::BPAWN)) |
||
1081 | score -= bTrapped; |
||
1082 | if ((pos.getPiece(A2) == Piece::BBISHOP) && |
||
1083 | (pos.getPiece(B3) == Piece::WPAWN) && |
||
1084 | (pos.getPiece(C2) == Piece::WPAWN)) |
||
1085 | score += bTrapped; |
||
1086 | if ((pos.getPiece(H2) == Piece::BBISHOP) && |
||
1087 | (pos.getPiece(G3) == Piece::WPAWN) && |
||
1088 | (pos.getPiece(F2) == Piece::WPAWN)) |
||
1089 | score += bTrapped; |
||
1090 | } |
||
1091 | |||
1092 | return score; |
||
1093 | } |
||
1094 | |||
1095 | int |
||
1096 | Evaluate::knightEval(const Position& pos) { |
||
1097 | int score = 0; |
||
1098 | U64 wKnights = pos.pieceTypeBB(Piece::WKNIGHT); |
||
1099 | U64 bKnights = pos.pieceTypeBB(Piece::BKNIGHT); |
||
1100 | if ((wKnights | bKnights) == 0) |
||
1101 | return 0; |
||
1102 | |||
1103 | // Knight mobility |
||
1104 | U64 m = wKnights; |
||
1105 | while (m != 0) { |
||
1106 | int sq = BitBoard::extractSquare(m); |
||
1107 | U64 atk = BitBoard::knightAttacks[sq]; |
||
1108 | wAttacksBB |= atk; |
||
1109 | score += knightMobScoreA[sq][BitBoard::bitCount(atk & ~pos.whiteBB() & ~bPawnAttacks)]; |
||
1110 | } |
||
1111 | |||
1112 | m = bKnights; |
||
1113 | while (m != 0) { |
||
1114 | int sq = BitBoard::extractSquare(m); |
||
1115 | U64 atk = BitBoard::knightAttacks[sq]; |
||
1116 | bAttacksBB |= atk; |
||
1117 | score -= knightMobScoreA[sq][BitBoard::bitCount(atk & ~pos.blackBB() & ~wPawnAttacks)]; |
||
1118 | } |
||
1119 | |||
1120 | m = wKnights & phd->outPostsW; |
||
1121 | if (m != 0) { |
||
1122 | int outPost = 0; |
||
1123 | while (m != 0) { |
||
1124 | int sq = BitBoard::extractSquare(m); |
||
1125 | outPost += knightOutpostBonus[63-sq]; |
||
1126 | } |
||
1127 | score += interpolate(0, outPost, mhd->wKnightOutPostIPF); |
||
1128 | } |
||
1129 | |||
1130 | m = bKnights & phd->outPostsB; |
||
1131 | if (m != 0) { |
||
1132 | int outPost = 0; |
||
1133 | while (m != 0) { |
||
1134 | int sq = BitBoard::extractSquare(m); |
||
1135 | outPost += knightOutpostBonus[sq]; |
||
1136 | } |
||
1137 | score -= interpolate(0, outPost, mhd->bKnightOutPostIPF); |
||
1138 | } |
||
1139 | |||
1140 | return score; |
||
1141 | } |
||
1142 | |||
1143 | int |
||
1144 | Evaluate::threatBonus(const Position& pos) { |
||
1145 | int score = 0; |
||
1146 | |||
1147 | // Sum values for all black pieces under attack |
||
1148 | wAttacksBB &= pos.pieceTypeBB(Piece::BKNIGHT, Piece::BBISHOP, Piece::BROOK, Piece::BQUEEN); |
||
1149 | wAttacksBB |= wPawnAttacks; |
||
1150 | U64 m = wAttacksBB & pos.blackBB() & ~pos.pieceTypeBB(Piece::BKING); |
||
1151 | int tmp = 0; |
||
1152 | while (m != 0) { |
||
1153 | int sq = BitBoard::extractSquare(m); |
||
1154 | tmp += ::pieceValue[pos.getPiece(sq)]; |
||
1155 | } |
||
1156 | score += tmp + tmp * tmp / threatBonus2; |
||
1157 | |||
1158 | // Sum values for all white pieces under attack |
||
1159 | bAttacksBB &= pos.pieceTypeBB(Piece::WKNIGHT, Piece::WBISHOP, Piece::WROOK, Piece::WQUEEN); |
||
1160 | bAttacksBB |= bPawnAttacks; |
||
1161 | m = bAttacksBB & pos.whiteBB() & ~pos.pieceTypeBB(Piece::WKING); |
||
1162 | tmp = 0; |
||
1163 | while (m != 0) { |
||
1164 | int sq = BitBoard::extractSquare(m); |
||
1165 | tmp += ::pieceValue[pos.getPiece(sq)]; |
||
1166 | } |
||
1167 | score -= tmp + tmp * tmp / threatBonus2; |
||
1168 | return score / threatBonus1; |
||
1169 | } |
||
1170 | |||
1171 | int |
||
1172 | Evaluate::protectBonus(const Position& pos) { |
||
1173 | int score = 0; |
||
1174 | score += BitBoard::bitCount(pos.pieceTypeBB(Piece::WKNIGHT) & wPawnAttacks) * ::protectBonus[0]; |
||
1175 | score += BitBoard::bitCount(pos.pieceTypeBB(Piece::WBISHOP) & wPawnAttacks) * ::protectBonus[1]; |
||
1176 | score += BitBoard::bitCount(pos.pieceTypeBB(Piece::WROOK ) & wPawnAttacks) * ::protectBonus[2]; |
||
1177 | score += BitBoard::bitCount(pos.pieceTypeBB(Piece::WQUEEN ) & wPawnAttacks) * ::protectBonus[3]; |
||
1178 | score -= BitBoard::bitCount(pos.pieceTypeBB(Piece::BKNIGHT) & bPawnAttacks) * ::protectBonus[0]; |
||
1179 | score -= BitBoard::bitCount(pos.pieceTypeBB(Piece::BBISHOP) & bPawnAttacks) * ::protectBonus[1]; |
||
1180 | score -= BitBoard::bitCount(pos.pieceTypeBB(Piece::BROOK ) & bPawnAttacks) * ::protectBonus[2]; |
||
1181 | score -= BitBoard::bitCount(pos.pieceTypeBB(Piece::BQUEEN ) & bPawnAttacks) * ::protectBonus[3]; |
||
1182 | return score; |
||
1183 | } |
||
1184 | |||
1185 | /** Compute king safety for both kings. */ |
||
1186 | int |
||
1187 | Evaluate::kingSafety(const Position& pos) { |
||
1188 | const int minM = (rV + bV) * 2; |
||
1189 | const int m = pos.wMtrl() - pos.wMtrlPawns() + pos.bMtrl() - pos.bMtrlPawns(); |
||
1190 | if (m <= minM) |
||
1191 | return 0; |
||
1192 | |||
1193 | const int wKing = pos.getKingSq(true); |
||
1194 | const int bKing = pos.getKingSq(false); |
||
1195 | int score = kingSafetyKPPart(pos); |
||
1196 | if (Position::getY(wKing) == 0) { |
||
1197 | if (((pos.pieceTypeBB(Piece::WKING) & BitBoard::sqMask(F1,G1)) != 0) && |
||
1198 | ((pos.pieceTypeBB(Piece::WROOK) & BitBoard::sqMask(G1,H1)) != 0) && |
||
1199 | ((pos.pieceTypeBB(Piece::WPAWN) & BitBoard::maskFile[6]) != 0)) { |
||
1200 | score -= ((pos.pieceTypeBB(Piece::WPAWN) & BitBoard::maskFile[7]) != 0) ? |
||
1201 | (int)trappedRookPenalty1 : (int)trappedRookPenalty2; // Pierre-Marie Baty -- added type cast |
||
1202 | } else |
||
1203 | if (((pos.pieceTypeBB(Piece::WKING) & BitBoard::sqMask(B1,C1)) != 0) && |
||
1204 | ((pos.pieceTypeBB(Piece::WROOK) & BitBoard::sqMask(A1,B1)) != 0) && |
||
1205 | ((pos.pieceTypeBB(Piece::WPAWN) & BitBoard::maskFile[1]) != 0)) { |
||
1206 | score -= ((pos.pieceTypeBB(Piece::WPAWN) & BitBoard::maskFile[0]) != 0) ? |
||
1207 | (int)trappedRookPenalty1 : (int)trappedRookPenalty2; // Pierre-Marie Baty -- added type cast |
||
1208 | } |
||
1209 | } |
||
1210 | if (Position::getY(bKing) == 7) { |
||
1211 | if (((pos.pieceTypeBB(Piece::BKING) & BitBoard::sqMask(F8,G8)) != 0) && |
||
1212 | ((pos.pieceTypeBB(Piece::BROOK) & BitBoard::sqMask(G8,H8)) != 0) && |
||
1213 | ((pos.pieceTypeBB(Piece::BPAWN) & BitBoard::maskFile[6]) != 0)) { |
||
1214 | score += ((pos.pieceTypeBB(Piece::BPAWN) & BitBoard::maskFile[7]) != 0) ? |
||
1215 | (int)trappedRookPenalty1 : (int)trappedRookPenalty2; // Pierre-Marie Baty -- added type cast |
||
1216 | } else |
||
1217 | if (((pos.pieceTypeBB(Piece::BKING) & BitBoard::sqMask(B8,C8)) != 0) && |
||
1218 | ((pos.pieceTypeBB(Piece::BROOK) & BitBoard::sqMask(A8,B8)) != 0) && |
||
1219 | ((pos.pieceTypeBB(Piece::BPAWN) & BitBoard::maskFile[1]) != 0)) { |
||
1220 | score += ((pos.pieceTypeBB(Piece::BPAWN) & BitBoard::maskFile[0]) != 0) ? |
||
1221 | (int)trappedRookPenalty1 : (int)trappedRookPenalty2; // Pierre-Marie Baty -- added type cast |
||
1222 | } |
||
1223 | } |
||
1224 | |||
1225 | // Bonus for minor pieces protecting king |
||
1226 | score += BitBoard::bitCount(Evaluate::knightKingProtectPattern[wKing] & pos.pieceTypeBB(Piece::WKNIGHT)) * knightKingProtectBonus; |
||
1227 | score += BitBoard::bitCount(Evaluate::bishopKingProtectPattern[wKing] & pos.pieceTypeBB(Piece::WBISHOP)) * bishopKingProtectBonus; |
||
1228 | score -= BitBoard::bitCount(Evaluate::knightKingProtectPattern[bKing] & pos.pieceTypeBB(Piece::BKNIGHT)) * knightKingProtectBonus; |
||
1229 | score -= BitBoard::bitCount(Evaluate::bishopKingProtectPattern[bKing] & pos.pieceTypeBB(Piece::BBISHOP)) * bishopKingProtectBonus; |
||
1230 | |||
1231 | score += kingAttackWeight[std::min(bKingAttacks, 13)] - kingAttackWeight[std::min(wKingAttacks, 13)]; |
||
1232 | const int kSafety = interpolate(0, score, mhd->kingSafetyIPF); |
||
1233 | return kSafety; |
||
1234 | } |
||
1235 | |||
1236 | template <bool white, bool right> |
||
1237 | static inline int |
||
1238 | evalKingPawnShelter(const Position& pos) { |
||
1239 | const int mPawn = white ? Piece::WPAWN : Piece::BPAWN; |
||
1240 | const int oPawn = white ? Piece::BPAWN : Piece::WPAWN; |
||
1241 | |||
1242 | const int yBeg = white ? 1 : 6; |
||
1243 | const int yInc = white ? 1 : -1; |
||
1244 | const int yEnd = white ? 4 : 3; |
||
1245 | const int xBeg = right ? 5 : 2; |
||
1246 | const int xInc = right ? 1 : -1; |
||
1247 | const int xEnd = right ? 8 : -1; |
||
1248 | int idx = 0; |
||
1249 | int score = 0; |
||
1250 | for (int y = yBeg; y != yEnd; y += yInc) { |
||
1251 | for (int x = xBeg; x != xEnd; x += xInc) { |
||
1252 | int p = pos.getPiece(Position::getSquare(x, y)); |
||
1253 | if (p == mPawn) |
||
1254 | score += pawnShelterTable[idx]; |
||
1255 | else if (p == oPawn) |
||
1256 | score -= pawnStormTable[idx]; |
||
1257 | idx++; |
||
1258 | } |
||
1259 | } |
||
1260 | return score; |
||
1261 | } |
||
1262 | |||
1263 | int |
||
1264 | Evaluate::kingSafetyKPPart(const Position& pos) { |
||
1265 | const U64 key = pos.pawnZobristHash() ^ pos.kingZobristHash(); |
||
1266 | KingSafetyHashData& ksh = getKingSafetyHashEntry(kingSafetyHash, key); |
||
1267 | if (ksh.key != key) { |
||
1268 | int score = 0; |
||
1269 | const U64 wPawns = pos.pieceTypeBB(Piece::WPAWN); |
||
1270 | const U64 bPawns = pos.pieceTypeBB(Piece::BPAWN); |
||
1271 | { // White pawn shelter bonus |
||
1272 | int safety = 0; |
||
1273 | int halfOpenFiles = 0; |
||
1274 | if (Position::getY(pos.wKingSq()) < 2) { |
||
1275 | U64 shelter = 1ULL << Position::getX(pos.wKingSq()); |
||
1276 | shelter |= ((shelter & BitBoard::maskBToHFiles) >> 1) | |
||
1277 | ((shelter & BitBoard::maskAToGFiles) << 1); |
||
1278 | shelter <<= 8; |
||
1279 | safety += kingSafetyWeight1 * BitBoard::bitCount(wPawns & shelter); |
||
1280 | safety -= kingSafetyWeight2 * BitBoard::bitCount(bPawns & (shelter | (shelter << 8))); |
||
1281 | shelter <<= 8; |
||
1282 | safety += kingSafetyWeight3 * BitBoard::bitCount(wPawns & shelter); |
||
1283 | shelter <<= 8; |
||
1284 | safety -= kingSafetyWeight4 * BitBoard::bitCount(bPawns & shelter); |
||
1285 | |||
1286 | U64 wOpen = BitBoard::southFill(shelter) & (~BitBoard::southFill(wPawns)) & 0xff; |
||
1287 | if (wOpen != 0) { |
||
1288 | halfOpenFiles += kingSafetyHalfOpenBCDEFG1 * BitBoard::bitCount(wOpen & 0xe7); |
||
1289 | halfOpenFiles += kingSafetyHalfOpenAH1 * BitBoard::bitCount(wOpen & 0x18); |
||
1290 | } |
||
1291 | U64 bOpen = BitBoard::southFill(shelter) & (~BitBoard::southFill(bPawns)) & 0xff; |
||
1292 | if (bOpen != 0) { |
||
1293 | halfOpenFiles += kingSafetyHalfOpenBCDEFG2 * BitBoard::bitCount(bOpen & 0xe7); |
||
1294 | halfOpenFiles += kingSafetyHalfOpenAH2 * BitBoard::bitCount(bOpen & 0x18); |
||
1295 | } |
||
1296 | const int th = kingSafetyThreshold; |
||
1297 | safety = std::min(safety, th); |
||
1298 | |||
1299 | const int xKing = Position::getX(pos.wKingSq()); |
||
1300 | if (xKing >= 5) |
||
1301 | score += evalKingPawnShelter<true, true>(pos); |
||
1302 | else if (xKing <= 2) |
||
1303 | score += evalKingPawnShelter<true, false>(pos); |
||
1304 | } |
||
1305 | const int kSafety = safety - halfOpenFiles; |
||
1306 | score += kSafety; |
||
1307 | } |
||
1308 | { // Black pawn shelter bonus |
||
1309 | int safety = 0; |
||
1310 | int halfOpenFiles = 0; |
||
1311 | if (Position::getY(pos.bKingSq()) >= 6) { |
||
1312 | U64 shelter = 1ULL << (56 + Position::getX(pos.bKingSq())); |
||
1313 | shelter |= ((shelter & BitBoard::maskBToHFiles) >> 1) | |
||
1314 | ((shelter & BitBoard::maskAToGFiles) << 1); |
||
1315 | shelter >>= 8; |
||
1316 | safety += kingSafetyWeight1 * BitBoard::bitCount(bPawns & shelter); |
||
1317 | safety -= kingSafetyWeight2 * BitBoard::bitCount(wPawns & (shelter | (shelter >> 8))); |
||
1318 | shelter >>= 8; |
||
1319 | safety += kingSafetyWeight3 * BitBoard::bitCount(bPawns & shelter); |
||
1320 | shelter >>= 8; |
||
1321 | safety -= kingSafetyWeight4 * BitBoard::bitCount(wPawns & shelter); |
||
1322 | |||
1323 | U64 bOpen = BitBoard::southFill(shelter) & (~BitBoard::southFill(bPawns)) & 0xff; |
||
1324 | if (bOpen != 0) { |
||
1325 | halfOpenFiles += kingSafetyHalfOpenBCDEFG1 * BitBoard::bitCount(bOpen & 0xe7); |
||
1326 | halfOpenFiles += kingSafetyHalfOpenAH1 * BitBoard::bitCount(bOpen & 0x18); |
||
1327 | } |
||
1328 | U64 wOpen = BitBoard::southFill(shelter) & (~BitBoard::southFill(wPawns)) & 0xff; |
||
1329 | if (wOpen != 0) { |
||
1330 | halfOpenFiles += kingSafetyHalfOpenBCDEFG2 * BitBoard::bitCount(wOpen & 0xe7); |
||
1331 | halfOpenFiles += kingSafetyHalfOpenAH2 * BitBoard::bitCount(wOpen & 0x18); |
||
1332 | } |
||
1333 | const int th = kingSafetyThreshold; |
||
1334 | safety = std::min(safety, th); |
||
1335 | |||
1336 | const int xKing = Position::getX(pos.bKingSq()); |
||
1337 | if (xKing >= 5) |
||
1338 | score -= evalKingPawnShelter<false, true>(pos); |
||
1339 | else if (xKing <= 2) |
||
1340 | score -= evalKingPawnShelter<false, false>(pos); |
||
1341 | } |
||
1342 | const int kSafety = safety - halfOpenFiles; |
||
1343 | score -= kSafety; |
||
1344 | } |
||
1345 | // Pawn storm bonus |
||
1346 | static const int kingZone[8] = {0,0,0, 1,1, 2,2,2}; |
||
1347 | static const U64 pStormMask[3] = { 0x0707070707070707ULL, 0, 0xE0E0E0E0E0E0E0E0ULL }; |
||
1348 | const int wKingZone = kingZone[Position::getX(pos.wKingSq())]; |
||
1349 | const int bKingZone = kingZone[Position::getX(pos.bKingSq())]; |
||
1350 | const int kingDiff = std::abs(wKingZone - bKingZone); |
||
1351 | if (kingDiff > 1) { |
||
1352 | U64 m = wPawns & pStormMask[bKingZone]; |
||
1353 | while (m != 0) { |
||
1354 | int sq = BitBoard::extractSquare(m); |
||
1355 | score += pawnStormBonus * (Position::getY(sq)-5); |
||
1356 | } |
||
1357 | m = bPawns & pStormMask[wKingZone]; |
||
1358 | while (m != 0) { |
||
1359 | int sq = BitBoard::extractSquare(m); |
||
1360 | score += pawnStormBonus * (Position::getY(sq)-2); |
||
1361 | } |
||
1362 | } |
||
1363 | |||
1364 | ksh.key = key; |
||
1365 | ksh.score = score; |
||
1366 | } |
||
1367 | return ksh.score; |
||
1368 | } |
||
1369 | |||
1370 | std::shared_ptr<Evaluate::EvalHashTables> |
||
1371 | Evaluate::getEvalHashTables() { |
||
1372 | return std::make_shared<EvalHashTables>(); |
||
1373 | } |
||
1374 | |||
1375 | int |
||
1376 | Evaluate::swindleScore(int evalScore) { |
||
1377 | int sgn = evalScore >= 0 ? 1 : -1; |
||
1378 | int score = std::abs(evalScore) + 4; |
||
1379 | int lg = floorLog2(score); |
||
1380 | score = (lg - 3) * 4 + (score >> (lg - 2)); |
||
1381 | return sgn * score; |
||
1382 | } |