X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fendgame.cpp;h=681b290c4711edd8d2d08fe92dd3afcc24b67fb0;hp=2c87b2a128a4ec7108246c1f043156148fdee05b;hb=3e4fed3a91752da394f7c912f4e5e29dc39391f6;hpb=42b48b08e81b55e385e55b3074b7c59d81809a45 diff --git a/src/endgame.cpp b/src/endgame.cpp index 2c87b2a1..681b290c 100644 --- a/src/endgame.cpp +++ b/src/endgame.cpp @@ -59,6 +59,9 @@ namespace { const int PushClose[8] = { 0, 0, 100, 80, 60, 40, 20, 10 }; const int PushAway [8] = { 0, 5, 20, 40, 60, 80, 90, 100 }; + // Pawn Rank based scaling factors used in KRPPKRP endgame + const int KRPPKRPScaleFactors[RANK_NB] = { 0, 9, 10, 14, 21, 44, 0, 0 }; + #ifndef NDEBUG bool verify_material(const Position& pos, Color c, Value npm, int pawnsCnt) { return pos.non_pawn_material(c) == npm && pos.count(c) == pawnsCnt; @@ -71,7 +74,7 @@ namespace { assert(pos.count(strongSide) == 1); - if (file_of(pos.list(strongSide)[0]) >= FILE_E) + if (file_of(pos.square(strongSide)) >= FILE_E) sq = Square(sq ^ 7); // Mirror SQ_H1 -> SQ_A1 if (strongSide == BLACK) @@ -96,12 +99,9 @@ namespace { string fen = sides[0] + char(8 - sides[0].length() + '0') + "/8/8/8/8/8/8/" + sides[1] + char(8 - sides[1].length() + '0') + " w - - 0 10"; - return Position(fen, false, NULL).material_key(); + return Position(fen, false, nullptr).material_key(); } - template - void delete_endgame(const typename M::value_type& p) { delete p.second; } - } // namespace @@ -128,17 +128,11 @@ Endgames::Endgames() { add("KRPPKRP"); } -Endgames::~Endgames() { - - for_each(m1.begin(), m1.end(), delete_endgame); - for_each(m2.begin(), m2.end(), delete_endgame); -} -template +template void Endgames::add(const string& code) { - - map((Endgame*)0)[key(code, WHITE)] = new Endgame(WHITE); - map((Endgame*)0)[key(code, BLACK)] = new Endgame(BLACK); + map()[key(code, WHITE)] = std::unique_ptr>(new Endgame(WHITE)); + map()[key(code, BLACK)] = std::unique_ptr>(new Endgame(BLACK)); } @@ -156,8 +150,8 @@ Value Endgame::operator()(const Position& pos) const { if (pos.side_to_move() == weakSide && !MoveList(pos).size()) return VALUE_DRAW; - Square winnerKSq = pos.king_square(strongSide); - Square loserKSq = pos.king_square(weakSide); + Square winnerKSq = pos.square(strongSide); + Square loserKSq = pos.square(weakSide); Value result = pos.non_pawn_material(strongSide) + pos.count(strongSide) * PawnValueEg @@ -167,9 +161,9 @@ Value Endgame::operator()(const Position& pos) const { if ( pos.count(strongSide) || pos.count(strongSide) ||(pos.count(strongSide) && pos.count(strongSide)) - ||(pos.count(strongSide) > 1 && opposite_colors(pos.list(strongSide)[0], - pos.list(strongSide)[1]))) - result += VALUE_KNOWN_WIN; + ||(pos.count(strongSide) > 1 && opposite_colors(pos.squares(strongSide)[0], + pos.squares(strongSide)[1]))) + result = std::min(result + VALUE_KNOWN_WIN, VALUE_MATE_IN_MAX_PLY - 1); return strongSide == pos.side_to_move() ? result : -result; } @@ -183,9 +177,9 @@ Value Endgame::operator()(const Position& pos) const { assert(verify_material(pos, strongSide, KnightValueMg + BishopValueMg, 0)); assert(verify_material(pos, weakSide, VALUE_ZERO, 0)); - Square winnerKSq = pos.king_square(strongSide); - Square loserKSq = pos.king_square(weakSide); - Square bishopSq = pos.list(strongSide)[0]; + Square winnerKSq = pos.square(strongSide); + Square loserKSq = pos.square(weakSide); + Square bishopSq = pos.square(strongSide); // kbnk_mate_table() tries to drive toward corners A1 or H8. If we have a // bishop that cannot reach the above squares, we flip the kings in order @@ -212,9 +206,9 @@ Value Endgame::operator()(const Position& pos) const { assert(verify_material(pos, weakSide, VALUE_ZERO, 0)); // Assume strongSide is white and the pawn is on files A-D - Square wksq = normalize(pos, strongSide, pos.king_square(strongSide)); - Square bksq = normalize(pos, strongSide, pos.king_square(weakSide)); - Square psq = normalize(pos, strongSide, pos.list(strongSide)[0]); + Square wksq = normalize(pos, strongSide, pos.square(strongSide)); + Square bksq = normalize(pos, strongSide, pos.square(weakSide)); + Square psq = normalize(pos, strongSide, pos.square(strongSide)); Color us = strongSide == pos.side_to_move() ? WHITE : BLACK; @@ -237,10 +231,10 @@ Value Endgame::operator()(const Position& pos) const { assert(verify_material(pos, strongSide, RookValueMg, 0)); assert(verify_material(pos, weakSide, VALUE_ZERO, 1)); - Square wksq = relative_square(strongSide, pos.king_square(strongSide)); - Square bksq = relative_square(strongSide, pos.king_square(weakSide)); - Square rsq = relative_square(strongSide, pos.list(strongSide)[0]); - Square psq = relative_square(strongSide, pos.list(weakSide)[0]); + Square wksq = relative_square(strongSide, pos.square(strongSide)); + Square bksq = relative_square(strongSide, pos.square(weakSide)); + Square rsq = relative_square(strongSide, pos.square(strongSide)); + Square psq = relative_square(strongSide, pos.square(weakSide)); Square queeningSq = make_square(file_of(psq), RANK_1); Value result; @@ -280,7 +274,7 @@ Value Endgame::operator()(const Position& pos) const { assert(verify_material(pos, strongSide, RookValueMg, 0)); assert(verify_material(pos, weakSide, BishopValueMg, 0)); - Value result = Value(PushToEdges[pos.king_square(weakSide)]); + Value result = Value(PushToEdges[pos.square(weakSide)]); return strongSide == pos.side_to_move() ? result : -result; } @@ -293,8 +287,8 @@ Value Endgame::operator()(const Position& pos) const { assert(verify_material(pos, strongSide, RookValueMg, 0)); assert(verify_material(pos, weakSide, KnightValueMg, 0)); - Square bksq = pos.king_square(weakSide); - Square bnsq = pos.list(weakSide)[0]; + Square bksq = pos.square(weakSide); + Square bnsq = pos.square(weakSide); Value result = Value(PushToEdges[bksq] + PushAway[distance(bksq, bnsq)]); return strongSide == pos.side_to_move() ? result : -result; } @@ -310,9 +304,9 @@ Value Endgame::operator()(const Position& pos) const { assert(verify_material(pos, strongSide, QueenValueMg, 0)); assert(verify_material(pos, weakSide, VALUE_ZERO, 1)); - Square winnerKSq = pos.king_square(strongSide); - Square loserKSq = pos.king_square(weakSide); - Square pawnSq = pos.list(weakSide)[0]; + Square winnerKSq = pos.square(strongSide); + Square loserKSq = pos.square(weakSide); + Square pawnSq = pos.square(weakSide); Value result = Value(PushClose[distance(winnerKSq, loserKSq)]); @@ -335,8 +329,8 @@ Value Endgame::operator()(const Position& pos) const { assert(verify_material(pos, strongSide, QueenValueMg, 0)); assert(verify_material(pos, weakSide, RookValueMg, 0)); - Square winnerKSq = pos.king_square(strongSide); - Square loserKSq = pos.king_square(weakSide); + Square winnerKSq = pos.square(strongSide); + Square loserKSq = pos.square(weakSide); Value result = QueenValueEg - RookValueEg @@ -365,15 +359,15 @@ ScaleFactor Endgame::operator()(const Position& pos) const { // be detected even when the weaker side has some pawns. Bitboard pawns = pos.pieces(strongSide, PAWN); - File pawnFile = file_of(pos.list(strongSide)[0]); + File pawnsFile = file_of(lsb(pawns)); - // All pawns are on a single rook file ? - if ( (pawnFile == FILE_A || pawnFile == FILE_H) - && !(pawns & ~file_bb(pawnFile))) + // All pawns are on a single rook file? + if ( (pawnsFile == FILE_A || pawnsFile == FILE_H) + && !(pawns & ~file_bb(pawnsFile))) { - Square bishopSq = pos.list(strongSide)[0]; - Square queeningSq = relative_square(strongSide, make_square(pawnFile, RANK_8)); - Square kingSq = pos.king_square(weakSide); + Square bishopSq = pos.square(strongSide); + Square queeningSq = relative_square(strongSide, make_square(pawnsFile, RANK_8)); + Square kingSq = pos.square(weakSide); if ( opposite_colors(queeningSq, bishopSq) && distance(queeningSq, kingSq) <= 1) @@ -381,17 +375,17 @@ ScaleFactor Endgame::operator()(const Position& pos) const { } // If all the pawns are on the same B or G file, then it's potentially a draw - if ( (pawnFile == FILE_B || pawnFile == FILE_G) - && !(pos.pieces(PAWN) & ~file_bb(pawnFile)) + if ( (pawnsFile == FILE_B || pawnsFile == FILE_G) + && !(pos.pieces(PAWN) & ~file_bb(pawnsFile)) && pos.non_pawn_material(weakSide) == 0 && pos.count(weakSide) >= 1) { // Get weakSide pawn that is closest to the home rank Square weakPawnSq = backmost_sq(weakSide, pos.pieces(weakSide, PAWN)); - Square strongKingSq = pos.king_square(strongSide); - Square weakKingSq = pos.king_square(weakSide); - Square bishopSq = pos.list(strongSide)[0]; + Square strongKingSq = pos.square(strongSide); + Square weakKingSq = pos.square(weakSide); + Square bishopSq = pos.square(strongSide); // There's potential for a draw if our pawn is blocked on the 7th rank, // the bishop cannot attack it or they only have one pawn left @@ -428,11 +422,11 @@ ScaleFactor Endgame::operator()(const Position& pos) const { assert(pos.count(weakSide) == 1); assert(pos.count(weakSide) >= 1); - Square kingSq = pos.king_square(weakSide); - Square rsq = pos.list(weakSide)[0]; + Square kingSq = pos.square(weakSide); + Square rsq = pos.square(weakSide); if ( relative_rank(weakSide, kingSq) <= RANK_2 - && relative_rank(weakSide, pos.king_square(strongSide)) >= RANK_4 + && relative_rank(weakSide, pos.square(strongSide)) >= RANK_4 && relative_rank(weakSide, rsq) == RANK_3 && ( pos.pieces(weakSide, PAWN) & pos.attacks_from(kingSq) @@ -456,11 +450,11 @@ ScaleFactor Endgame::operator()(const Position& pos) const { assert(verify_material(pos, weakSide, RookValueMg, 0)); // Assume strongSide is white and the pawn is on files A-D - Square wksq = normalize(pos, strongSide, pos.king_square(strongSide)); - Square bksq = normalize(pos, strongSide, pos.king_square(weakSide)); - Square wrsq = normalize(pos, strongSide, pos.list(strongSide)[0]); - Square wpsq = normalize(pos, strongSide, pos.list(strongSide)[0]); - Square brsq = normalize(pos, strongSide, pos.list(weakSide)[0]); + Square wksq = normalize(pos, strongSide, pos.square(strongSide)); + Square bksq = normalize(pos, strongSide, pos.square(weakSide)); + Square wrsq = normalize(pos, strongSide, pos.square(strongSide)); + Square wpsq = normalize(pos, strongSide, pos.square(strongSide)); + Square brsq = normalize(pos, strongSide, pos.square(weakSide)); File f = file_of(wpsq); Rank r = rank_of(wpsq); @@ -480,7 +474,7 @@ ScaleFactor Endgame::operator()(const Position& pos) const { if ( r == RANK_6 && distance(bksq, queeningSq) <= 1 && rank_of(wksq) + tempo <= RANK_6 - && (rank_of(brsq) == RANK_1 || (!tempo && distance(file_of(brsq), f) >= 3))) + && (rank_of(brsq) == RANK_1 || (!tempo && distance(brsq, wpsq) >= 3))) return SCALE_FACTOR_DRAW; if ( r >= RANK_6 @@ -552,9 +546,9 @@ ScaleFactor Endgame::operator()(const Position& pos) const { // Test for a rook pawn if (pos.pieces(PAWN) & (FileABB | FileHBB)) { - Square ksq = pos.king_square(weakSide); - Square bsq = pos.list(weakSide)[0]; - Square psq = pos.list(strongSide)[0]; + Square ksq = pos.square(weakSide); + Square bsq = pos.square(weakSide); + Square psq = pos.square(strongSide); Rank rk = relative_rank(strongSide, psq); Square push = pawn_push(strongSide); @@ -567,7 +561,7 @@ ScaleFactor Endgame::operator()(const Position& pos) const { { int d = distance(psq + 3 * push, ksq); - if (d <= 2 && !(d == 0 && ksq == pos.king_square(strongSide) + 2 * push)) + if (d <= 2 && !(d == 0 && ksq == pos.square(strongSide) + 2 * push)) return ScaleFactor(24); else return ScaleFactor(48); @@ -595,9 +589,9 @@ ScaleFactor Endgame::operator()(const Position& pos) const { assert(verify_material(pos, strongSide, RookValueMg, 2)); assert(verify_material(pos, weakSide, RookValueMg, 1)); - Square wpsq1 = pos.list(strongSide)[0]; - Square wpsq2 = pos.list(strongSide)[1]; - Square bksq = pos.king_square(weakSide); + Square wpsq1 = pos.squares(strongSide)[0]; + Square wpsq2 = pos.squares(strongSide)[1]; + Square bksq = pos.square(weakSide); // Does the stronger side have a passed pawn? if (pos.pawn_passed(strongSide, wpsq1) || pos.pawn_passed(strongSide, wpsq2)) @@ -609,14 +603,8 @@ ScaleFactor Endgame::operator()(const Position& pos) const { && distance(bksq, wpsq2) <= 1 && relative_rank(strongSide, bksq) > r) { - switch (r) { - case RANK_2: return ScaleFactor(10); - case RANK_3: return ScaleFactor(10); - case RANK_4: return ScaleFactor(15); - case RANK_5: return ScaleFactor(20); - case RANK_6: return ScaleFactor(40); - default: assert(false); - } + assert(r > RANK_1 && r < RANK_7); + return ScaleFactor(KRPPKRPScaleFactors[r]); } return SCALE_FACTOR_NONE; } @@ -631,15 +619,14 @@ ScaleFactor Endgame::operator()(const Position& pos) const { assert(pos.count(strongSide) >= 2); assert(verify_material(pos, weakSide, VALUE_ZERO, 0)); - Square ksq = pos.king_square(weakSide); + Square ksq = pos.square(weakSide); Bitboard pawns = pos.pieces(strongSide, PAWN); - Square psq = pos.list(strongSide)[0]; // If all pawns are ahead of the king, on a single rook file and // the king is within one file of the pawns, it's a draw. if ( !(pawns & ~in_front_bb(weakSide, rank_of(ksq))) && !((pawns & ~FileABB) && (pawns & ~FileHBB)) - && distance(ksq, psq) <= 1) + && distance(ksq, lsb(pawns)) <= 1) return SCALE_FACTOR_DRAW; return SCALE_FACTOR_NONE; @@ -656,10 +643,10 @@ ScaleFactor Endgame::operator()(const Position& pos) const { assert(verify_material(pos, strongSide, BishopValueMg, 1)); assert(verify_material(pos, weakSide, BishopValueMg, 0)); - Square pawnSq = pos.list(strongSide)[0]; - Square strongBishopSq = pos.list(strongSide)[0]; - Square weakBishopSq = pos.list(weakSide)[0]; - Square weakKingSq = pos.king_square(weakSide); + Square pawnSq = pos.square(strongSide); + Square strongBishopSq = pos.square(strongSide); + Square weakBishopSq = pos.square(weakSide); + Square weakKingSq = pos.square(weakSide); // Case 1: Defending king blocks the pawn, and cannot be driven away if ( file_of(weakKingSq) == file_of(pawnSq) @@ -706,15 +693,15 @@ ScaleFactor Endgame::operator()(const Position& pos) const { assert(verify_material(pos, strongSide, BishopValueMg, 2)); assert(verify_material(pos, weakSide, BishopValueMg, 0)); - Square wbsq = pos.list(strongSide)[0]; - Square bbsq = pos.list(weakSide)[0]; + Square wbsq = pos.square(strongSide); + Square bbsq = pos.square(weakSide); if (!opposite_colors(wbsq, bbsq)) return SCALE_FACTOR_NONE; - Square ksq = pos.king_square(weakSide); - Square psq1 = pos.list(strongSide)[0]; - Square psq2 = pos.list(strongSide)[1]; + Square ksq = pos.square(weakSide); + Square psq1 = pos.squares(strongSide)[0]; + Square psq2 = pos.squares(strongSide)[1]; Rank r1 = rank_of(psq1); Rank r2 = rank_of(psq2); Square blockSq1, blockSq2; @@ -777,9 +764,9 @@ ScaleFactor Endgame::operator()(const Position& pos) const { assert(verify_material(pos, strongSide, BishopValueMg, 1)); assert(verify_material(pos, weakSide, KnightValueMg, 0)); - Square pawnSq = pos.list(strongSide)[0]; - Square strongBishopSq = pos.list(strongSide)[0]; - Square weakKingSq = pos.king_square(weakSide); + Square pawnSq = pos.square(strongSide); + Square strongBishopSq = pos.square(strongSide); + Square weakKingSq = pos.square(weakSide); if ( file_of(weakKingSq) == file_of(pawnSq) && relative_rank(strongSide, pawnSq) < relative_rank(strongSide, weakKingSq) @@ -800,8 +787,8 @@ ScaleFactor Endgame::operator()(const Position& pos) const { assert(verify_material(pos, weakSide, VALUE_ZERO, 0)); // Assume strongSide is white and the pawn is on files A-D - Square pawnSq = normalize(pos, strongSide, pos.list(strongSide)[0]); - Square weakKingSq = normalize(pos, strongSide, pos.king_square(weakSide)); + Square pawnSq = normalize(pos, strongSide, pos.square(strongSide)); + Square weakKingSq = normalize(pos, strongSide, pos.square(weakSide)); if (pawnSq == SQ_A7 && distance(SQ_A8, weakKingSq) <= 1) return SCALE_FACTOR_DRAW; @@ -815,9 +802,9 @@ ScaleFactor Endgame::operator()(const Position& pos) const { template<> ScaleFactor Endgame::operator()(const Position& pos) const { - Square pawnSq = pos.list(strongSide)[0]; - Square bishopSq = pos.list(weakSide)[0]; - Square weakKingSq = pos.king_square(weakSide); + Square pawnSq = pos.square(strongSide); + Square bishopSq = pos.square(weakSide); + Square weakKingSq = pos.square(weakSide); // King needs to get close to promoting pawn to prevent knight from blocking. // Rules for this are very tricky, so just approximate. @@ -840,9 +827,9 @@ ScaleFactor Endgame::operator()(const Position& pos) const { assert(verify_material(pos, weakSide, VALUE_ZERO, 1)); // Assume strongSide is white and the pawn is on files A-D - Square wksq = normalize(pos, strongSide, pos.king_square(strongSide)); - Square bksq = normalize(pos, strongSide, pos.king_square(weakSide)); - Square psq = normalize(pos, strongSide, pos.list(strongSide)[0]); + Square wksq = normalize(pos, strongSide, pos.square(strongSide)); + Square bksq = normalize(pos, strongSide, pos.square(weakSide)); + Square psq = normalize(pos, strongSide, pos.square(strongSide)); Color us = strongSide == pos.side_to_move() ? WHITE : BLACK;