X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fendgame.cpp;h=56583c58890ffb6f7aac25979987719388407477;hp=53c9ec8364c4b6a010ff96fec56e1ebc6ac2a814;hb=ddcbacd04d1c860e808202ce8c1206c8acdca627;hpb=9690cd6295fbed93ee434e7b2e16181e475755ac diff --git a/src/endgame.cpp b/src/endgame.cpp index 53c9ec83..56583c58 100644 --- a/src/endgame.cpp +++ b/src/endgame.cpp @@ -24,35 +24,19 @@ #include "endgame.h" #include "movegen.h" -using std::string; - namespace { - // Table used to drive the king towards the edge of the board + // Used to drive the king towards the edge of the board // in KX vs K and KQ vs KR endgames. - constexpr 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, - 70, 50, 30, 20, 20, 30, 50, 70, - 70, 50, 30, 20, 20, 30, 50, 70, - 80, 60, 40, 30, 30, 40, 60, 80, - 90, 70, 60, 50, 50, 60, 70, 90, - 100, 90, 80, 70, 70, 80, 90, 100 - }; - - // Table used to drive the king towards a corner square of the - // right color in KBN vs K endgames. - constexpr int PushToCorners[SQUARE_NB] = { - 6400, 6080, 5760, 5440, 5120, 4800, 4480, 4160, - 6080, 5760, 5440, 5120, 4800, 4480, 4160, 4480, - 5760, 5440, 4960, 4480, 4480, 4000, 4480, 4800, - 5440, 5120, 4480, 3840, 3520, 4480, 4800, 5120, - 5120, 4800, 4480, 3520, 3840, 4480, 5120, 5440, - 4800, 4480, 4000, 4480, 4480, 4960, 5440, 5760, - 4480, 4160, 4480, 4800, 5120, 5440, 5760, 6080, - 4160, 4480, 4800, 5120, 5440, 5760, 6080, 6400 - }; + inline int push_to_edge(Square s) { + int rd = edge_distance(rank_of(s)), fd = edge_distance(file_of(s)); + return 90 - (7 * fd * fd / 2 + 7 * rd * rd / 2); + } + + // Used to drive the king towards A1H8 corners in KBN vs K endgames. + inline int push_to_corner(Square s) { + return abs(7 - rank_of(s) - file_of(s)); + } // Drive a piece close to or away from another piece inline int push_close(Square s1, Square s2) { return 140 - 20 * distance(s1, s2); } @@ -126,7 +110,7 @@ Value Endgame::operator()(const Position& pos) const { Value result = pos.non_pawn_material(strongSide) + pos.count(strongSide) * PawnValueEg - + PushToEdges[loserKSq] + + push_to_edge(loserKSq) + push_close(winnerKSq, loserKSq); if ( pos.count(strongSide) @@ -155,9 +139,9 @@ Value Endgame::operator()(const Position& pos) const { // If our bishop does not attack A1/H8, we flip the enemy king square // to drive to opposite corners (A8/H1). - Value result = VALUE_KNOWN_WIN + Value result = (VALUE_KNOWN_WIN + 3520) + push_close(winnerKSq, loserKSq) - + PushToCorners[opposite_colors(bishopSq, SQ_A1) ? ~loserKSq : loserKSq]; + + 420 * push_to_corner(opposite_colors(bishopSq, SQ_A1) ? flip_file(loserKSq) : loserKSq); assert(abs(result) < VALUE_TB_WIN_IN_MAX_PLY); return strongSide == pos.side_to_move() ? result : -result; @@ -240,7 +224,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.square(weakSide)]); + Value result = Value(push_to_edge(pos.square(weakSide))); return strongSide == pos.side_to_move() ? result : -result; } @@ -255,7 +239,7 @@ Value Endgame::operator()(const Position& pos) const { Square bksq = pos.square(weakSide); Square bnsq = pos.square(weakSide); - Value result = Value(PushToEdges[bksq] + push_away(bksq, bnsq)); + Value result = Value(push_to_edge(bksq) + push_away(bksq, bnsq)); return strongSide == pos.side_to_move() ? result : -result; } @@ -300,7 +284,7 @@ Value Endgame::operator()(const Position& pos) const { Value result = QueenValueEg - RookValueEg - + PushToEdges[loserKSq] + + push_to_edge(loserKSq) + push_close(winnerKSq, loserKSq); return strongSide == pos.side_to_move() ? result : -result; @@ -316,7 +300,7 @@ Value Endgame::operator()(const Position& pos) const { assert(verify_material(pos, weakSide, VALUE_ZERO, 1)); Value result = PawnValueEg - + 2 * PushToEdges[pos.square(weakSide)] + + 2 * push_to_edge(pos.square(weakSide)) - 10 * relative_rank(weakSide, pos.square(weakSide)); return strongSide == pos.side_to_move() ? result : -result; @@ -340,23 +324,23 @@ ScaleFactor Endgame::operator()(const Position& pos) const { // No assertions about the material of weakSide, because we want draws to // be detected even when the weaker side has some pawns. - Bitboard strongpawns = pos.pieces(strongSide, PAWN); - Bitboard allpawns = pos.pieces(PAWN); + Bitboard strongPawns = pos.pieces(strongSide, PAWN); + Bitboard allPawns = pos.pieces(PAWN); // All strongSide pawns are on a single rook file? - if (!(strongpawns & ~FileABB) || !(strongpawns & ~FileHBB)) + if (!(strongPawns & ~FileABB) || !(strongPawns & ~FileHBB)) { Square bishopSq = pos.square(strongSide); - Square queeningSq = relative_square(strongSide, make_square(file_of(lsb(strongpawns)), RANK_8)); - Square weakkingSq = pos.square(weakSide); + Square queeningSq = relative_square(strongSide, make_square(file_of(lsb(strongPawns)), RANK_8)); + Square weakKingSq = pos.square(weakSide); if ( opposite_colors(queeningSq, bishopSq) - && distance(queeningSq, weakkingSq) <= 1) + && distance(queeningSq, weakKingSq) <= 1) return SCALE_FACTOR_DRAW; } // If all the pawns are on the same B or G file, then it's potentially a draw - if ((!(allpawns & ~FileBBB) || !(allpawns & ~FileGBB)) + if ((!(allPawns & ~FileBBB) || !(allPawns & ~FileGBB)) && pos.non_pawn_material(weakSide) == 0 && pos.count(weakSide) >= 1) { @@ -370,8 +354,8 @@ ScaleFactor Endgame::operator()(const Position& pos) const { // 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 - && (strongpawns & (weakPawnSq + pawn_push(weakSide))) - && (opposite_colors(bishopSq, weakPawnSq) || !more_than_one(strongpawns))) + && (strongPawns & (weakPawnSq + pawn_push(weakSide))) + && (opposite_colors(bishopSq, weakPawnSq) || !more_than_one(strongPawns))) { int strongKingDist = distance(weakPawnSq, strongKingSq); int weakKingDist = distance(weakPawnSq, weakKingSq); @@ -602,11 +586,9 @@ ScaleFactor Endgame::operator()(const Position& pos) const { Square ksq = pos.square(weakSide); Bitboard pawns = pos.pieces(strongSide, PAWN); - // 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 & ~forward_ranks_bb(weakSide, ksq)) - && !((pawns & ~FileABB) && (pawns & ~FileHBB)) - && distance(ksq, lsb(pawns)) <= 1) + // If all pawns are ahead of the king on a single rook file, it's a draw. + if (!((pawns & ~FileABB) || (pawns & ~FileHBB)) && + !(pawns & ~passed_pawn_span(weakSide, ksq))) return SCALE_FACTOR_DRAW; return SCALE_FACTOR_NONE; @@ -629,8 +611,7 @@ ScaleFactor Endgame::operator()(const Position& pos) const { Square weakKingSq = pos.square(weakSide); // Case 1: Defending king blocks the pawn, and cannot be driven away - if ( file_of(weakKingSq) == file_of(pawnSq) - && relative_rank(strongSide, pawnSq) < relative_rank(strongSide, weakKingSq) + if ( (forward_file_bb(strongSide, pawnSq) & weakKingSq) && ( opposite_colors(weakKingSq, strongBishopSq) || relative_rank(strongSide, weakKingSq) <= RANK_6)) return SCALE_FACTOR_DRAW;