X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fendgame.cpp;h=b78d1ba909f64f19845cc29f7b4d93ea2a64be7a;hp=52786cdbe3b58b6166192802f35ab2f3eef674a8;hb=45b0aea875860e9f0fe2d0435ee6163906639194;hpb=52f3e717fa93c8774f37c249b05aa857993ee8a2 diff --git a/src/endgame.cpp b/src/endgame.cpp index 52786cdb..b78d1ba9 100644 --- a/src/endgame.cpp +++ b/src/endgame.cpp @@ -29,9 +29,9 @@ using std::string; namespace { - // Table used to drive the defending king towards the edge of the board + // Table used to drive the king towards the edge of the board // in KX vs K and KQ vs KR endgames. - const int MateTable[SQUARE_NB] = { + const int PushToEdges[SQUARE_NB] = { 100, 90, 80, 70, 70, 80, 90, 100, 90, 70, 60, 50, 50, 60, 70, 90, 80, 60, 40, 30, 30, 40, 60, 80, @@ -42,9 +42,9 @@ namespace { 100, 90, 80, 70, 70, 80, 90, 100, }; - // Table used to drive the defending king towards a corner square of the + // Table used to drive the king towards a corner square of the // right color in KBN vs K endgames. - const int KBNKMateTable[SQUARE_NB] = { + const int PushToCorners[SQUARE_NB] = { 200, 190, 180, 170, 160, 150, 140, 130, 190, 180, 170, 160, 150, 140, 130, 140, 180, 170, 155, 140, 140, 125, 140, 150, @@ -55,9 +55,9 @@ namespace { 130, 140, 150, 160, 170, 180, 190, 200 }; - // The attacking side is given a descending bonus based on distance between - // the two kings in basic endgames. - const int DistanceBonus[8] = { 0, 0, 100, 80, 60, 40, 20, 10 }; + // Tables used to drive a piece towards or away from another piece + const int PushClose[8] = { 0, 0, 100, 80, 60, 40, 20, 10 }; + const int PushAway [8] = { 0, 5, 20, 40, 60, 80, 90, 100 }; // Get the material key of a Position out of the given endgame key code // like "KBPKN". The trick here is to first forge an ad-hoc fen string @@ -130,28 +130,25 @@ template<> Value Endgame::operator()(const Position& pos) const { assert(pos.non_pawn_material(weakerSide) == VALUE_ZERO); - assert(pos.piece_count(weakerSide, PAWN) == VALUE_ZERO); + assert(!pos.count(weakerSide)); + assert(!pos.checkers()); // Eval is never called when in check // Stalemate detection with lone king - if ( pos.side_to_move() == weakerSide - && !pos.checkers() - && !MoveList(pos).size()) { - return VALUE_DRAW; - } + if (pos.side_to_move() == weakerSide && !MoveList(pos).size()) + return VALUE_DRAW; Square winnerKSq = pos.king_square(strongerSide); Square loserKSq = pos.king_square(weakerSide); Value result = pos.non_pawn_material(strongerSide) - + pos.piece_count(strongerSide, PAWN) * PawnValueEg - + MateTable[loserKSq] - + DistanceBonus[square_distance(winnerKSq, loserKSq)]; - - if ( pos.piece_count(strongerSide, QUEEN) - || pos.piece_count(strongerSide, ROOK) - || pos.bishop_pair(strongerSide)) { - result += VALUE_KNOWN_WIN; - } + + pos.count(strongerSide) * PawnValueEg + + PushToEdges[loserKSq] + + PushClose[square_distance(winnerKSq, loserKSq)]; + + if ( pos.count(strongerSide) + || pos.count(strongerSide) + || pos.bishop_pair(strongerSide)) + result += VALUE_KNOWN_WIN; return strongerSide == pos.side_to_move() ? result : -result; } @@ -162,16 +159,16 @@ Value Endgame::operator()(const Position& pos) const { template<> Value Endgame::operator()(const Position& pos) const { - assert(pos.non_pawn_material(weakerSide) == VALUE_ZERO); - assert(pos.piece_count(weakerSide, PAWN) == VALUE_ZERO); assert(pos.non_pawn_material(strongerSide) == KnightValueMg + BishopValueMg); - assert(pos.piece_count(strongerSide, BISHOP) == 1); - assert(pos.piece_count(strongerSide, KNIGHT) == 1); - assert(pos.piece_count(strongerSide, PAWN) == 0); + assert(pos.non_pawn_material(weakerSide) == VALUE_ZERO); + assert(pos.count(strongerSide) == 1); + assert(pos.count(strongerSide) == 1); + assert(pos.count< PAWN>(strongerSide) == 0); + assert(pos.count< PAWN>(weakerSide ) == 0); Square winnerKSq = pos.king_square(strongerSide); Square loserKSq = pos.king_square(weakerSide); - Square bishopSq = pos.piece_list(strongerSide, BISHOP)[0]; + Square bishopSq = pos.list(strongerSide)[0]; // kbnk_mate_table() tries to drive toward corners A1 or H8, // if we have a bishop that cannot reach the above squares we @@ -183,8 +180,8 @@ Value Endgame::operator()(const Position& pos) const { } Value result = VALUE_KNOWN_WIN - + DistanceBonus[square_distance(winnerKSq, loserKSq)] - + KBNKMateTable[loserKSq]; + + PushClose[square_distance(winnerKSq, loserKSq)] + + PushToCorners[loserKSq]; return strongerSide == pos.side_to_move() ? result : -result; } @@ -196,38 +193,33 @@ Value Endgame::operator()(const Position& pos) const { assert(pos.non_pawn_material(strongerSide) == VALUE_ZERO); assert(pos.non_pawn_material(weakerSide) == VALUE_ZERO); - assert(pos.piece_count(strongerSide, PAWN) == 1); - assert(pos.piece_count(weakerSide, PAWN) == 0); + assert(pos.count(strongerSide) == 1); + assert(pos.count(weakerSide ) == 0); - Square wksq, bksq, wpsq; - Color us; + Square wksq = pos.king_square(strongerSide); + Square bksq = pos.king_square(weakerSide); + Square psq = pos.list(strongerSide)[0]; + Color us = pos.side_to_move(); - if (strongerSide == WHITE) - { - wksq = pos.king_square(WHITE); - bksq = pos.king_square(BLACK); - wpsq = pos.piece_list(WHITE, PAWN)[0]; - us = pos.side_to_move(); - } - else + if (strongerSide == BLACK) { - wksq = ~pos.king_square(BLACK); - bksq = ~pos.king_square(WHITE); - wpsq = ~pos.piece_list(BLACK, PAWN)[0]; - us = ~pos.side_to_move(); + wksq = ~wksq; + bksq = ~bksq; + psq = ~psq; + us = ~us; } - if (file_of(wpsq) >= FILE_E) + if (file_of(psq) >= FILE_E) { wksq = mirror(wksq); bksq = mirror(bksq); - wpsq = mirror(wpsq); + psq = mirror(psq); } - if (!Bitbases::probe_kpk(wksq, wpsq, bksq, us)) + if (!Bitbases::probe_kpk(wksq, psq, bksq, us)) return VALUE_DRAW; - Value result = VALUE_KNOWN_WIN + PawnValueEg + Value(rank_of(wpsq)); + Value result = VALUE_KNOWN_WIN + PawnValueEg + Value(rank_of(psq)); return strongerSide == pos.side_to_move() ? result : -result; } @@ -241,52 +233,49 @@ template<> Value Endgame::operator()(const Position& pos) const { assert(pos.non_pawn_material(strongerSide) == RookValueMg); - assert(pos.piece_count(strongerSide, PAWN) == 0); assert(pos.non_pawn_material(weakerSide) == 0); - assert(pos.piece_count(weakerSide, PAWN) == 1); + assert(pos.count(strongerSide) == 0); + assert(pos.count(weakerSide ) == 1); - Square wksq, wrsq, bksq, bpsq; - int tempo = (pos.side_to_move() == strongerSide); - - wksq = pos.king_square(strongerSide); - wrsq = pos.piece_list(strongerSide, ROOK)[0]; - bksq = pos.king_square(weakerSide); - bpsq = pos.piece_list(weakerSide, PAWN)[0]; + Square wksq = pos.king_square(strongerSide); + Square bksq = pos.king_square(weakerSide); + Square rsq = pos.list(strongerSide)[0]; + Square psq = pos.list(weakerSide)[0]; if (strongerSide == BLACK) { wksq = ~wksq; - wrsq = ~wrsq; bksq = ~bksq; - bpsq = ~bpsq; + rsq = ~rsq; + psq = ~psq; } - Square queeningSq = file_of(bpsq) | RANK_1; + Square queeningSq = 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 < bpsq && file_of(wksq) == file_of(bpsq)) - result = RookValueEg - Value(square_distance(wksq, bpsq)); + if (wksq < psq && file_of(wksq) == file_of(psq)) + result = RookValueEg - Value(square_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, bpsq) - (tempo ^ 1) >= 3 - && square_distance(bksq, wrsq) >= 3) - result = RookValueEg - Value(square_distance(wksq, bpsq)); + // it's a win. + else if ( square_distance(bksq, psq) >= 3 + (pos.side_to_move() == weakerSide) + && square_distance(bksq, rsq) >= 3) + result = RookValueEg - Value(square_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, bpsq) == 1 + && square_distance(bksq, psq) == 1 && rank_of(wksq) >= RANK_4 - && square_distance(wksq, bpsq) - tempo > 2) - result = Value(80 - square_distance(wksq, bpsq) * 8); + && square_distance(wksq, psq) > 2 + (pos.side_to_move() == strongerSide)) + result = Value(80 - square_distance(wksq, psq) * 8); else result = Value(200) - - Value(square_distance(wksq, bpsq + DELTA_S) * 8) - + Value(square_distance(bksq, bpsq + DELTA_S) * 8) - + Value(square_distance(bpsq, queeningSq) * 8); + - Value(square_distance(wksq, psq + DELTA_S) * 8) + + Value(square_distance(bksq, psq + DELTA_S) * 8) + + Value(square_distance(psq, queeningSq) * 8); return strongerSide == pos.side_to_move() ? result : -result; } @@ -298,12 +287,12 @@ template<> Value Endgame::operator()(const Position& pos) const { assert(pos.non_pawn_material(strongerSide) == RookValueMg); - assert(pos.piece_count(strongerSide, PAWN) == 0); - assert(pos.non_pawn_material(weakerSide) == BishopValueMg); - assert(pos.piece_count(weakerSide, PAWN) == 0); - assert(pos.piece_count(weakerSide, BISHOP) == 1); + assert(pos.non_pawn_material(weakerSide ) == BishopValueMg); + assert(pos.count(weakerSide ) == 1); + assert(pos.count< PAWN>(weakerSide ) == 0); + assert(pos.count< PAWN>(strongerSide) == 0); - Value result = Value(MateTable[pos.king_square(weakerSide)]); + Value result = Value(PushToEdges[pos.king_square(weakerSide)]); return strongerSide == pos.side_to_move() ? result : -result; } @@ -314,16 +303,14 @@ template<> Value Endgame::operator()(const Position& pos) const { assert(pos.non_pawn_material(strongerSide) == RookValueMg); - assert(pos.piece_count(strongerSide, PAWN) == 0); - assert(pos.non_pawn_material(weakerSide) == KnightValueMg); - assert(pos.piece_count(weakerSide, PAWN) == 0); - assert(pos.piece_count(weakerSide, KNIGHT) == 1); - - const int penalty[8] = { 0, 10, 14, 20, 30, 42, 58, 80 }; + assert(pos.non_pawn_material(weakerSide ) == KnightValueMg); + assert(pos.count(weakerSide ) == 1); + assert(pos.count< PAWN>(weakerSide ) == 0); + assert(pos.count< PAWN>(strongerSide) == 0); Square bksq = pos.king_square(weakerSide); - Square bnsq = pos.piece_list(weakerSide, KNIGHT)[0]; - Value result = Value(MateTable[bksq] + penalty[square_distance(bksq, bnsq)]); + Square bnsq = pos.list(weakerSide)[0]; + Value result = Value(PushToEdges[bksq] + PushAway[square_distance(bksq, bnsq)]); return strongerSide == pos.side_to_move() ? result : -result; } @@ -335,26 +322,21 @@ template<> Value Endgame::operator()(const Position& pos) const { assert(pos.non_pawn_material(strongerSide) == QueenValueMg); - assert(pos.piece_count(strongerSide, PAWN) == 0); - assert(pos.non_pawn_material(weakerSide) == 0); - assert(pos.piece_count(weakerSide, PAWN) == 1); + assert(pos.non_pawn_material(weakerSide ) == VALUE_ZERO); + assert(pos.count(strongerSide) == 0); + assert(pos.count(weakerSide ) == 1); Square winnerKSq = pos.king_square(strongerSide); Square loserKSq = pos.king_square(weakerSide); - Square pawnSq = pos.piece_list(weakerSide, PAWN)[0]; + Square pawnSq = pos.list(weakerSide)[0]; - Value result = QueenValueEg - - PawnValueEg - + DistanceBonus[square_distance(winnerKSq, loserKSq)]; + Value result = Value(PushClose[square_distance(winnerKSq, loserKSq)]); - if ( square_distance(loserKSq, pawnSq) == 1 - && relative_rank(weakerSide, pawnSq) == RANK_7) - { - File f = file_of(pawnSq); + if ( relative_rank(weakerSide, pawnSq) != RANK_7 + || square_distance(loserKSq, pawnSq) != 1 + || !((FileABB | FileCBB | FileFBB | FileHBB) & pawnSq)) + result += QueenValueEg - PawnValueEg; - if (f == FILE_A || f == FILE_C || f == FILE_F || f == FILE_H) - result = Value(DistanceBonus[square_distance(winnerKSq, loserKSq)]); - } return strongerSide == pos.side_to_move() ? result : -result; } @@ -368,59 +350,52 @@ template<> Value Endgame::operator()(const Position& pos) const { assert(pos.non_pawn_material(strongerSide) == QueenValueMg); - assert(pos.piece_count(strongerSide, PAWN) == 0); - assert(pos.non_pawn_material(weakerSide) == RookValueMg); - assert(pos.piece_count(weakerSide, PAWN) == 0); + assert(pos.non_pawn_material(weakerSide ) == RookValueMg); + assert(pos.count(strongerSide) == 0); + assert(pos.count(weakerSide ) == 0); Square winnerKSq = pos.king_square(strongerSide); Square loserKSq = pos.king_square(weakerSide); Value result = QueenValueEg - RookValueEg - + MateTable[loserKSq] - + DistanceBonus[square_distance(winnerKSq, loserKSq)]; + + PushToEdges[loserKSq] + + PushClose[square_distance(winnerKSq, loserKSq)]; return strongerSide == pos.side_to_move() ? result : -result; } + +/// KBB vs KN. This is almost always a win. We try to push 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(pos.piece_count(strongerSide, BISHOP) == 2); - assert(pos.non_pawn_material(strongerSide) == 2*BishopValueMg); - assert(pos.piece_count(weakerSide, KNIGHT) == 1); - assert(pos.non_pawn_material(weakerSide) == KnightValueMg); + assert(pos.non_pawn_material(strongerSide) == 2 * BishopValueMg); + assert(pos.non_pawn_material(weakerSide ) == KnightValueMg); + assert(pos.count(strongerSide) == 2); + assert(pos.count(weakerSide ) == 1); assert(!pos.pieces(PAWN)); - Value result = BishopValueEg; - Square wksq = pos.king_square(strongerSide); - Square bksq = pos.king_square(weakerSide); - Square nsq = pos.piece_list(weakerSide, KNIGHT)[0]; - - // Bonus for attacking king close to defending king - result += Value(DistanceBonus[square_distance(wksq, bksq)]); - - // Bonus for driving the defending king and knight apart - result += Value(square_distance(bksq, nsq) * 32); + Square winnerKSq = pos.king_square(strongerSide); + Square loserKSq = pos.king_square(weakerSide); + Square knightSq = pos.list(weakerSide)[0]; - // Bonus for restricting the knight's mobility - result += Value((8 - popcount(pos.attacks_from(nsq))) * 8); + Value result = VALUE_KNOWN_WIN + + PushToCorners[loserKSq] + + PushClose[square_distance(winnerKSq, loserKSq)] + + PushAway[square_distance(loserKSq, knightSq)]; return strongerSide == pos.side_to_move() ? result : -result; } -/// K and two minors vs K and one or two minors or K and two knights against -/// king alone are always draw. -template<> -Value Endgame::operator()(const Position&) const { - return VALUE_DRAW; -} +/// 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; } -template<> -Value Endgame::operator()(const Position&) const { - return VALUE_DRAW; -} /// K, bishop and one or more pawns vs K. It checks for draws with rook pawns and /// a bishop of the wrong color. If such a draw is detected, SCALE_FACTOR_DRAW @@ -430,20 +405,20 @@ template<> ScaleFactor Endgame::operator()(const Position& pos) const { assert(pos.non_pawn_material(strongerSide) == BishopValueMg); - assert(pos.piece_count(strongerSide, BISHOP) == 1); - assert(pos.piece_count(strongerSide, PAWN) >= 1); + assert(pos.count(strongerSide) == 1); + assert(pos.count< PAWN>(strongerSide) >= 1); // No assertions about the material of weakerSide, because we want draws to // be detected even when the weaker side has some pawns. Bitboard pawns = pos.pieces(strongerSide, PAWN); - File pawnFile = file_of(pos.piece_list(strongerSide, PAWN)[0]); + File pawnFile = file_of(pos.list(strongerSide)[0]); // All pawns are on a single rook file ? if ( (pawnFile == FILE_A || pawnFile == FILE_H) && !(pawns & ~file_bb(pawnFile))) { - Square bishopSq = pos.piece_list(strongerSide, BISHOP)[0]; + Square bishopSq = pos.list(strongerSide)[0]; Square queeningSq = relative_square(strongerSide, pawnFile | RANK_8); Square kingSq = pos.king_square(weakerSide); @@ -453,22 +428,12 @@ ScaleFactor Endgame::operator()(const Position& pos) const { // The bishop has the wrong color, and the defending king is on the // file of the pawn(s) or the adjacent file. Find the rank of the // frontmost pawn. - Rank rank; - if (strongerSide == WHITE) - { - for (rank = RANK_7; !(rank_bb(rank) & pawns); rank--) {} - assert(rank >= RANK_2 && rank <= RANK_7); - } - else - { - for (rank = RANK_2; !(rank_bb(rank) & pawns); rank++) {} - rank = Rank(rank ^ 7); // HACK to get the relative rank - assert(rank >= RANK_2 && rank <= RANK_7); - } + Square pawnSq = frontmost_sq(strongerSide, pawns); + // If the defending king has distance 1 to the promotion square or // is placed somewhere in front of the pawn, it's a draw. if ( square_distance(kingSq, queeningSq) <= 1 - || relative_rank(strongerSide, kingSq) >= rank) + || relative_rank(weakerSide, kingSq) <= relative_rank(weakerSide, pawnSq)) return SCALE_FACTOR_DRAW; } } @@ -477,15 +442,14 @@ ScaleFactor Endgame::operator()(const Position& pos) const { if ( (pawnFile == FILE_B || pawnFile == FILE_G) && !(pos.pieces(PAWN) & ~file_bb(pawnFile)) && pos.non_pawn_material(weakerSide) == 0 - && pos.piece_count(weakerSide, PAWN) >= 1) + && pos.count(weakerSide) >= 1) { - // Get weaker pawn closest to opponent's queening square - Bitboard wkPawns = pos.pieces(weakerSide, PAWN); - Square weakerPawnSq = strongerSide == WHITE ? msb(wkPawns) : lsb(wkPawns); + // Get weakerSide pawn that is closest to home rank + Square weakerPawnSq = backmost_sq(weakerSide, pos.pieces(weakerSide, PAWN)); Square strongerKingSq = pos.king_square(strongerSide); Square weakerKingSq = pos.king_square(weakerSide); - Square bishopSq = pos.piece_list(strongerSide, BISHOP)[0]; + Square bishopSq = pos.list(strongerSide)[0]; // Draw if weaker pawn is on rank 7, bishop can't attack the pawn, and // weaker king can stop opposing opponent's king from penetrating. @@ -505,22 +469,22 @@ template<> ScaleFactor Endgame::operator()(const Position& pos) const { assert(pos.non_pawn_material(strongerSide) == QueenValueMg); - assert(pos.piece_count(strongerSide, QUEEN) == 1); - assert(pos.piece_count(strongerSide, PAWN) == 0); - assert(pos.piece_count(weakerSide, ROOK) == 1); - assert(pos.piece_count(weakerSide, PAWN) >= 1); + assert(pos.count(strongerSide) == 1); + assert(pos.count< PAWN>(strongerSide) == 0); + assert(pos.count< ROOK>(weakerSide ) == 1); + assert(pos.count< PAWN>(weakerSide ) >= 1); Square kingSq = pos.king_square(weakerSide); - if ( relative_rank(weakerSide, kingSq) <= RANK_2 - && relative_rank(weakerSide, pos.king_square(strongerSide)) >= RANK_4 + Square rsq = pos.list(weakerSide)[0]; + + if ( relative_rank(weakerSide, kingSq) <= RANK_2 + && relative_rank(weakerSide, pos.king_square(strongerSide)) >= RANK_4 && (pos.pieces(weakerSide, ROOK) & rank_bb(relative_rank(weakerSide, RANK_3))) && (pos.pieces(weakerSide, PAWN) & rank_bb(relative_rank(weakerSide, RANK_2))) - && (pos.attacks_from(kingSq) & pos.pieces(weakerSide, PAWN))) - { - Square rsq = pos.piece_list(weakerSide, ROOK)[0]; - if (pos.attacks_from(rsq, strongerSide) & pos.pieces(weakerSide, PAWN)) + && (pos.attacks_from(kingSq) & pos.pieces(weakerSide, PAWN)) + && (pos.attacks_from(rsq, strongerSide) & pos.pieces(weakerSide, PAWN))) return SCALE_FACTOR_DRAW; - } + return SCALE_FACTOR_NONE; } @@ -535,15 +499,15 @@ template<> ScaleFactor Endgame::operator()(const Position& pos) const { assert(pos.non_pawn_material(strongerSide) == RookValueMg); - assert(pos.piece_count(strongerSide, PAWN) == 1); - assert(pos.non_pawn_material(weakerSide) == RookValueMg); - assert(pos.piece_count(weakerSide, PAWN) == 0); + assert(pos.non_pawn_material(weakerSide) == RookValueMg); + assert(pos.count(strongerSide) == 1); + assert(pos.count(weakerSide ) == 0); Square wksq = pos.king_square(strongerSide); - Square wrsq = pos.piece_list(strongerSide, ROOK)[0]; - Square wpsq = pos.piece_list(strongerSide, PAWN)[0]; Square bksq = pos.king_square(weakerSide); - Square brsq = pos.piece_list(weakerSide, ROOK)[0]; + Square wrsq = pos.list(strongerSide)[0]; + Square wpsq = pos.list(strongerSide)[0]; + Square brsq = pos.list(weakerSide)[0]; // Orient the board in such a way that the stronger side is white, and the // pawn is on the left half of the board. @@ -555,6 +519,7 @@ ScaleFactor Endgame::operator()(const Position& pos) const { bksq = ~bksq; brsq = ~brsq; } + if (file_of(wpsq) > FILE_D) { wksq = mirror(wksq); @@ -653,12 +618,12 @@ template<> ScaleFactor Endgame::operator()(const Position& pos) const { assert(pos.non_pawn_material(strongerSide) == RookValueMg); - assert(pos.piece_count(strongerSide, PAWN) == 2); - assert(pos.non_pawn_material(weakerSide) == RookValueMg); - assert(pos.piece_count(weakerSide, PAWN) == 1); + assert(pos.non_pawn_material(weakerSide) == RookValueMg); + assert(pos.count(strongerSide) == 2); + assert(pos.count(weakerSide ) == 1); - Square wpsq1 = pos.piece_list(strongerSide, PAWN)[0]; - Square wpsq2 = pos.piece_list(strongerSide, PAWN)[1]; + Square wpsq1 = pos.list(strongerSide)[0]; + Square wpsq2 = pos.list(strongerSide)[1]; Square bksq = pos.king_square(weakerSide); // Does the stronger side have a passed pawn? @@ -691,9 +656,9 @@ template<> ScaleFactor Endgame::operator()(const Position& pos) const { assert(pos.non_pawn_material(strongerSide) == VALUE_ZERO); - assert(pos.piece_count(strongerSide, PAWN) >= 2); - assert(pos.non_pawn_material(weakerSide) == VALUE_ZERO); - assert(pos.piece_count(weakerSide, PAWN) == 0); + assert(pos.non_pawn_material(weakerSide) == VALUE_ZERO); + assert(pos.count(strongerSide) >= 2); + assert(pos.count(weakerSide ) == 0); Square ksq = pos.king_square(weakerSide); Bitboard pawns = pos.pieces(strongerSide, PAWN); @@ -704,7 +669,7 @@ ScaleFactor Endgame::operator()(const Position& pos) const { // Does the defending king block the pawns? if ( square_distance(ksq, relative_square(strongerSide, SQ_A8)) <= 1 || ( file_of(ksq) == FILE_A - && !(in_front_bb(strongerSide, ksq) & pawns))) + && !(in_front_bb(strongerSide, rank_of(ksq)) & pawns))) return SCALE_FACTOR_DRAW; } // Are all pawns on the 'h' file? @@ -713,7 +678,7 @@ ScaleFactor Endgame::operator()(const Position& pos) const { // Does the defending king block the pawns? if ( square_distance(ksq, relative_square(strongerSide, SQ_H8)) <= 1 || ( file_of(ksq) == FILE_H - && !(in_front_bb(strongerSide, ksq) & pawns))) + && !(in_front_bb(strongerSide, rank_of(ksq)) & pawns))) return SCALE_FACTOR_DRAW; } return SCALE_FACTOR_NONE; @@ -728,15 +693,15 @@ template<> ScaleFactor Endgame::operator()(const Position& pos) const { assert(pos.non_pawn_material(strongerSide) == BishopValueMg); - assert(pos.piece_count(strongerSide, BISHOP) == 1); - assert(pos.piece_count(strongerSide, PAWN) == 1); - assert(pos.non_pawn_material(weakerSide) == BishopValueMg); - assert(pos.piece_count(weakerSide, BISHOP) == 1); - assert(pos.piece_count(weakerSide, PAWN) == 0); - - Square pawnSq = pos.piece_list(strongerSide, PAWN)[0]; - Square strongerBishopSq = pos.piece_list(strongerSide, BISHOP)[0]; - Square weakerBishopSq = pos.piece_list(weakerSide, BISHOP)[0]; + assert(pos.non_pawn_material(weakerSide ) == BishopValueMg); + assert(pos.count(strongerSide) == 1); + assert(pos.count(weakerSide ) == 1); + assert(pos.count< PAWN>(strongerSide) == 1); + assert(pos.count< PAWN>(weakerSide ) == 0); + + Square pawnSq = pos.list(strongerSide)[0]; + Square strongerBishopSq = pos.list(strongerSide)[0]; + Square weakerBishopSq = pos.list(weakerSide)[0]; Square weakerKingSq = pos.king_square(weakerSide); // Case 1: Defending king blocks the pawn, and cannot be driven away @@ -783,21 +748,21 @@ template<> ScaleFactor Endgame::operator()(const Position& pos) const { assert(pos.non_pawn_material(strongerSide) == BishopValueMg); - assert(pos.piece_count(strongerSide, BISHOP) == 1); - assert(pos.piece_count(strongerSide, PAWN) == 2); - assert(pos.non_pawn_material(weakerSide) == BishopValueMg); - assert(pos.piece_count(weakerSide, BISHOP) == 1); - assert(pos.piece_count(weakerSide, PAWN) == 0); + assert(pos.non_pawn_material(weakerSide ) == BishopValueMg); + assert(pos.count(strongerSide) == 1); + assert(pos.count(weakerSide ) == 1); + assert(pos.count< PAWN>(strongerSide) == 2); + assert(pos.count< PAWN>(weakerSide ) == 0); - Square wbsq = pos.piece_list(strongerSide, BISHOP)[0]; - Square bbsq = pos.piece_list(weakerSide, BISHOP)[0]; + Square wbsq = pos.list(strongerSide)[0]; + Square bbsq = pos.list(weakerSide)[0]; if (!opposite_colors(wbsq, bbsq)) return SCALE_FACTOR_NONE; Square ksq = pos.king_square(weakerSide); - Square psq1 = pos.piece_list(strongerSide, PAWN)[0]; - Square psq2 = pos.piece_list(strongerSide, PAWN)[1]; + Square psq1 = pos.list(strongerSide)[0]; + Square psq2 = pos.list(strongerSide)[1]; Rank r1 = rank_of(psq1); Rank r2 = rank_of(psq2); Square blockSq1, blockSq2; @@ -858,14 +823,14 @@ template<> ScaleFactor Endgame::operator()(const Position& pos) const { assert(pos.non_pawn_material(strongerSide) == BishopValueMg); - assert(pos.piece_count(strongerSide, BISHOP) == 1); - assert(pos.piece_count(strongerSide, PAWN) == 1); - assert(pos.non_pawn_material(weakerSide) == KnightValueMg); - assert(pos.piece_count(weakerSide, KNIGHT) == 1); - assert(pos.piece_count(weakerSide, PAWN) == 0); - - Square pawnSq = pos.piece_list(strongerSide, PAWN)[0]; - Square strongerBishopSq = pos.piece_list(strongerSide, BISHOP)[0]; + assert(pos.non_pawn_material(weakerSide ) == KnightValueMg); + assert(pos.count(strongerSide) == 1); + assert(pos.count(weakerSide ) == 1); + assert(pos.count< PAWN>(strongerSide) == 1); + assert(pos.count< PAWN>(weakerSide ) == 0); + + Square pawnSq = pos.list(strongerSide)[0]; + Square strongerBishopSq = pos.list(strongerSide)[0]; Square weakerKingSq = pos.king_square(weakerSide); if ( file_of(weakerKingSq) == file_of(pawnSq) @@ -885,12 +850,12 @@ template<> ScaleFactor Endgame::operator()(const Position& pos) const { assert(pos.non_pawn_material(strongerSide) == KnightValueMg); - assert(pos.piece_count(strongerSide, KNIGHT) == 1); - assert(pos.piece_count(strongerSide, PAWN) == 1); - assert(pos.non_pawn_material(weakerSide) == VALUE_ZERO); - assert(pos.piece_count(weakerSide, PAWN) == 0); + assert(pos.non_pawn_material(weakerSide ) == VALUE_ZERO); + assert(pos.count(strongerSide) == 1); + assert(pos.count< PAWN>(strongerSide) == 1); + assert(pos.count< PAWN>(weakerSide ) == 0); - Square pawnSq = pos.piece_list(strongerSide, PAWN)[0]; + Square pawnSq = pos.list(strongerSide)[0]; Square weakerKingSq = pos.king_square(weakerSide); if ( pawnSq == relative_square(strongerSide, SQ_A7) @@ -910,8 +875,8 @@ ScaleFactor Endgame::operator()(const Position& pos) const { template<> ScaleFactor Endgame::operator()(const Position& pos) const { - Square pawnSq = pos.piece_list(strongerSide, PAWN)[0]; - Square bishopSq = pos.piece_list(weakerSide, BISHOP)[0]; + Square pawnSq = pos.list(strongerSide)[0]; + Square bishopSq = pos.list(weakerSide)[0]; Square weakerKingSq = pos.king_square(weakerSide); // King needs to get close to promoting pawn to prevent knight from blocking. @@ -932,37 +897,36 @@ template<> ScaleFactor Endgame::operator()(const Position& pos) const { assert(pos.non_pawn_material(strongerSide) == VALUE_ZERO); - assert(pos.non_pawn_material(weakerSide) == VALUE_ZERO); - assert(pos.piece_count(WHITE, PAWN) == 1); - assert(pos.piece_count(BLACK, PAWN) == 1); + assert(pos.non_pawn_material(weakerSide ) == VALUE_ZERO); + assert(pos.count(WHITE) == 1); + assert(pos.count(BLACK) == 1); Square wksq = pos.king_square(strongerSide); Square bksq = pos.king_square(weakerSide); - Square wpsq = pos.piece_list(strongerSide, PAWN)[0]; - Color us = pos.side_to_move(); + Square psq = pos.list(strongerSide)[0]; + Color us = pos.side_to_move(); if (strongerSide == BLACK) { wksq = ~wksq; bksq = ~bksq; - wpsq = ~wpsq; + psq = ~psq; us = ~us; } - if (file_of(wpsq) >= FILE_E) + if (file_of(psq) >= FILE_E) { wksq = mirror(wksq); bksq = mirror(bksq); - wpsq = mirror(wpsq); + psq = mirror(psq); } // If the pawn has advanced to the fifth rank or further, and is not a // rook pawn, it's too dangerous to assume that it's at least a draw. - if ( rank_of(wpsq) >= RANK_5 - && file_of(wpsq) != FILE_A) + if (rank_of(psq) >= RANK_5 && file_of(psq) != FILE_A) return SCALE_FACTOR_NONE; // 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, wpsq, bksq, us) ? SCALE_FACTOR_NONE : SCALE_FACTOR_DRAW; + return Bitbases::probe_kpk(wksq, psq, bksq, us) ? SCALE_FACTOR_NONE : SCALE_FACTOR_DRAW; }