From: Fabian Fichter Date: Sat, 18 Jul 2020 08:33:12 +0000 (+0200) Subject: Merge official-stockfish/master X-Git-Url: http://winboard.nl/cgi-bin?a=commitdiff_plain;h=2c8742f185c8516ae67a775a3eb0042b65827fc4;p=fairystockfish.git Merge official-stockfish/master bench: 5054568 --- 2c8742f185c8516ae67a775a3eb0042b65827fc4 diff --cc src/endgame.cpp index 4cc1340,73a4463..e48a01f --- a/src/endgame.cpp +++ b/src/endgame.cpp @@@ -54,22 -54,9 +54,22 @@@ namespace 4160, 4480, 4800, 5120, 5440, 5760, 6080, 6400 }; + // Table used to drive the king towards the edge of the board + // in KSF vs K. + constexpr int PushToOpposingSideEdges[SQUARE_NB] = { + 20, 10, 5, 0, 0, 5, 10, 20, + 20, 10, 5, 0, 0, 5, 10, 20, + 30, 20, 10, 0, 0, 10, 20, 30, + 50, 40, 20, 10, 10, 20, 40, 50, + 60, 50, 40, 30, 30, 40, 50, 60, + 70, 60, 50, 40, 40, 50, 60, 70, + 90, 70, 60, 50, 50, 60, 70, 90, + 100, 90, 80, 70, 70, 80, 90, 100 + }; + - // Tables used to drive a piece towards or away from another piece - constexpr int PushClose[FILE_NB] = { 0, 0, 100, 80, 60, 40, 20, 10 }; - constexpr int PushAway [FILE_NB] = { 0, 5, 20, 40, 60, 80, 90, 100 }; + // Drive a piece close to or away from another piece + inline int push_close(Square s1, Square s2) { return 140 - 20 * distance(s1, s2); } + inline int push_away(Square s1, Square s2) { return 120 - push_close(s1, s2); } // Pawn Rank based scaling factors used in KRPPKRP endgame constexpr int KRPPKRPScaleFactors[RANK_NB] = { 0, 9, 10, 14, 21, 44, 0, 0 }; @@@ -157,8 -129,8 +157,8 @@@ Value Endgame::operator()(const Po Value result = pos.non_pawn_material(strongSide) + pos.count(strongSide) * PawnValueEg - + PushToEdges[loserKSq] + + PushToEdges[map_to_standard_board(pos, loserKSq)] - + PushClose[distance(winnerKSq, loserKSq)]; + + push_close(winnerKSq, loserKSq); if ( pos.count(strongSide) || pos.count(strongSide) @@@ -194,8 -159,8 +194,8 @@@ Value Endgame::operator()(const P // to drive to opposite corners (A8/H1). Value result = VALUE_KNOWN_WIN - + PushClose[distance(winnerKSq, loserKSq)] + + push_close(winnerKSq, loserKSq) - + PushToCorners[opposite_colors(bishopSq, SQ_A1) ? ~loserKSq : loserKSq]; + + PushToCorners[map_to_standard_board(pos, relative_square(opposite_colors(bishopSq, SQ_A1) ? BLACK : WHITE, loserKSq, pos.max_rank()))]; assert(abs(result) < VALUE_TB_WIN_IN_MAX_PLY); return strongSide == pos.side_to_move() ? result : -result; @@@ -304,7 -258,7 +304,7 @@@ Value Endgame::operator()(const P Square bksq = pos.square(weakSide); Square bnsq = pos.square(weakSide); - Value result = Value(PushToEdges[map_to_standard_board(pos, bksq)] + PushAway[distance(bksq, bnsq)]); - Value result = Value(PushToEdges[bksq] + push_away(bksq, bnsq)); ++ Value result = Value(PushToEdges[map_to_standard_board(pos, bksq)] + push_away(bksq, bnsq)); return strongSide == pos.side_to_move() ? result : -result; } @@@ -349,8 -303,8 +349,8 @@@ Value Endgame::operator()(const P Value result = QueenValueEg - RookValueEg - + PushToEdges[loserKSq] + + PushToEdges[map_to_standard_board(pos, loserKSq)] - + PushClose[distance(winnerKSq, loserKSq)]; + + push_close(winnerKSq, loserKSq); return strongSide == pos.side_to_move() ? result : -result; } @@@ -376,169 -330,6 +376,169 @@@ Value Endgame::operator()(const template<> Value Endgame::operator()(const Position&) const { return VALUE_DRAW; } +/// KFsPs vs K. +template<> +Value Endgame::operator()(const Position& pos) const { + + assert(verify_material(pos, weakSide, VALUE_ZERO, 0)); + + Square winnerKSq = pos.square(strongSide); + Square loserKSq = pos.square(weakSide); + + Value result = pos.non_pawn_material(strongSide) + + pos.count(strongSide) * PawnValueEg + + PushToEdges[map_to_standard_board(pos, loserKSq)] - + PushClose[distance(winnerKSq, loserKSq)]; ++ + push_close(winnerKSq, loserKSq); + + if ( pos.count(strongSide) >= 3 + && ( DarkSquares & pos.pieces(strongSide, FERS)) + && (~DarkSquares & pos.pieces(strongSide, FERS))) + result = std::min(result + VALUE_KNOWN_WIN, VALUE_TB_WIN_IN_MAX_PLY - 1); + else if (pos.count(strongSide) + pos.count(strongSide) < 3) + return VALUE_DRAW; + else + { + bool dark = DarkSquares & pos.pieces(strongSide, FERS); + bool light = ~DarkSquares & pos.pieces(strongSide, FERS); + + // Determine the color of ferzes from promoting pawns + Bitboard b = pos.pieces(strongSide, PAWN); + while (b && (!dark || !light)) + { + if (file_of(pop_lsb(&b)) % 2 != relative_rank(strongSide, pos.promotion_rank(), pos.max_rank()) % 2) + light = true; + else + dark = true; + } + if (!dark || !light) + return VALUE_DRAW; // we can not checkmate with same colored ferzes + } + + return strongSide == pos.side_to_move() ? result : -result; +} + + +/// Mate with KNS vs K. +template<> +Value Endgame::operator()(const Position& pos) const { + + assert(verify_material(pos, strongSide, KnightValueMg + SilverValueMg, 0)); + assert(verify_material(pos, weakSide, VALUE_ZERO, 0)); + + Square winnerKSq = pos.square(strongSide); + Square loserKSq = pos.square(weakSide); + + Value result = VALUE_KNOWN_WIN - + PushClose[distance(winnerKSq, loserKSq)] ++ + push_close(winnerKSq, loserKSq) + + PushToOpposingSideEdges[map_to_standard_board(pos, relative_square(strongSide, loserKSq, pos.max_rank()))]; + + return strongSide == pos.side_to_move() ? result : -result; +} + + +/// KNF vs K. Can only be won if the weaker side's king +/// is close to a corner of the same color as the fers. +template<> +Value Endgame::operator()(const Position& pos) const { + + assert(verify_material(pos, strongSide, KnightValueMg + FersValueMg, 0)); + assert(verify_material(pos, weakSide, VALUE_ZERO, 0)); + + Square winnerKSq = pos.square(strongSide); + Square loserKSq = pos.square(weakSide); + Square fersSq = pos.square(strongSide); + + // tries to drive toward corners A1 or H8. If we have a + // fers that cannot reach the above squares, we flip the kings in order + // to drive the enemy toward corners A8 or H1. + if (opposite_colors(fersSq, SQ_A1)) + { + winnerKSq = relative_square(BLACK, winnerKSq, pos.max_rank()); + loserKSq = relative_square(BLACK, loserKSq, pos.max_rank()); + } + - Value result = Value(PushClose[distance(winnerKSq, loserKSq)]) ++ Value result = Value(push_close(winnerKSq, loserKSq)) + + (PushToCorners[map_to_standard_board(pos, loserKSq)] - 3000) / 10; + + return strongSide == pos.side_to_move() ? result : -result; +} + + +/// KNSFKR vs K. +template<> +Value Endgame::operator()(const Position& pos) const { + + assert(verify_material(pos, strongSide, KnightValueMg + SilverValueMg + FersValueMg, 0)); + assert(verify_material(pos, weakSide, RookValueMg, 0)); + + Square winnerKSq = pos.square(strongSide); + Square loserKSq = pos.square(weakSide); + + Value result = KnightValueEg + SilverValueEg + FersValueEg - RookValueEg - + PushClose[distance(winnerKSq, loserKSq)] ++ + push_close(winnerKSq, loserKSq) + + PushToOpposingSideEdges[map_to_standard_board(pos, relative_square(strongSide, loserKSq, pos.max_rank()))]; + + return strongSide == pos.side_to_move() ? result : -result; +} + + +/// Mate with KSF vs K. +template<> +Value Endgame::operator()(const Position& pos) const { + + assert(verify_material(pos, strongSide, SilverValueMg + FersValueMg, 0)); + assert(verify_material(pos, weakSide, VALUE_ZERO, 0)); + + Square winnerKSq = pos.square(strongSide); + Square loserKSq = pos.square(weakSide); + + Value result = VALUE_KNOWN_WIN - + PushClose[distance(winnerKSq, loserKSq)] ++ + push_close(winnerKSq, loserKSq) + + PushToOpposingSideEdges[map_to_standard_board(pos, relative_square(strongSide, loserKSq, pos.max_rank()))]; + + return strongSide == pos.side_to_move() ? result : -result; +} + + +/// Mate with KSF vs KF. +template<> +Value Endgame::operator()(const Position& pos) const { + + assert(verify_material(pos, strongSide, SilverValueMg + FersValueMg, 0)); + assert(verify_material(pos, weakSide, FersValueMg, 0)); + + Square winnerKSq = pos.square(strongSide); + Square loserKSq = pos.square(weakSide); + Square fersSq = pos.square(weakSide); + + Value result = SilverValueEg - + PushClose[distance(winnerKSq, loserKSq)] - + PushAway[distance(fersSq, loserKSq)] ++ + push_close(winnerKSq, loserKSq) ++ + push_away(fersSq, loserKSq) + + PushToOpposingSideEdges[map_to_standard_board(pos, relative_square(strongSide, loserKSq, pos.max_rank()))]; + + return strongSide == pos.side_to_move() ? result : -result; +} + + +/// KR vs KS +template<> +Value Endgame::operator()(const Position& pos) const { + + assert(verify_material(pos, strongSide, RookValueMg, 0)); + assert(verify_material(pos, weakSide, SilverValueMg, 0)); + + Square winnerKSq = pos.square(strongSide); + Square loserKSq = pos.square(weakSide); + + Value result = RookValueEg + - SilverValueEg + + PushToEdges[map_to_standard_board(pos, loserKSq)] - + PushClose[distance(winnerKSq, loserKSq)]; ++ + push_close(winnerKSq, loserKSq); + + return strongSide == pos.side_to_move() ? result : -result; +} + + /// KB 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 /// is returned. If not, the return value is SCALE_FACTOR_NONE, i.e. no scaling