X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fendgame.cpp;h=976b3d6365c46d4316784bb3ea078af54924e0b7;hp=e1ff568f7716b4f306ff04f71ab8e30bed459608;hb=c7e7d9217b232eb7d75b083a45f001ef998c9deb;hpb=3674f18b97bbf54bcec9b474d2204302a311e9da diff --git a/src/endgame.cpp b/src/endgame.cpp index e1ff568f..976b3d63 100644 --- a/src/endgame.cpp +++ b/src/endgame.cpp @@ -65,6 +65,21 @@ namespace { } #endif + // Map the square as if strongSide is white and strongSide's only pawn + // is on the left half of the board. + Square normalize(const Position& pos, Color strongSide, Square sq) { + + assert(pos.count(strongSide) == 1); + + if (file_of(pos.list(strongSide)[0]) >= FILE_E) + sq = Square(sq ^ 7); // Mirror SQ_H1 -> SQ_A1 + + if (strongSide == BLACK) + sq = ~sq; + + return sq; + } + // 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 // and then let a Position object to do the work for us. Note that the @@ -130,7 +145,7 @@ void Endgames::add(const string& code) { /// Mate with KX vs K. This function is used to evaluate positions with -/// King and plenty of material vs a lone king. It simply gives the +/// king and plenty of material vs a lone king. It simply gives the /// attacking side a bonus for driving the defending king towards the edge /// of the board, and for keeping the distance between the two kings small. template<> @@ -172,9 +187,9 @@ Value Endgame::operator()(const Position& pos) const { Square loserKSq = pos.king_square(weakSide); Square bishopSq = pos.list(strongSide)[0]; - // 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 so to drive enemy toward corners A8 or H1. + // 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 + // to drive the enemy toward corners A8 or H1. if (opposite_colors(bishopSq, SQ_A1)) { winnerKSq = ~winnerKSq; @@ -188,22 +203,6 @@ Value Endgame::operator()(const Position& pos) const { return strongSide == pos.side_to_move() ? result : -result; } -// Returns a square that will allow us to orient the board so that -// strongSide is white and strongSide's only pawn is on the left -// half of the board -Square get_flip_sq(const Position& pos, Color strongSide) { - - assert(pos.count(strongSide) == 1); - - Square psq = pos.list(strongSide)[0]; - - return (FILE_H * (file_of(psq) >= FILE_E)) | (RANK_8 * int(strongSide)); -} - -Square operator^(Square s, Square flip_sq) { - assert(flip_sq == SQ_A1 || flip_sq == SQ_H1 || flip_sq == SQ_A8 || flip_sq == SQ_H8); - return Square(int(s) ^ int(flip_sq)); -} /// KP vs K. This endgame is evaluated with the help of a bitbase. template<> @@ -213,11 +212,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 flip_sq = get_flip_sq(pos, strongSide); - - Square wksq = pos.king_square(strongSide) ^ flip_sq; - Square bksq = pos.king_square(weakSide) ^ flip_sq; - Square psq = pos.list(strongSide)[0] ^ flip_sq; + 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]); Color us = strongSide == pos.side_to_move() ? WHITE : BLACK; @@ -304,9 +301,10 @@ Value Endgame::operator()(const Position& pos) const { } -/// KQ vs KP. In general, a win for the stronger side, however, there are a few -/// important exceptions. Pawn on 7th rank, A,C,F or H file, with king next can -/// be a draw, so we scale down to distance between kings only. +/// KQ vs KP. In general, this is a win for the stronger side, but there are a +/// few important exceptions. A pawn on 7th rank and on the A,C,F or H files +/// with a king positioned next to it can be a draw, so in that case, we only +/// use the distance between the kings. template<> Value Endgame::operator()(const Position& pos) const { @@ -408,20 +406,20 @@ ScaleFactor Endgame::operator()(const Position& pos) const { return SCALE_FACTOR_DRAW; } - // All pawns on same B or G file? Then potential draw + // 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)) && pos.non_pawn_material(weakSide) == 0 && pos.count(weakSide) >= 1) { - // Get weakSide pawn that is closest to home rank + // 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]; - // Potential for a draw if our pawn is blocked on the 7th rank + // 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 if ( relative_rank(strongSide, weakPawnSq) == RANK_7 && (pos.pieces(strongSide, PAWN) & (weakPawnSq + pawn_push(weakSide))) @@ -430,7 +428,7 @@ ScaleFactor Endgame::operator()(const Position& pos) const { int strongKingDist = square_distance(weakPawnSq, strongKingSq); int weakKingDist = square_distance(weakPawnSq, weakKingSq); - // Draw if the weak king is on it's back two ranks, within 2 + // 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 // closer. (I think this rule only fails in practically // unreachable positions such as 5k1K/6p1/6P1/8/8/3B4/8/8 w @@ -476,7 +474,7 @@ ScaleFactor Endgame::operator()(const Position& pos) const { /// probably be a good idea to add more knowledge in the future. /// /// It would also be nice to rewrite the actual code for this function, -/// which is mostly copied from Glaurung 1.x, and not very pretty. +/// which is mostly copied from Glaurung 1.x, and isn't very pretty. template<> ScaleFactor Endgame::operator()(const Position& pos) const { @@ -484,13 +482,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 flip_sq = get_flip_sq(pos, strongSide); - - Square wksq = pos.king_square(strongSide) ^ flip_sq; - Square bksq = pos.king_square(weakSide) ^ flip_sq; - Square wrsq = pos.list(strongSide)[0] ^ flip_sq; - Square wpsq = pos.list(strongSide)[0] ^ flip_sq; - Square brsq = pos.list(weakSide)[0] ^ flip_sq; + 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]); File f = file_of(wpsq); Rank r = rank_of(wpsq); @@ -765,8 +761,8 @@ ScaleFactor Endgame::operator()(const Position& pos) const { switch (file_distance(psq1, psq2)) { case 0: - // Both pawns are on the same file. Easy draw if defender firmly controls - // some square in the frontmost pawn's path. + // Both pawns are on the same file. It's an easy draw if the defender firmly + // controls some square in the frontmost pawn's path. if ( file_of(ksq) == file_of(blockSq1) && relative_rank(strongSide, ksq) >= relative_rank(strongSide, blockSq1) && opposite_colors(ksq, wbsq)) @@ -775,9 +771,9 @@ ScaleFactor Endgame::operator()(const Position& pos) const { return SCALE_FACTOR_NONE; case 1: - // Pawns on adjacent files. Draw if defender firmly controls the square - // in front of the frontmost pawn's path, and the square diagonally behind - // this square on the file of the other pawn. + // Pawns on adjacent files. It's a draw if the defender firmly controls the + // square in front of the frontmost pawn's path, and the square diagonally + // behind this square on the file of the other pawn. if ( ksq == blockSq1 && opposite_colors(ksq, wbsq) && ( bbsq == blockSq2 @@ -833,10 +829,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 flip_sq = get_flip_sq(pos, strongSide); - - Square pawnSq = pos.list(strongSide)[0] ^ flip_sq; - Square weakKingSq = pos.king_square(weakSide) ^ flip_sq; + 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) return SCALE_FACTOR_DRAW; @@ -875,11 +869,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 flip_sq = get_flip_sq(pos, strongSide); - - Square wksq = pos.king_square(strongSide) ^ flip_sq; - Square bksq = pos.king_square(weakSide) ^ flip_sq; - Square psq = pos.list(strongSide)[0] ^ flip_sq; + 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]); Color us = strongSide == pos.side_to_move() ? WHITE : BLACK;