X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fendgame.cpp;h=2c87b2a128a4ec7108246c1f043156148fdee05b;hp=869a36d76ceb5d0358765e7dd89ef639f240f6f6;hb=950c8436edc50857b83eb3e0cbaca06407764655;hpb=a646f74e6a62af756b2e51756a81ee983db4ff34 diff --git a/src/endgame.cpp b/src/endgame.cpp index 869a36d7..2c87b2a1 100644 --- a/src/endgame.cpp +++ b/src/endgame.cpp @@ -1,7 +1,7 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Copyright (C) 2004-2008 Tord Romstad (Glaurung author) - Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad + Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -60,8 +60,8 @@ namespace { const int PushAway [8] = { 0, 5, 20, 40, 60, 80, 90, 100 }; #ifndef NDEBUG - bool verify_material(const Position& pos, Color c, Value npm, int num_pawns) { - return pos.non_pawn_material(c) == npm && pos.count(c) == num_pawns; + bool verify_material(const Position& pos, Color c, Value npm, int pawnsCnt) { + return pos.non_pawn_material(c) == npm && pos.count(c) == pawnsCnt; } #endif @@ -82,8 +82,7 @@ namespace { // Get the material key of Position out of the given endgame key code // like "KBPKN". The trick here is to first forge an ad-hoc FEN string - // and then let a Position object do the work for us. Note that the - // FEN string could correspond to an illegal position. + // and then let a Position object do the work for us. Key key(const string& code, Color c) { assert(code.length() > 0 && code.length() < 8); @@ -94,8 +93,8 @@ namespace { std::transform(sides[c].begin(), sides[c].end(), sides[c].begin(), tolower); - string fen = sides[0] + char('0' + int(8 - code.length())) - + sides[1] + "/8/8/8/8/8/8/8 w - - 0 10"; + 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(); } @@ -118,7 +117,6 @@ Endgames::Endgames() { add("KRKN"); add("KQKP"); add("KQKR"); - add("KBBKN"); add("KNPK"); add("KNPKB"); @@ -164,11 +162,13 @@ Value Endgame::operator()(const Position& pos) const { Value result = pos.non_pawn_material(strongSide) + pos.count(strongSide) * PawnValueEg + PushToEdges[loserKSq] - + PushClose[square_distance(winnerKSq, loserKSq)]; + + PushClose[distance(winnerKSq, loserKSq)]; if ( pos.count(strongSide) || pos.count(strongSide) - || pos.bishop_pair(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; return strongSide == pos.side_to_move() ? result : -result; @@ -197,7 +197,7 @@ Value Endgame::operator()(const Position& pos) const { } Value result = VALUE_KNOWN_WIN - + PushClose[square_distance(winnerKSq, loserKSq)] + + PushClose[distance(winnerKSq, loserKSq)] + PushToCorners[loserKSq]; return strongSide == pos.side_to_move() ? result : -result; @@ -218,7 +218,7 @@ Value Endgame::operator()(const Position& pos) const { Color us = strongSide == pos.side_to_move() ? WHITE : BLACK; - if (!Bitbases::probe_kpk(wksq, psq, bksq, us)) + if (!Bitbases::probe(wksq, psq, bksq, us)) return VALUE_DRAW; Value result = VALUE_KNOWN_WIN + PawnValueEg + Value(rank_of(psq)); @@ -242,32 +242,31 @@ Value Endgame::operator()(const Position& pos) const { Square rsq = relative_square(strongSide, pos.list(strongSide)[0]); Square psq = relative_square(strongSide, pos.list(weakSide)[0]); - Square queeningSq = file_of(psq) | RANK_1; + Square queeningSq = make_square(file_of(psq), RANK_1); Value result; // If the stronger side's king is in front of the pawn, it's a win if (wksq < psq && file_of(wksq) == file_of(psq)) - result = RookValueEg - Value(square_distance(wksq, psq)); + result = RookValueEg - distance(wksq, psq); // If the weaker side's king is too far from the pawn and the rook, // it's a win. - else if ( square_distance(bksq, psq) >= 3 + (pos.side_to_move() == weakSide) - && square_distance(bksq, rsq) >= 3) - result = RookValueEg - Value(square_distance(wksq, psq)); + else if ( distance(bksq, psq) >= 3 + (pos.side_to_move() == weakSide) + && distance(bksq, rsq) >= 3) + result = RookValueEg - distance(wksq, psq); // If the pawn is far advanced and supported by the defending king, // the position is drawish else if ( rank_of(bksq) <= RANK_3 - && square_distance(bksq, psq) == 1 + && distance(bksq, psq) == 1 && rank_of(wksq) >= RANK_4 - && square_distance(wksq, psq) > 2 + (pos.side_to_move() == strongSide)) - result = Value(80 - square_distance(wksq, psq) * 8); + && distance(wksq, psq) > 2 + (pos.side_to_move() == strongSide)) + result = Value(80) - 8 * distance(wksq, psq); else - result = Value(200) - - Value(square_distance(wksq, psq + DELTA_S) * 8) - + Value(square_distance(bksq, psq + DELTA_S) * 8) - + Value(square_distance(psq, queeningSq) * 8); + result = Value(200) - 8 * ( distance(wksq, psq + DELTA_S) + - distance(bksq, psq + DELTA_S) + - distance(psq, queeningSq)); return strongSide == pos.side_to_move() ? result : -result; } @@ -296,7 +295,7 @@ Value Endgame::operator()(const Position& pos) const { Square bksq = pos.king_square(weakSide); Square bnsq = pos.list(weakSide)[0]; - Value result = Value(PushToEdges[bksq] + PushAway[square_distance(bksq, bnsq)]); + Value result = Value(PushToEdges[bksq] + PushAway[distance(bksq, bnsq)]); return strongSide == pos.side_to_move() ? result : -result; } @@ -315,10 +314,10 @@ Value Endgame::operator()(const Position& pos) const { Square loserKSq = pos.king_square(weakSide); Square pawnSq = pos.list(weakSide)[0]; - Value result = Value(PushClose[square_distance(winnerKSq, loserKSq)]); + Value result = Value(PushClose[distance(winnerKSq, loserKSq)]); if ( relative_rank(weakSide, pawnSq) != RANK_7 - || square_distance(loserKSq, pawnSq) != 1 + || distance(loserKSq, pawnSq) != 1 || !((FileABB | FileCBB | FileFBB | FileHBB) & pawnSq)) result += QueenValueEg - PawnValueEg; @@ -342,30 +341,7 @@ Value Endgame::operator()(const Position& pos) const { Value result = QueenValueEg - RookValueEg + PushToEdges[loserKSq] - + PushClose[square_distance(winnerKSq, loserKSq)]; - - return strongSide == pos.side_to_move() ? result : -result; -} - - -/// KBB vs KN. This is almost always a win. We try to push the enemy king to a corner -/// and away from his knight. For a reference of this difficult endgame see: -/// en.wikipedia.org/wiki/Chess_endgame#Effect_of_tablebases_on_endgame_theory - -template<> -Value Endgame::operator()(const Position& pos) const { - - assert(verify_material(pos, strongSide, 2 * BishopValueMg, 0)); - assert(verify_material(pos, weakSide, KnightValueMg, 0)); - - Square winnerKSq = pos.king_square(strongSide); - Square loserKSq = pos.king_square(weakSide); - Square knightSq = pos.list(weakSide)[0]; - - Value result = VALUE_KNOWN_WIN - + PushToCorners[loserKSq] - + PushClose[square_distance(winnerKSq, loserKSq)] - + PushAway[square_distance(loserKSq, knightSq)]; + + PushClose[distance(winnerKSq, loserKSq)]; return strongSide == pos.side_to_move() ? result : -result; } @@ -373,7 +349,6 @@ Value Endgame::operator()(const Position& pos) const { /// Some cases of trivial draws template<> Value Endgame::operator()(const Position&) const { return VALUE_DRAW; } -template<> Value Endgame::operator()(const Position&) const { return VALUE_DRAW; } /// KB and one or more pawns vs K. It checks for draws with rook pawns and @@ -397,11 +372,11 @@ ScaleFactor Endgame::operator()(const Position& pos) const { && !(pawns & ~file_bb(pawnFile))) { Square bishopSq = pos.list(strongSide)[0]; - Square queeningSq = relative_square(strongSide, pawnFile | RANK_8); + Square queeningSq = relative_square(strongSide, make_square(pawnFile, RANK_8)); Square kingSq = pos.king_square(weakSide); if ( opposite_colors(queeningSq, bishopSq) - && square_distance(queeningSq, kingSq) <= 1) + && distance(queeningSq, kingSq) <= 1) return SCALE_FACTOR_DRAW; } @@ -424,8 +399,8 @@ ScaleFactor Endgame::operator()(const Position& pos) const { && (pos.pieces(strongSide, PAWN) & (weakPawnSq + pawn_push(weakSide))) && (opposite_colors(bishopSq, weakPawnSq) || pos.count(strongSide) == 1)) { - int strongKingDist = square_distance(weakPawnSq, strongKingSq); - int weakKingDist = square_distance(weakPawnSq, weakKingSq); + int strongKingDist = distance(weakPawnSq, strongKingSq); + int weakKingDist = distance(weakPawnSq, weakKingSq); // It's a draw if the weak king is on its back two ranks, within 2 // squares of the blocking pawn and the strong king is not @@ -489,13 +464,13 @@ ScaleFactor Endgame::operator()(const Position& pos) const { File f = file_of(wpsq); Rank r = rank_of(wpsq); - Square queeningSq = f | RANK_8; + Square queeningSq = make_square(f, RANK_8); int tempo = (pos.side_to_move() == strongSide); // If the pawn is not too far advanced and the defending king defends the // queening square, use the third-rank defence. if ( r <= RANK_5 - && square_distance(bksq, queeningSq) <= 1 + && distance(bksq, queeningSq) <= 1 && wksq <= SQ_H5 && (rank_of(brsq) == RANK_6 || (r <= RANK_3 && rank_of(wrsq) != RANK_6))) return SCALE_FACTOR_DRAW; @@ -503,15 +478,15 @@ ScaleFactor Endgame::operator()(const Position& pos) const { // The defending side saves a draw by checking from behind in case the pawn // has advanced to the 6th rank with the king behind. if ( r == RANK_6 - && square_distance(bksq, queeningSq) <= 1 + && distance(bksq, queeningSq) <= 1 && rank_of(wksq) + tempo <= RANK_6 - && (rank_of(brsq) == RANK_1 || (!tempo && abs(file_of(brsq) - f) >= 3))) + && (rank_of(brsq) == RANK_1 || (!tempo && distance(file_of(brsq), f) >= 3))) return SCALE_FACTOR_DRAW; if ( r >= RANK_6 && bksq == queeningSq && rank_of(brsq) == RANK_1 - && (!tempo || square_distance(wksq, wpsq) >= 2)) + && (!tempo || distance(wksq, wpsq) >= 2)) return SCALE_FACTOR_DRAW; // White pawn on a7 and rook on a8 is a draw if black's king is on g7 or h7 @@ -527,8 +502,8 @@ ScaleFactor Endgame::operator()(const Position& pos) const { // away, it's a draw. if ( r <= RANK_5 && bksq == wpsq + DELTA_N - && square_distance(wksq, wpsq) - tempo >= 2 - && square_distance(wksq, brsq) - tempo >= 2) + && distance(wksq, wpsq) - tempo >= 2 + && distance(wksq, brsq) - tempo >= 2) return SCALE_FACTOR_DRAW; // Pawn on the 7th rank supported by the rook from behind usually wins if the @@ -538,22 +513,22 @@ ScaleFactor Endgame::operator()(const Position& pos) const { && f != FILE_A && file_of(wrsq) == f && wrsq != queeningSq - && (square_distance(wksq, queeningSq) < square_distance(bksq, queeningSq) - 2 + tempo) - && (square_distance(wksq, queeningSq) < square_distance(bksq, wrsq) + tempo)) - return ScaleFactor(SCALE_FACTOR_MAX - 2 * square_distance(wksq, queeningSq)); + && (distance(wksq, queeningSq) < distance(bksq, queeningSq) - 2 + tempo) + && (distance(wksq, queeningSq) < distance(bksq, wrsq) + tempo)) + return ScaleFactor(SCALE_FACTOR_MAX - 2 * distance(wksq, queeningSq)); // Similar to the above, but with the pawn further back if ( f != FILE_A && file_of(wrsq) == f && wrsq < wpsq - && (square_distance(wksq, queeningSq) < square_distance(bksq, queeningSq) - 2 + tempo) - && (square_distance(wksq, wpsq + DELTA_N) < square_distance(bksq, wpsq + DELTA_N) - 2 + tempo) - && ( square_distance(bksq, wrsq) + tempo >= 3 - || ( square_distance(wksq, queeningSq) < square_distance(bksq, wrsq) + tempo - && (square_distance(wksq, wpsq + DELTA_N) < square_distance(bksq, wrsq) + tempo)))) + && (distance(wksq, queeningSq) < distance(bksq, queeningSq) - 2 + tempo) + && (distance(wksq, wpsq + DELTA_N) < distance(bksq, wpsq + DELTA_N) - 2 + tempo) + && ( distance(bksq, wrsq) + tempo >= 3 + || ( distance(wksq, queeningSq) < distance(bksq, wrsq) + tempo + && (distance(wksq, wpsq + DELTA_N) < distance(bksq, wrsq) + tempo)))) return ScaleFactor( SCALE_FACTOR_MAX - - 8 * square_distance(wpsq, queeningSq) - - 2 * square_distance(wksq, queeningSq)); + - 8 * distance(wpsq, queeningSq) + - 2 * distance(wksq, queeningSq)); // If the pawn is not far advanced and the defending king is somewhere in // the pawn's path, it's probably a draw. @@ -561,9 +536,9 @@ ScaleFactor Endgame::operator()(const Position& pos) const { { if (file_of(bksq) == file_of(wpsq)) return ScaleFactor(10); - if ( abs(file_of(bksq) - file_of(wpsq)) == 1 - && square_distance(wksq, bksq) > 2) - return ScaleFactor(24 - 2 * square_distance(wksq, bksq)); + if ( distance(bksq, wpsq) == 1 + && distance(wksq, bksq) > 2) + return ScaleFactor(24 - 2 * distance(wksq, bksq)); } return SCALE_FACTOR_NONE; } @@ -590,7 +565,7 @@ ScaleFactor Endgame::operator()(const Position& pos) const { // corner but not trapped there. if (rk == RANK_5 && !opposite_colors(bsq, psq)) { - int d = square_distance(psq + 3 * push, ksq); + int d = distance(psq + 3 * push, ksq); if (d <= 2 && !(d == 0 && ksq == pos.king_square(strongSide) + 2 * push)) return ScaleFactor(24); @@ -603,9 +578,9 @@ ScaleFactor Endgame::operator()(const Position& pos) const { // pawn from a reasonable distance and the defending king is near // the corner if ( rk == RANK_6 - && square_distance(psq + 2 * push, ksq) <= 1 + && distance(psq + 2 * push, ksq) <= 1 && (PseudoAttacks[BISHOP][bsq] & (psq + push)) - && file_distance(bsq, psq) >= 2) + && distance(bsq, psq) >= 2) return ScaleFactor(8); } @@ -630,8 +605,8 @@ ScaleFactor Endgame::operator()(const Position& pos) const { Rank r = std::max(relative_rank(strongSide, wpsq1), relative_rank(strongSide, wpsq2)); - if ( file_distance(bksq, wpsq1) <= 1 - && file_distance(bksq, wpsq2) <= 1 + if ( distance(bksq, wpsq1) <= 1 + && distance(bksq, wpsq2) <= 1 && relative_rank(strongSide, bksq) > r) { switch (r) { @@ -664,7 +639,7 @@ ScaleFactor Endgame::operator()(const Position& pos) const { // 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)) - && file_distance(ksq, psq) <= 1) + && distance(ksq, psq) <= 1) return SCALE_FACTOR_DRAW; return SCALE_FACTOR_NONE; @@ -716,7 +691,7 @@ ScaleFactor Endgame::operator()(const Position& pos) const { return SCALE_FACTOR_DRAW; if ( (pos.attacks_from(weakBishopSq) & path) - && square_distance(weakBishopSq, pawnSq) >= 3) + && distance(weakBishopSq, pawnSq) >= 3) return SCALE_FACTOR_DRAW; } } @@ -747,15 +722,15 @@ ScaleFactor Endgame::operator()(const Position& pos) const { if (relative_rank(strongSide, psq1) > relative_rank(strongSide, psq2)) { blockSq1 = psq1 + pawn_push(strongSide); - blockSq2 = file_of(psq2) | rank_of(psq1); + blockSq2 = make_square(file_of(psq2), rank_of(psq1)); } else { blockSq1 = psq2 + pawn_push(strongSide); - blockSq2 = file_of(psq1) | rank_of(psq2); + blockSq2 = make_square(file_of(psq1), rank_of(psq2)); } - switch (file_distance(psq1, psq2)) + switch (distance(psq1, psq2)) { case 0: // Both pawns are on the same file. It's an easy draw if the defender firmly @@ -775,7 +750,7 @@ ScaleFactor Endgame::operator()(const Position& pos) const { && opposite_colors(ksq, wbsq) && ( bbsq == blockSq2 || (pos.attacks_from(blockSq2) & pos.pieces(weakSide, BISHOP)) - || abs(r1 - r2) >= 2)) + || distance(r1, r2) >= 2)) return SCALE_FACTOR_DRAW; else if ( ksq == blockSq2 @@ -828,7 +803,7 @@ ScaleFactor Endgame::operator()(const Position& pos) const { Square pawnSq = normalize(pos, strongSide, pos.list(strongSide)[0]); Square weakKingSq = normalize(pos, strongSide, pos.king_square(weakSide)); - if (pawnSq == SQ_A7 && square_distance(SQ_A8, weakKingSq) <= 1) + if (pawnSq == SQ_A7 && distance(SQ_A8, weakKingSq) <= 1) return SCALE_FACTOR_DRAW; return SCALE_FACTOR_NONE; @@ -847,7 +822,7 @@ ScaleFactor Endgame::operator()(const Position& pos) const { // King needs to get close to promoting pawn to prevent knight from blocking. // Rules for this are very tricky, so just approximate. if (forward_bb(strongSide, pawnSq) & pos.attacks_from(bishopSq)) - return ScaleFactor(square_distance(weakKingSq, pawnSq)); + return ScaleFactor(distance(weakKingSq, pawnSq)); return SCALE_FACTOR_NONE; } @@ -878,5 +853,5 @@ ScaleFactor Endgame::operator()(const Position& pos) const { // Probe the KPK bitbase with the weakest side's pawn removed. If it's a draw, // it's probably at least a draw even with the pawn. - return Bitbases::probe_kpk(wksq, psq, bksq, us) ? SCALE_FACTOR_NONE : SCALE_FACTOR_DRAW; + return Bitbases::probe(wksq, psq, bksq, us) ? SCALE_FACTOR_NONE : SCALE_FACTOR_DRAW; }