mirror of
https://github.com/sockspls/badfish
synced 2025-04-30 16:53:09 +00:00
Equations for edges and corners.
This is a functional simplification that removes the large arrays in endgames.cpp.
It also fixes a recently introduced bug (960d59d541
) in KNBvK,
now using flip_file() instead of ~.
One fen added to bench to increase endgame coverage.
STC
LLR: 2.94 (-2.94,2.94) {-1.50,0.50}
Total: 174724 W: 33325 L: 33404 D: 107995
Ptnml(0-2): 2503, 19607, 43181, 19608, 2463
http://tests.stockfishchess.org/tests/view/5e6448ffe42a5c3b3ca2e287
LTC
LLR: 2.95 (-2.94,2.94) {-1.50,0.50}
Total: 35640 W: 4679 L: 4621 D: 26340
Ptnml(0-2): 189, 2991, 11424, 3005, 211
http://tests.stockfishchess.org/tests/view/5e650b24e42a5c3b3ca2e2d8
closes https://github.com/official-stockfish/Stockfish/pull/2577
Bench: 5527957
This commit is contained in:
parent
37e3863927
commit
47be966d30
8 changed files with 24 additions and 38 deletions
|
@ -65,6 +65,7 @@ const vector<string> Defaults = {
|
||||||
"4rrk1/1p1nq3/p7/2p1P1pp/3P2bp/3Q1Bn1/PPPB4/1K2R1NR w - - 40 21",
|
"4rrk1/1p1nq3/p7/2p1P1pp/3P2bp/3Q1Bn1/PPPB4/1K2R1NR w - - 40 21",
|
||||||
"r3k2r/3nnpbp/q2pp1p1/p7/Pp1PPPP1/4BNN1/1P5P/R2Q1RK1 w kq - 0 16",
|
"r3k2r/3nnpbp/q2pp1p1/p7/Pp1PPPP1/4BNN1/1P5P/R2Q1RK1 w kq - 0 16",
|
||||||
"3Qb1k1/1r2ppb1/pN1n2q1/Pp1Pp1Pr/4P2p/4BP2/4B1R1/1R5K b - - 11 40",
|
"3Qb1k1/1r2ppb1/pN1n2q1/Pp1Pp1Pr/4P2p/4BP2/4B1R1/1R5K b - - 11 40",
|
||||||
|
"4k3/3q1r2/1N2r1b1/3ppN2/2nPP3/1B1R2n1/2R1Q3/3K4 w - - 5 1",
|
||||||
|
|
||||||
// 5-man positions
|
// 5-man positions
|
||||||
"8/8/8/8/5kp1/P7/8/1K1N4 w - - 0 1", // Kc2 - mate
|
"8/8/8/8/5kp1/P7/8/1K1N4 w - - 0 1", // Kc2 - mate
|
||||||
|
|
|
@ -255,6 +255,8 @@ template<> inline int distance<File>(Square x, Square y) { return std::abs(file_
|
||||||
template<> inline int distance<Rank>(Square x, Square y) { return std::abs(rank_of(x) - rank_of(y)); }
|
template<> inline int distance<Rank>(Square x, Square y) { return std::abs(rank_of(x) - rank_of(y)); }
|
||||||
template<> inline int distance<Square>(Square x, Square y) { return SquareDistance[x][y]; }
|
template<> inline int distance<Square>(Square x, Square y) { return SquareDistance[x][y]; }
|
||||||
|
|
||||||
|
inline File edge_distance(File f) { return std::min(f, File(FILE_H - f)); }
|
||||||
|
inline Rank edge_distance(Rank r) { return std::min(r, Rank(RANK_8 - r)); }
|
||||||
|
|
||||||
/// attacks_bb() returns a bitboard representing all the squares attacked by a
|
/// attacks_bb() returns a bitboard representing all the squares attacked by a
|
||||||
/// piece of type Pt (bishop or rook) placed on 's'.
|
/// piece of type Pt (bishop or rook) placed on 's'.
|
||||||
|
|
|
@ -28,31 +28,17 @@ using std::string;
|
||||||
|
|
||||||
namespace {
|
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.
|
// in KX vs K and KQ vs KR endgames.
|
||||||
constexpr int PushToEdges[SQUARE_NB] = {
|
inline int push_to_edge(Square s) {
|
||||||
100, 90, 80, 70, 70, 80, 90, 100,
|
int rd = edge_distance(rank_of(s)), fd = edge_distance(file_of(s));
|
||||||
90, 70, 60, 50, 50, 60, 70, 90,
|
return 90 - (7 * fd * fd / 2 + 7 * rd * rd / 2);
|
||||||
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
|
// Used to drive the king towards A1H8 corners in KBN vs K endgames.
|
||||||
// right color in KBN vs K endgames.
|
inline int push_to_corner(Square s) {
|
||||||
constexpr int PushToCorners[SQUARE_NB] = {
|
return abs(7 - rank_of(s) - file_of(s));
|
||||||
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
|
|
||||||
};
|
|
||||||
|
|
||||||
// Drive a piece close to or away from another piece
|
// 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_close(Square s1, Square s2) { return 140 - 20 * distance(s1, s2); }
|
||||||
|
@ -126,7 +112,7 @@ Value Endgame<KXK>::operator()(const Position& pos) const {
|
||||||
|
|
||||||
Value result = pos.non_pawn_material(strongSide)
|
Value result = pos.non_pawn_material(strongSide)
|
||||||
+ pos.count<PAWN>(strongSide) * PawnValueEg
|
+ pos.count<PAWN>(strongSide) * PawnValueEg
|
||||||
+ PushToEdges[loserKSq]
|
+ push_to_edge(loserKSq)
|
||||||
+ push_close(winnerKSq, loserKSq);
|
+ push_close(winnerKSq, loserKSq);
|
||||||
|
|
||||||
if ( pos.count<QUEEN>(strongSide)
|
if ( pos.count<QUEEN>(strongSide)
|
||||||
|
@ -155,9 +141,9 @@ Value Endgame<KBNK>::operator()(const Position& pos) const {
|
||||||
// If our bishop does not attack A1/H8, we flip the enemy king square
|
// If our bishop does not attack A1/H8, we flip the enemy king square
|
||||||
// to drive to opposite corners (A8/H1).
|
// to drive to opposite corners (A8/H1).
|
||||||
|
|
||||||
Value result = VALUE_KNOWN_WIN
|
Value result = (VALUE_KNOWN_WIN + 3520)
|
||||||
+ push_close(winnerKSq, loserKSq)
|
+ 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);
|
assert(abs(result) < VALUE_TB_WIN_IN_MAX_PLY);
|
||||||
return strongSide == pos.side_to_move() ? result : -result;
|
return strongSide == pos.side_to_move() ? result : -result;
|
||||||
|
@ -240,7 +226,7 @@ Value Endgame<KRKB>::operator()(const Position& pos) const {
|
||||||
assert(verify_material(pos, strongSide, RookValueMg, 0));
|
assert(verify_material(pos, strongSide, RookValueMg, 0));
|
||||||
assert(verify_material(pos, weakSide, BishopValueMg, 0));
|
assert(verify_material(pos, weakSide, BishopValueMg, 0));
|
||||||
|
|
||||||
Value result = Value(PushToEdges[pos.square<KING>(weakSide)]);
|
Value result = Value(push_to_edge(pos.square<KING>(weakSide)));
|
||||||
return strongSide == pos.side_to_move() ? result : -result;
|
return strongSide == pos.side_to_move() ? result : -result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -255,7 +241,7 @@ Value Endgame<KRKN>::operator()(const Position& pos) const {
|
||||||
|
|
||||||
Square bksq = pos.square<KING>(weakSide);
|
Square bksq = pos.square<KING>(weakSide);
|
||||||
Square bnsq = pos.square<KNIGHT>(weakSide);
|
Square bnsq = pos.square<KNIGHT>(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;
|
return strongSide == pos.side_to_move() ? result : -result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -300,7 +286,7 @@ Value Endgame<KQKR>::operator()(const Position& pos) const {
|
||||||
|
|
||||||
Value result = QueenValueEg
|
Value result = QueenValueEg
|
||||||
- RookValueEg
|
- RookValueEg
|
||||||
+ PushToEdges[loserKSq]
|
+ push_to_edge(loserKSq)
|
||||||
+ push_close(winnerKSq, loserKSq);
|
+ push_close(winnerKSq, loserKSq);
|
||||||
|
|
||||||
return strongSide == pos.side_to_move() ? result : -result;
|
return strongSide == pos.side_to_move() ? result : -result;
|
||||||
|
@ -316,7 +302,7 @@ Value Endgame<KNNKP>::operator()(const Position& pos) const {
|
||||||
assert(verify_material(pos, weakSide, VALUE_ZERO, 1));
|
assert(verify_material(pos, weakSide, VALUE_ZERO, 1));
|
||||||
|
|
||||||
Value result = PawnValueEg
|
Value result = PawnValueEg
|
||||||
+ 2 * PushToEdges[pos.square<KING>(weakSide)]
|
+ 2 * push_to_edge(pos.square<KING>(weakSide))
|
||||||
- 10 * relative_rank(weakSide, pos.square<PAWN>(weakSide));
|
- 10 * relative_rank(weakSide, pos.square<PAWN>(weakSide));
|
||||||
|
|
||||||
return strongSide == pos.side_to_move() ? result : -result;
|
return strongSide == pos.side_to_move() ? result : -result;
|
||||||
|
|
|
@ -643,7 +643,7 @@ namespace {
|
||||||
|| (pos.pieces(PAWN) & (s + Up)))
|
|| (pos.pieces(PAWN) & (s + Up)))
|
||||||
bonus = bonus / 2;
|
bonus = bonus / 2;
|
||||||
|
|
||||||
score += bonus - PassedFile * map_to_queenside(file_of(s));
|
score += bonus - PassedFile * edge_distance(file_of(s));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (T)
|
if (T)
|
||||||
|
|
|
@ -202,7 +202,7 @@ Score Entry::evaluate_shelter(const Position& pos, Square ksq) {
|
||||||
b = theirPawns & file_bb(f);
|
b = theirPawns & file_bb(f);
|
||||||
int theirRank = b ? relative_rank(Us, frontmost_sq(Them, b)) : 0;
|
int theirRank = b ? relative_rank(Us, frontmost_sq(Them, b)) : 0;
|
||||||
|
|
||||||
File d = map_to_queenside(f);
|
File d = edge_distance(f);
|
||||||
bonus += make_score(ShelterStrength[d][ourRank], 0);
|
bonus += make_score(ShelterStrength[d][ourRank], 0);
|
||||||
|
|
||||||
if (ourRank && (ourRank == theirRank - 1))
|
if (ourRank && (ourRank == theirRank - 1))
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
#include "bitboard.h"
|
||||||
|
|
||||||
namespace PSQT {
|
namespace PSQT {
|
||||||
|
|
||||||
|
@ -111,7 +112,7 @@ void init() {
|
||||||
|
|
||||||
for (Square s = SQ_A1; s <= SQ_H8; ++s)
|
for (Square s = SQ_A1; s <= SQ_H8; ++s)
|
||||||
{
|
{
|
||||||
File f = map_to_queenside(file_of(s));
|
File f = edge_distance(file_of(s));
|
||||||
psq[ pc][ s] = score + (type_of(pc) == PAWN ? PBonus[rank_of(s)][file_of(s)]
|
psq[ pc][ s] = score + (type_of(pc) == PAWN ? PBonus[rank_of(s)][file_of(s)]
|
||||||
: Bonus[pc][rank_of(s)][f]);
|
: Bonus[pc][rank_of(s)][f]);
|
||||||
psq[~pc][flip_rank(s)] = -psq[pc][s];
|
psq[~pc][flip_rank(s)] = -psq[pc][s];
|
||||||
|
|
|
@ -705,7 +705,7 @@ Ret do_probe_table(const Position& pos, T* entry, WDLScore wdl, ProbeState* resu
|
||||||
|
|
||||||
std::swap(squares[0], *std::max_element(squares, squares + leadPawnsCnt, pawns_comp));
|
std::swap(squares[0], *std::max_element(squares, squares + leadPawnsCnt, pawns_comp));
|
||||||
|
|
||||||
tbFile = map_to_queenside(file_of(squares[0]));
|
tbFile = edge_distance(file_of(squares[0]));
|
||||||
}
|
}
|
||||||
|
|
||||||
// DTZ tables are one-sided, i.e. they store positions only for white to
|
// DTZ tables are one-sided, i.e. they store positions only for white to
|
||||||
|
|
|
@ -370,10 +370,6 @@ constexpr Piece operator~(Piece pc) {
|
||||||
return Piece(pc ^ 8); // Swap color of piece B_KNIGHT -> W_KNIGHT
|
return Piece(pc ^ 8); // Swap color of piece B_KNIGHT -> W_KNIGHT
|
||||||
}
|
}
|
||||||
|
|
||||||
inline File map_to_queenside(File f) {
|
|
||||||
return std::min(f, File(FILE_H - f)); // Map files ABCDEFGH to files ABCDDCBA
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr CastlingRights operator&(Color c, CastlingRights cr) {
|
constexpr CastlingRights operator&(Color c, CastlingRights cr) {
|
||||||
return CastlingRights((c == WHITE ? WHITE_CASTLING : BLACK_CASTLING) & cr);
|
return CastlingRights((c == WHITE ? WHITE_CASTLING : BLACK_CASTLING) & cr);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue