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 | } |