mirror of
https://github.com/sockspls/badfish
synced 2025-04-30 16:53:09 +00:00
Merge pull request #14 from joergoster/sf-nnue-nodchip
Update to SF master
This commit is contained in:
commit
ff31d92b94
25 changed files with 446 additions and 392 deletions
1
AUTHORS
1
AUTHORS
|
@ -115,6 +115,7 @@ Nick Pelling (nickpelling)
|
|||
Nicklas Persson (NicklasPersson)
|
||||
Niklas Fiekas (niklasf)
|
||||
Nikolay Kostov (NikolayIT)
|
||||
Nguyen Pham
|
||||
Ondrej Mosnáček (WOnder93)
|
||||
Oskar Werkelin Ahlin
|
||||
Pablo Vazquez
|
||||
|
|
24
Readme.md
24
Readme.md
|
@ -165,17 +165,23 @@ are in use, see the engine log.
|
|||
|
||||
## Compiling Stockfish yourself from the sources
|
||||
|
||||
On Unix-like systems, it should be possible to compile Stockfish
|
||||
directly from the source code with the included Makefile.
|
||||
Stockfish has support for 32 or 64-bit CPUs, certain hardware
|
||||
instructions, big-endian machines such as Power PC, and other platforms.
|
||||
|
||||
Stockfish has support for 32 or 64-bit CPUs, the hardware POPCNT
|
||||
instruction, big-endian machines such as Power PC, and other platforms.
|
||||
On Unix-like systems, it should be easy to compile Stockfish
|
||||
directly from the source code with the included Makefile in the folder
|
||||
`src`. In general it is recommended to run `make help` to see a list of make
|
||||
targets with corresponding descriptions.
|
||||
|
||||
In general it is recommended to run `make help` to see a list of make
|
||||
targets with corresponding descriptions. When not using the Makefile to
|
||||
compile (for instance with Microsoft MSVC) you need to manually
|
||||
set/unset some switches in the compiler command line; see file *types.h*
|
||||
for a quick reference.
|
||||
```
|
||||
cd src
|
||||
make help
|
||||
make build ARCH=x86-64-modern
|
||||
```
|
||||
|
||||
When not using the Makefile to compile (for instance with Microsoft MSVC) you
|
||||
need to manually set/unset some switches in the compiler command line; see
|
||||
file *types.h* for a quick reference.
|
||||
|
||||
When reporting an issue or a bug, please tell us which version and
|
||||
compiler you used to create your executable. These informations can
|
||||
|
|
|
@ -391,7 +391,7 @@ ifeq ($(pext),yes)
|
|||
endif
|
||||
endif
|
||||
|
||||
### 3.8 Link Time Optimization, it works since gcc 4.5 but not on mingw under Windows.
|
||||
### 3.8 Link Time Optimization
|
||||
### This is a mix of compile and link time options because the lto link phase
|
||||
### needs access to the optimization flags.
|
||||
ifeq ($(optimize),yes)
|
||||
|
|
|
@ -108,25 +108,25 @@ namespace {
|
|||
stm = Color ((idx >> 12) & 0x01);
|
||||
psq = make_square(File((idx >> 13) & 0x3), Rank(RANK_7 - ((idx >> 15) & 0x7)));
|
||||
|
||||
// Check if two pieces are on the same square or if a king can be captured
|
||||
// Invalid if two pieces are on the same square or if a king can be captured
|
||||
if ( distance(ksq[WHITE], ksq[BLACK]) <= 1
|
||||
|| ksq[WHITE] == psq
|
||||
|| ksq[BLACK] == psq
|
||||
|| (stm == WHITE && (pawn_attacks_bb(WHITE, psq) & ksq[BLACK])))
|
||||
result = INVALID;
|
||||
|
||||
// Immediate win if a pawn can be promoted without getting captured
|
||||
// Win if the pawn can be promoted without getting captured
|
||||
else if ( stm == WHITE
|
||||
&& rank_of(psq) == RANK_7
|
||||
&& ksq[stm] != psq + NORTH
|
||||
&& ( distance(ksq[~stm], psq + NORTH) > 1
|
||||
|| (attacks_bb<KING>(ksq[stm]) & (psq + NORTH))))
|
||||
&& ksq[WHITE] != psq + NORTH
|
||||
&& ( distance(ksq[BLACK], psq + NORTH) > 1
|
||||
|| (distance(ksq[WHITE], psq + NORTH) == 1)))
|
||||
result = WIN;
|
||||
|
||||
// Immediate draw if it is a stalemate or a king captures undefended pawn
|
||||
// Draw if it is stalemate or the black king can capture the pawn
|
||||
else if ( stm == BLACK
|
||||
&& ( !(attacks_bb<KING>(ksq[stm]) & ~(attacks_bb<KING>(ksq[~stm]) | pawn_attacks_bb(~stm, psq)))
|
||||
|| (attacks_bb<KING>(ksq[stm]) & psq & ~attacks_bb<KING>(ksq[~stm]))))
|
||||
&& ( !(attacks_bb<KING>(ksq[BLACK]) & ~(attacks_bb<KING>(ksq[WHITE]) | pawn_attacks_bb(WHITE, psq)))
|
||||
|| (attacks_bb<KING>(ksq[BLACK]) & ~attacks_bb<KING>(ksq[WHITE]) & psq)))
|
||||
result = DRAW;
|
||||
|
||||
// Position will be classified later
|
||||
|
|
|
@ -40,7 +40,7 @@ namespace {
|
|||
Bitboard RookTable[0x19000]; // To store rook attacks
|
||||
Bitboard BishopTable[0x1480]; // To store bishop attacks
|
||||
|
||||
void init_magics(Bitboard table[], Magic magics[], Direction directions[]);
|
||||
void init_magics(PieceType pt, Bitboard table[], Magic magics[]);
|
||||
}
|
||||
|
||||
|
||||
|
@ -56,8 +56,9 @@ const std::string Bitboards::pretty(Bitboard b) {
|
|||
for (File f = FILE_A; f <= FILE_H; ++f)
|
||||
s += b & make_square(f, r) ? "| X " : "| ";
|
||||
|
||||
s += "|\n+---+---+---+---+---+---+---+---+\n";
|
||||
s += "| " + std::to_string(1 + r) + "\n+---+---+---+---+---+---+---+---+\n";
|
||||
}
|
||||
s += " a b c d e f g h\n";
|
||||
|
||||
return s;
|
||||
}
|
||||
|
@ -78,11 +79,8 @@ void Bitboards::init() {
|
|||
for (Square s2 = SQ_A1; s2 <= SQ_H8; ++s2)
|
||||
SquareDistance[s1][s2] = std::max(distance<File>(s1, s2), distance<Rank>(s1, s2));
|
||||
|
||||
Direction RookDirections[] = { NORTH, EAST, SOUTH, WEST };
|
||||
Direction BishopDirections[] = { NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST };
|
||||
|
||||
init_magics(RookTable, RookMagics, RookDirections);
|
||||
init_magics(BishopTable, BishopMagics, BishopDirections);
|
||||
init_magics(ROOK, RookTable, RookMagics);
|
||||
init_magics(BISHOP, BishopTable, BishopMagics);
|
||||
|
||||
for (Square s1 = SQ_A1; s1 <= SQ_H8; ++s1)
|
||||
{
|
||||
|
@ -108,15 +106,17 @@ void Bitboards::init() {
|
|||
|
||||
namespace {
|
||||
|
||||
Bitboard sliding_attack(Direction directions[], Square sq, Bitboard occupied) {
|
||||
Bitboard sliding_attack(PieceType pt, Square sq, Bitboard occupied) {
|
||||
|
||||
Bitboard attacks = 0;
|
||||
Direction RookDirections[4] = {NORTH, SOUTH, EAST, WEST};
|
||||
Direction BishopDirections[4] = {NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST};
|
||||
|
||||
for (int i = 0; i < 4; ++i)
|
||||
for(Direction d : (pt == ROOK ? RookDirections : BishopDirections))
|
||||
{
|
||||
Square s = sq;
|
||||
while(safe_destination(s, directions[i]) && !(occupied & s))
|
||||
attacks |= (s += directions[i]);
|
||||
while(safe_destination(s, d) && !(occupied & s))
|
||||
attacks |= (s += d);
|
||||
}
|
||||
|
||||
return attacks;
|
||||
|
@ -128,7 +128,7 @@ namespace {
|
|||
// www.chessprogramming.org/Magic_Bitboards. In particular, here we use the so
|
||||
// called "fancy" approach.
|
||||
|
||||
void init_magics(Bitboard table[], Magic magics[], Direction directions[]) {
|
||||
void init_magics(PieceType pt, Bitboard table[], Magic magics[]) {
|
||||
|
||||
// Optimal PRNG seeds to pick the correct magics in the shortest time
|
||||
int seeds[][RANK_NB] = { { 8977, 44560, 54343, 38998, 5731, 95205, 104912, 17020 },
|
||||
|
@ -148,7 +148,7 @@ namespace {
|
|||
// the number of 1s of the mask. Hence we deduce the size of the shift to
|
||||
// apply to the 64 or 32 bits word to get the index.
|
||||
Magic& m = magics[s];
|
||||
m.mask = sliding_attack(directions, s, 0) & ~edges;
|
||||
m.mask = sliding_attack(pt, s, 0) & ~edges;
|
||||
m.shift = (Is64Bit ? 64 : 32) - popcount(m.mask);
|
||||
|
||||
// Set the offset for the attacks table of the square. We have individual
|
||||
|
@ -160,7 +160,7 @@ namespace {
|
|||
b = size = 0;
|
||||
do {
|
||||
occupancy[size] = b;
|
||||
reference[size] = sliding_attack(directions, s, b);
|
||||
reference[size] = sliding_attack(pt, s, b);
|
||||
|
||||
if (HasPext)
|
||||
m.attacks[pext(b, m.mask)] = reference[size];
|
||||
|
|
|
@ -200,12 +200,24 @@ inline Bitboard adjacent_files_bb(Square s) {
|
|||
return shift<EAST>(file_bb(s)) | shift<WEST>(file_bb(s));
|
||||
}
|
||||
|
||||
|
||||
/// between_bb() returns squares that are linearly between the given squares
|
||||
/// line_bb(Square, Square) returns a Bitboard representing an entire line
|
||||
/// (from board edge to board edge) that intersects the given squares.
|
||||
/// If the given squares are not on a same file/rank/diagonal, return 0.
|
||||
/// Ex. line_bb(SQ_C4, SQ_F7) returns a bitboard with the A2-G8 diagonal.
|
||||
|
||||
inline Bitboard line_bb(Square s1, Square s2) {
|
||||
|
||||
assert(is_ok(s1) && is_ok(s2));
|
||||
return LineBB[s1][s2];
|
||||
}
|
||||
|
||||
/// between_bb() returns a Bitboard representing squares that are linearly
|
||||
/// between the given squares (excluding the given squares).
|
||||
/// If the given squares are not on a same file/rank/diagonal, return 0.
|
||||
/// Ex. between_bb(SQ_C4, SQ_F7) returns a bitboard with squares D5 and E6.
|
||||
|
||||
inline Bitboard between_bb(Square s1, Square s2) {
|
||||
Bitboard b = LineBB[s1][s2] & ((AllSquares << s1) ^ (AllSquares << s2));
|
||||
Bitboard b = line_bb(s1, s2) & ((AllSquares << s1) ^ (AllSquares << s2));
|
||||
return b & (b - 1); //exclude lsb
|
||||
}
|
||||
|
||||
|
@ -241,7 +253,7 @@ inline Bitboard pawn_attack_span(Color c, Square s) {
|
|||
/// the given color and on the given square is a passed pawn.
|
||||
|
||||
inline Bitboard passed_pawn_span(Color c, Square s) {
|
||||
return forward_ranks_bb(c, s) & (adjacent_files_bb(s) | file_bb(s));
|
||||
return pawn_attack_span(c, s) | forward_file_bb(c, s);
|
||||
}
|
||||
|
||||
|
||||
|
@ -249,7 +261,7 @@ inline Bitboard passed_pawn_span(Color c, Square s) {
|
|||
/// straight or on a diagonal line.
|
||||
|
||||
inline bool aligned(Square s1, Square s2, Square s3) {
|
||||
return LineBB[s1][s2] & s3;
|
||||
return line_bb(s1, s2) & s3;
|
||||
}
|
||||
|
||||
|
||||
|
|
384
src/endgame.cpp
384
src/endgame.cpp
|
@ -28,12 +28,14 @@ namespace {
|
|||
|
||||
// Used to drive the king towards the edge of the board
|
||||
// in KX vs K and KQ vs KR endgames.
|
||||
// Values range from 27 (center squares) to 90 (in the corners)
|
||||
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.
|
||||
// Values range from 0 on A8H1 diagonal to 7 in A1H8 corners
|
||||
inline int push_to_corner(Square s) {
|
||||
return abs(7 - rank_of(s) - file_of(s));
|
||||
}
|
||||
|
@ -103,13 +105,13 @@ Value Endgame<KXK>::operator()(const Position& pos) const {
|
|||
if (pos.side_to_move() == weakSide && !MoveList<LEGAL>(pos).size())
|
||||
return VALUE_DRAW;
|
||||
|
||||
Square winnerKSq = pos.square<KING>(strongSide);
|
||||
Square loserKSq = pos.square<KING>(weakSide);
|
||||
Square strongKing = pos.square<KING>(strongSide);
|
||||
Square weakKing = pos.square<KING>(weakSide);
|
||||
|
||||
Value result = pos.non_pawn_material(strongSide)
|
||||
+ pos.count<PAWN>(strongSide) * PawnValueEg
|
||||
+ push_to_edge(loserKSq)
|
||||
+ push_close(winnerKSq, loserKSq);
|
||||
+ push_to_edge(weakKing)
|
||||
+ push_close(strongKing, weakKing);
|
||||
|
||||
if ( pos.count<QUEEN>(strongSide)
|
||||
|| pos.count<ROOK>(strongSide)
|
||||
|
@ -130,16 +132,16 @@ Value Endgame<KBNK>::operator()(const Position& pos) const {
|
|||
assert(verify_material(pos, strongSide, KnightValueMg + BishopValueMg, 0));
|
||||
assert(verify_material(pos, weakSide, VALUE_ZERO, 0));
|
||||
|
||||
Square winnerKSq = pos.square<KING>(strongSide);
|
||||
Square loserKSq = pos.square<KING>(weakSide);
|
||||
Square bishopSq = pos.square<BISHOP>(strongSide);
|
||||
Square strongKing = pos.square<KING>(strongSide);
|
||||
Square strongBishop = pos.square<BISHOP>(strongSide);
|
||||
Square weakKing = pos.square<KING>(weakSide);
|
||||
|
||||
// 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 + 3520)
|
||||
+ push_close(winnerKSq, loserKSq)
|
||||
+ 420 * push_to_corner(opposite_colors(bishopSq, SQ_A1) ? flip_file(loserKSq) : loserKSq);
|
||||
+ push_close(strongKing, weakKing)
|
||||
+ 420 * push_to_corner(opposite_colors(strongBishop, SQ_A1) ? flip_file(weakKing) : weakKing);
|
||||
|
||||
assert(abs(result) < VALUE_TB_WIN_IN_MAX_PLY);
|
||||
return strongSide == pos.side_to_move() ? result : -result;
|
||||
|
@ -154,16 +156,16 @@ Value Endgame<KPK>::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 wksq = normalize(pos, strongSide, pos.square<KING>(strongSide));
|
||||
Square bksq = normalize(pos, strongSide, pos.square<KING>(weakSide));
|
||||
Square psq = normalize(pos, strongSide, pos.square<PAWN>(strongSide));
|
||||
Square strongKing = normalize(pos, strongSide, pos.square<KING>(strongSide));
|
||||
Square strongPawn = normalize(pos, strongSide, pos.square<PAWN>(strongSide));
|
||||
Square weakKing = normalize(pos, strongSide, pos.square<KING>(weakSide));
|
||||
|
||||
Color us = strongSide == pos.side_to_move() ? WHITE : BLACK;
|
||||
|
||||
if (!Bitbases::probe(wksq, psq, bksq, us))
|
||||
if (!Bitbases::probe(strongKing, strongPawn, weakKing, us))
|
||||
return VALUE_DRAW;
|
||||
|
||||
Value result = VALUE_KNOWN_WIN + PawnValueEg + Value(rank_of(psq));
|
||||
Value result = VALUE_KNOWN_WIN + PawnValueEg + Value(rank_of(strongPawn));
|
||||
|
||||
return strongSide == pos.side_to_move() ? result : -result;
|
||||
}
|
||||
|
@ -179,36 +181,35 @@ Value Endgame<KRKP>::operator()(const Position& pos) const {
|
|||
assert(verify_material(pos, strongSide, RookValueMg, 0));
|
||||
assert(verify_material(pos, weakSide, VALUE_ZERO, 1));
|
||||
|
||||
Square wksq = relative_square(strongSide, pos.square<KING>(strongSide));
|
||||
Square bksq = relative_square(strongSide, pos.square<KING>(weakSide));
|
||||
Square rsq = relative_square(strongSide, pos.square<ROOK>(strongSide));
|
||||
Square psq = relative_square(strongSide, pos.square<PAWN>(weakSide));
|
||||
|
||||
Square queeningSq = make_square(file_of(psq), RANK_1);
|
||||
Square strongKing = relative_square(strongSide, pos.square<KING>(strongSide));
|
||||
Square weakKing = relative_square(strongSide, pos.square<KING>(weakSide));
|
||||
Square strongRook = relative_square(strongSide, pos.square<ROOK>(strongSide));
|
||||
Square weakPawn = relative_square(strongSide, pos.square<PAWN>(weakSide));
|
||||
Square queeningSquare = make_square(file_of(weakPawn), RANK_1);
|
||||
Value result;
|
||||
|
||||
// If the stronger side's king is in front of the pawn, it's a win
|
||||
if (forward_file_bb(WHITE, wksq) & psq)
|
||||
result = RookValueEg - distance(wksq, psq);
|
||||
if (forward_file_bb(WHITE, strongKing) & weakPawn)
|
||||
result = RookValueEg - distance(strongKing, weakPawn);
|
||||
|
||||
// If the weaker side's king is too far from the pawn and the rook,
|
||||
// it's a win.
|
||||
else if ( distance(bksq, psq) >= 3 + (pos.side_to_move() == weakSide)
|
||||
&& distance(bksq, rsq) >= 3)
|
||||
result = RookValueEg - distance(wksq, psq);
|
||||
else if ( distance(weakKing, weakPawn) >= 3 + (pos.side_to_move() == weakSide)
|
||||
&& distance(weakKing, strongRook) >= 3)
|
||||
result = RookValueEg - distance(strongKing, weakPawn);
|
||||
|
||||
// If the pawn is far advanced and supported by the defending king,
|
||||
// the position is drawish
|
||||
else if ( rank_of(bksq) <= RANK_3
|
||||
&& distance(bksq, psq) == 1
|
||||
&& rank_of(wksq) >= RANK_4
|
||||
&& distance(wksq, psq) > 2 + (pos.side_to_move() == strongSide))
|
||||
result = Value(80) - 8 * distance(wksq, psq);
|
||||
else if ( rank_of(weakKing) <= RANK_3
|
||||
&& distance(weakKing, weakPawn) == 1
|
||||
&& rank_of(strongKing) >= RANK_4
|
||||
&& distance(strongKing, weakPawn) > 2 + (pos.side_to_move() == strongSide))
|
||||
result = Value(80) - 8 * distance(strongKing, weakPawn);
|
||||
|
||||
else
|
||||
result = Value(200) - 8 * ( distance(wksq, psq + SOUTH)
|
||||
- distance(bksq, psq + SOUTH)
|
||||
- distance(psq, queeningSq));
|
||||
result = Value(200) - 8 * ( distance(strongKing, weakPawn + SOUTH)
|
||||
- distance(weakKing, weakPawn + SOUTH)
|
||||
- distance(weakPawn, queeningSquare));
|
||||
|
||||
return strongSide == pos.side_to_move() ? result : -result;
|
||||
}
|
||||
|
@ -235,9 +236,9 @@ Value Endgame<KRKN>::operator()(const Position& pos) const {
|
|||
assert(verify_material(pos, strongSide, RookValueMg, 0));
|
||||
assert(verify_material(pos, weakSide, KnightValueMg, 0));
|
||||
|
||||
Square bksq = pos.square<KING>(weakSide);
|
||||
Square bnsq = pos.square<KNIGHT>(weakSide);
|
||||
Value result = Value(push_to_edge(bksq) + push_away(bksq, bnsq));
|
||||
Square weakKing = pos.square<KING>(weakSide);
|
||||
Square weakKnight = pos.square<KNIGHT>(weakSide);
|
||||
Value result = Value(push_to_edge(weakKing) + push_away(weakKing, weakKnight));
|
||||
return strongSide == pos.side_to_move() ? result : -result;
|
||||
}
|
||||
|
||||
|
@ -252,15 +253,15 @@ Value Endgame<KQKP>::operator()(const Position& pos) const {
|
|||
assert(verify_material(pos, strongSide, QueenValueMg, 0));
|
||||
assert(verify_material(pos, weakSide, VALUE_ZERO, 1));
|
||||
|
||||
Square winnerKSq = pos.square<KING>(strongSide);
|
||||
Square loserKSq = pos.square<KING>(weakSide);
|
||||
Square pawnSq = pos.square<PAWN>(weakSide);
|
||||
Square strongKing = pos.square<KING>(strongSide);
|
||||
Square weakKing = pos.square<KING>(weakSide);
|
||||
Square weakPawn = pos.square<PAWN>(weakSide);
|
||||
|
||||
Value result = Value(push_close(winnerKSq, loserKSq));
|
||||
Value result = Value(push_close(strongKing, weakKing));
|
||||
|
||||
if ( relative_rank(weakSide, pawnSq) != RANK_7
|
||||
|| distance(loserKSq, pawnSq) != 1
|
||||
|| ((FileBBB | FileDBB | FileEBB | FileGBB) & pawnSq))
|
||||
if ( relative_rank(weakSide, weakPawn) != RANK_7
|
||||
|| distance(weakKing, weakPawn) != 1
|
||||
|| ((FileBBB | FileDBB | FileEBB | FileGBB) & weakPawn))
|
||||
result += QueenValueEg - PawnValueEg;
|
||||
|
||||
return strongSide == pos.side_to_move() ? result : -result;
|
||||
|
@ -277,13 +278,13 @@ Value Endgame<KQKR>::operator()(const Position& pos) const {
|
|||
assert(verify_material(pos, strongSide, QueenValueMg, 0));
|
||||
assert(verify_material(pos, weakSide, RookValueMg, 0));
|
||||
|
||||
Square winnerKSq = pos.square<KING>(strongSide);
|
||||
Square loserKSq = pos.square<KING>(weakSide);
|
||||
Square strongKing = pos.square<KING>(strongSide);
|
||||
Square weakKing = pos.square<KING>(weakSide);
|
||||
|
||||
Value result = QueenValueEg
|
||||
- RookValueEg
|
||||
+ push_to_edge(loserKSq)
|
||||
+ push_close(winnerKSq, loserKSq);
|
||||
+ push_to_edge(weakKing)
|
||||
+ push_close(strongKing, weakKing);
|
||||
|
||||
return strongSide == pos.side_to_move() ? result : -result;
|
||||
}
|
||||
|
@ -297,9 +298,12 @@ Value Endgame<KNNKP>::operator()(const Position& pos) const {
|
|||
assert(verify_material(pos, strongSide, 2 * KnightValueMg, 0));
|
||||
assert(verify_material(pos, weakSide, VALUE_ZERO, 1));
|
||||
|
||||
Square weakKing = pos.square<KING>(weakSide);
|
||||
Square weakPawn = pos.square<PAWN>(weakSide);
|
||||
|
||||
Value result = PawnValueEg
|
||||
+ 2 * push_to_edge(pos.square<KING>(weakSide))
|
||||
- 10 * relative_rank(weakSide, pos.square<PAWN>(weakSide));
|
||||
+ 2 * push_to_edge(weakKing)
|
||||
- 10 * relative_rank(weakSide, weakPawn);
|
||||
|
||||
return strongSide == pos.side_to_move() ? result : -result;
|
||||
}
|
||||
|
@ -325,15 +329,17 @@ ScaleFactor Endgame<KBPsK>::operator()(const Position& pos) const {
|
|||
Bitboard strongPawns = pos.pieces(strongSide, PAWN);
|
||||
Bitboard allPawns = pos.pieces(PAWN);
|
||||
|
||||
Square strongBishop = pos.square<BISHOP>(strongSide);
|
||||
Square weakKing = pos.square<KING>(weakSide);
|
||||
Square strongKing = pos.square<KING>(strongSide);
|
||||
|
||||
// All strongSide pawns are on a single rook file?
|
||||
if (!(strongPawns & ~FileABB) || !(strongPawns & ~FileHBB))
|
||||
{
|
||||
Square bishopSq = pos.square<BISHOP>(strongSide);
|
||||
Square queeningSq = relative_square(strongSide, make_square(file_of(lsb(strongPawns)), RANK_8));
|
||||
Square weakKingSq = pos.square<KING>(weakSide);
|
||||
Square queeningSquare = relative_square(strongSide, make_square(file_of(lsb(strongPawns)), RANK_8));
|
||||
|
||||
if ( opposite_colors(queeningSq, bishopSq)
|
||||
&& distance(queeningSq, weakKingSq) <= 1)
|
||||
if ( opposite_colors(queeningSquare, strongBishop)
|
||||
&& distance(queeningSquare, weakKing) <= 1)
|
||||
return SCALE_FACTOR_DRAW;
|
||||
}
|
||||
|
||||
|
@ -343,20 +349,16 @@ ScaleFactor Endgame<KBPsK>::operator()(const Position& pos) const {
|
|||
&& pos.count<PAWN>(weakSide) >= 1)
|
||||
{
|
||||
// Get the least advanced weakSide pawn
|
||||
Square weakPawnSq = frontmost_sq(strongSide, pos.pieces(weakSide, PAWN));
|
||||
|
||||
Square strongKingSq = pos.square<KING>(strongSide);
|
||||
Square weakKingSq = pos.square<KING>(weakSide);
|
||||
Square bishopSq = pos.square<BISHOP>(strongSide);
|
||||
Square weakPawn = frontmost_sq(strongSide, pos.pieces(weakSide, PAWN));
|
||||
|
||||
// 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)))
|
||||
if ( relative_rank(strongSide, weakPawn) == RANK_7
|
||||
&& (strongPawns & (weakPawn + pawn_push(weakSide)))
|
||||
&& (opposite_colors(strongBishop, weakPawn) || !more_than_one(strongPawns)))
|
||||
{
|
||||
int strongKingDist = distance(weakPawnSq, strongKingSq);
|
||||
int weakKingDist = distance(weakPawnSq, weakKingSq);
|
||||
int strongKingDist = distance(weakPawn, strongKing);
|
||||
int weakKingDist = distance(weakPawn, weakKing);
|
||||
|
||||
// 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
|
||||
|
@ -364,7 +366,7 @@ ScaleFactor Endgame<KBPsK>::operator()(const Position& pos) const {
|
|||
// unreachable positions such as 5k1K/6p1/6P1/8/8/3B4/8/8 w
|
||||
// and positions where qsearch will immediately correct the
|
||||
// problem such as 8/4k1p1/6P1/1K6/3B4/8/8/8 w)
|
||||
if ( relative_rank(strongSide, weakKingSq) >= RANK_7
|
||||
if ( relative_rank(strongSide, weakKing) >= RANK_7
|
||||
&& weakKingDist <= 2
|
||||
&& weakKingDist <= strongKingDist)
|
||||
return SCALE_FACTOR_DRAW;
|
||||
|
@ -384,15 +386,16 @@ ScaleFactor Endgame<KQKRPs>::operator()(const Position& pos) const {
|
|||
assert(pos.count<ROOK>(weakSide) == 1);
|
||||
assert(pos.count<PAWN>(weakSide) >= 1);
|
||||
|
||||
Square kingSq = pos.square<KING>(weakSide);
|
||||
Square rsq = pos.square<ROOK>(weakSide);
|
||||
Square strongKing = pos.square<KING>(strongSide);
|
||||
Square weakKing = pos.square<KING>(weakSide);
|
||||
Square weakRook = pos.square<ROOK>(weakSide);
|
||||
|
||||
if ( relative_rank(weakSide, kingSq) <= RANK_2
|
||||
&& relative_rank(weakSide, pos.square<KING>(strongSide)) >= RANK_4
|
||||
&& relative_rank(weakSide, rsq) == RANK_3
|
||||
if ( relative_rank(weakSide, weakKing) <= RANK_2
|
||||
&& relative_rank(weakSide, strongKing) >= RANK_4
|
||||
&& relative_rank(weakSide, weakRook) == RANK_3
|
||||
&& ( pos.pieces(weakSide, PAWN)
|
||||
& attacks_bb<KING>(kingSq)
|
||||
& pawn_attacks_bb(strongSide, rsq)))
|
||||
& attacks_bb<KING>(weakKing)
|
||||
& pawn_attacks_bb(strongSide, weakRook)))
|
||||
return SCALE_FACTOR_DRAW;
|
||||
|
||||
return SCALE_FACTOR_NONE;
|
||||
|
@ -412,89 +415,89 @@ ScaleFactor Endgame<KRPKR>::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 wksq = normalize(pos, strongSide, pos.square<KING>(strongSide));
|
||||
Square bksq = normalize(pos, strongSide, pos.square<KING>(weakSide));
|
||||
Square wrsq = normalize(pos, strongSide, pos.square<ROOK>(strongSide));
|
||||
Square wpsq = normalize(pos, strongSide, pos.square<PAWN>(strongSide));
|
||||
Square brsq = normalize(pos, strongSide, pos.square<ROOK>(weakSide));
|
||||
Square strongKing = normalize(pos, strongSide, pos.square<KING>(strongSide));
|
||||
Square strongRook = normalize(pos, strongSide, pos.square<ROOK>(strongSide));
|
||||
Square strongPawn = normalize(pos, strongSide, pos.square<PAWN>(strongSide));
|
||||
Square weakKing = normalize(pos, strongSide, pos.square<KING>(weakSide));
|
||||
Square weakRook = normalize(pos, strongSide, pos.square<ROOK>(weakSide));
|
||||
|
||||
File f = file_of(wpsq);
|
||||
Rank r = rank_of(wpsq);
|
||||
Square queeningSq = make_square(f, RANK_8);
|
||||
File pawnFile = file_of(strongPawn);
|
||||
Rank pawnRank = rank_of(strongPawn);
|
||||
Square queeningSquare = make_square(pawnFile, RANK_8);
|
||||
int tempo = (pos.side_to_move() == strongSide);
|
||||
|
||||
// If the pawn is not too far advanced and the defending king defends the
|
||||
// queening square, use the third-rank defence.
|
||||
if ( r <= RANK_5
|
||||
&& distance(bksq, queeningSq) <= 1
|
||||
&& wksq <= SQ_H5
|
||||
&& (rank_of(brsq) == RANK_6 || (r <= RANK_3 && rank_of(wrsq) != RANK_6)))
|
||||
if ( pawnRank <= RANK_5
|
||||
&& distance(weakKing, queeningSquare) <= 1
|
||||
&& strongKing <= SQ_H5
|
||||
&& (rank_of(weakRook) == RANK_6 || (pawnRank <= RANK_3 && rank_of(strongRook) != RANK_6)))
|
||||
return SCALE_FACTOR_DRAW;
|
||||
|
||||
// The defending side saves a draw by checking from behind in case the pawn
|
||||
// has advanced to the 6th rank with the king behind.
|
||||
if ( r == RANK_6
|
||||
&& distance(bksq, queeningSq) <= 1
|
||||
&& rank_of(wksq) + tempo <= RANK_6
|
||||
&& (rank_of(brsq) == RANK_1 || (!tempo && distance<File>(brsq, wpsq) >= 3)))
|
||||
if ( pawnRank == RANK_6
|
||||
&& distance(weakKing, queeningSquare) <= 1
|
||||
&& rank_of(strongKing) + tempo <= RANK_6
|
||||
&& (rank_of(weakRook) == RANK_1 || (!tempo && distance<File>(weakRook, strongPawn) >= 3)))
|
||||
return SCALE_FACTOR_DRAW;
|
||||
|
||||
if ( r >= RANK_6
|
||||
&& bksq == queeningSq
|
||||
&& rank_of(brsq) == RANK_1
|
||||
&& (!tempo || distance(wksq, wpsq) >= 2))
|
||||
if ( pawnRank >= RANK_6
|
||||
&& weakKing == queeningSquare
|
||||
&& rank_of(weakRook) == RANK_1
|
||||
&& (!tempo || distance(strongKing, strongPawn) >= 2))
|
||||
return SCALE_FACTOR_DRAW;
|
||||
|
||||
// White pawn on a7 and rook on a8 is a draw if black's king is on g7 or h7
|
||||
// and the black rook is behind the pawn.
|
||||
if ( wpsq == SQ_A7
|
||||
&& wrsq == SQ_A8
|
||||
&& (bksq == SQ_H7 || bksq == SQ_G7)
|
||||
&& file_of(brsq) == FILE_A
|
||||
&& (rank_of(brsq) <= RANK_3 || file_of(wksq) >= FILE_D || rank_of(wksq) <= RANK_5))
|
||||
if ( strongPawn == SQ_A7
|
||||
&& strongRook == SQ_A8
|
||||
&& (weakKing == SQ_H7 || weakKing == SQ_G7)
|
||||
&& file_of(weakRook) == FILE_A
|
||||
&& (rank_of(weakRook) <= RANK_3 || file_of(strongKing) >= FILE_D || rank_of(strongKing) <= RANK_5))
|
||||
return SCALE_FACTOR_DRAW;
|
||||
|
||||
// If the defending king blocks the pawn and the attacking king is too far
|
||||
// away, it's a draw.
|
||||
if ( r <= RANK_5
|
||||
&& bksq == wpsq + NORTH
|
||||
&& distance(wksq, wpsq) - tempo >= 2
|
||||
&& distance(wksq, brsq) - tempo >= 2)
|
||||
if ( pawnRank <= RANK_5
|
||||
&& weakKing == strongPawn + NORTH
|
||||
&& distance(strongKing, strongPawn) - tempo >= 2
|
||||
&& distance(strongKing, weakRook) - tempo >= 2)
|
||||
return SCALE_FACTOR_DRAW;
|
||||
|
||||
// Pawn on the 7th rank supported by the rook from behind usually wins if the
|
||||
// attacking king is closer to the queening square than the defending king,
|
||||
// and the defending king cannot gain tempi by threatening the attacking rook.
|
||||
if ( r == RANK_7
|
||||
&& f != FILE_A
|
||||
&& file_of(wrsq) == f
|
||||
&& wrsq != queeningSq
|
||||
&& (distance(wksq, queeningSq) < distance(bksq, queeningSq) - 2 + tempo)
|
||||
&& (distance(wksq, queeningSq) < distance(bksq, wrsq) + tempo))
|
||||
return ScaleFactor(SCALE_FACTOR_MAX - 2 * distance(wksq, queeningSq));
|
||||
if ( pawnRank == RANK_7
|
||||
&& pawnFile != FILE_A
|
||||
&& file_of(strongRook) == pawnFile
|
||||
&& strongRook != queeningSquare
|
||||
&& (distance(strongKing, queeningSquare) < distance(weakKing, queeningSquare) - 2 + tempo)
|
||||
&& (distance(strongKing, queeningSquare) < distance(weakKing, strongRook) + tempo))
|
||||
return ScaleFactor(SCALE_FACTOR_MAX - 2 * distance(strongKing, queeningSquare));
|
||||
|
||||
// Similar to the above, but with the pawn further back
|
||||
if ( f != FILE_A
|
||||
&& file_of(wrsq) == f
|
||||
&& wrsq < wpsq
|
||||
&& (distance(wksq, queeningSq) < distance(bksq, queeningSq) - 2 + tempo)
|
||||
&& (distance(wksq, wpsq + NORTH) < distance(bksq, wpsq + NORTH) - 2 + tempo)
|
||||
&& ( distance(bksq, wrsq) + tempo >= 3
|
||||
|| ( distance(wksq, queeningSq) < distance(bksq, wrsq) + tempo
|
||||
&& (distance(wksq, wpsq + NORTH) < distance(bksq, wrsq) + tempo))))
|
||||
if ( pawnFile != FILE_A
|
||||
&& file_of(strongRook) == pawnFile
|
||||
&& strongRook < strongPawn
|
||||
&& (distance(strongKing, queeningSquare) < distance(weakKing, queeningSquare) - 2 + tempo)
|
||||
&& (distance(strongKing, strongPawn + NORTH) < distance(weakKing, strongPawn + NORTH) - 2 + tempo)
|
||||
&& ( distance(weakKing, strongRook) + tempo >= 3
|
||||
|| ( distance(strongKing, queeningSquare) < distance(weakKing, strongRook) + tempo
|
||||
&& (distance(strongKing, strongPawn + NORTH) < distance(weakKing, strongPawn) + tempo))))
|
||||
return ScaleFactor( SCALE_FACTOR_MAX
|
||||
- 8 * distance(wpsq, queeningSq)
|
||||
- 2 * distance(wksq, queeningSq));
|
||||
- 8 * distance(strongPawn, queeningSquare)
|
||||
- 2 * distance(strongKing, queeningSquare));
|
||||
|
||||
// If the pawn is not far advanced and the defending king is somewhere in
|
||||
// the pawn's path, it's probably a draw.
|
||||
if (r <= RANK_4 && bksq > wpsq)
|
||||
if (pawnRank <= RANK_4 && weakKing > strongPawn)
|
||||
{
|
||||
if (file_of(bksq) == file_of(wpsq))
|
||||
if (file_of(weakKing) == file_of(strongPawn))
|
||||
return ScaleFactor(10);
|
||||
if ( distance<File>(bksq, wpsq) == 1
|
||||
&& distance(wksq, bksq) > 2)
|
||||
return ScaleFactor(24 - 2 * distance(wksq, bksq));
|
||||
if ( distance<File>(weakKing, strongPawn) == 1
|
||||
&& distance(strongKing, weakKing) > 2)
|
||||
return ScaleFactor(24 - 2 * distance(strongKing, weakKing));
|
||||
}
|
||||
return SCALE_FACTOR_NONE;
|
||||
}
|
||||
|
@ -508,10 +511,11 @@ ScaleFactor Endgame<KRPKB>::operator()(const Position& pos) const {
|
|||
// Test for a rook pawn
|
||||
if (pos.pieces(PAWN) & (FileABB | FileHBB))
|
||||
{
|
||||
Square ksq = pos.square<KING>(weakSide);
|
||||
Square bsq = pos.square<BISHOP>(weakSide);
|
||||
Square psq = pos.square<PAWN>(strongSide);
|
||||
Rank rk = relative_rank(strongSide, psq);
|
||||
Square weakKing = pos.square<KING>(weakSide);
|
||||
Square weakBishop = pos.square<BISHOP>(weakSide);
|
||||
Square strongKing = pos.square<KING>(strongSide);
|
||||
Square strongPawn = pos.square<PAWN>(strongSide);
|
||||
Rank pawnRank = relative_rank(strongSide, strongPawn);
|
||||
Direction push = pawn_push(strongSide);
|
||||
|
||||
// If the pawn is on the 5th rank and the pawn (currently) is on
|
||||
|
@ -519,11 +523,11 @@ ScaleFactor Endgame<KRPKB>::operator()(const Position& pos) const {
|
|||
// a fortress. Depending on the king position give a moderate
|
||||
// reduction or a stronger one if the defending king is near the
|
||||
// corner but not trapped there.
|
||||
if (rk == RANK_5 && !opposite_colors(bsq, psq))
|
||||
if (pawnRank == RANK_5 && !opposite_colors(weakBishop, strongPawn))
|
||||
{
|
||||
int d = distance(psq + 3 * push, ksq);
|
||||
int d = distance(strongPawn + 3 * push, weakKing);
|
||||
|
||||
if (d <= 2 && !(d == 0 && ksq == pos.square<KING>(strongSide) + 2 * push))
|
||||
if (d <= 2 && !(d == 0 && weakKing == strongKing + 2 * push))
|
||||
return ScaleFactor(24);
|
||||
else
|
||||
return ScaleFactor(48);
|
||||
|
@ -533,10 +537,10 @@ ScaleFactor Endgame<KRPKB>::operator()(const Position& pos) const {
|
|||
// it's drawn if the bishop attacks the square in front of the
|
||||
// pawn from a reasonable distance and the defending king is near
|
||||
// the corner
|
||||
if ( rk == RANK_6
|
||||
&& distance(psq + 2 * push, ksq) <= 1
|
||||
&& (attacks_bb<BISHOP>(bsq) & (psq + push))
|
||||
&& distance<File>(bsq, psq) >= 2)
|
||||
if ( pawnRank == RANK_6
|
||||
&& distance(strongPawn + 2 * push, weakKing) <= 1
|
||||
&& (attacks_bb<BISHOP>(weakBishop) & (strongPawn + push))
|
||||
&& distance<File>(weakBishop, strongPawn) >= 2)
|
||||
return ScaleFactor(8);
|
||||
}
|
||||
|
||||
|
@ -551,22 +555,22 @@ ScaleFactor Endgame<KRPPKRP>::operator()(const Position& pos) const {
|
|||
assert(verify_material(pos, strongSide, RookValueMg, 2));
|
||||
assert(verify_material(pos, weakSide, RookValueMg, 1));
|
||||
|
||||
Square wpsq1 = pos.squares<PAWN>(strongSide)[0];
|
||||
Square wpsq2 = pos.squares<PAWN>(strongSide)[1];
|
||||
Square bksq = pos.square<KING>(weakSide);
|
||||
Square strongPawn1 = pos.squares<PAWN>(strongSide)[0];
|
||||
Square strongPawn2 = pos.squares<PAWN>(strongSide)[1];
|
||||
Square weakKing = pos.square<KING>(weakSide);
|
||||
|
||||
// Does the stronger side have a passed pawn?
|
||||
if (pos.pawn_passed(strongSide, wpsq1) || pos.pawn_passed(strongSide, wpsq2))
|
||||
if (pos.pawn_passed(strongSide, strongPawn1) || pos.pawn_passed(strongSide, strongPawn2))
|
||||
return SCALE_FACTOR_NONE;
|
||||
|
||||
Rank r = std::max(relative_rank(strongSide, wpsq1), relative_rank(strongSide, wpsq2));
|
||||
Rank pawnRank = std::max(relative_rank(strongSide, strongPawn1), relative_rank(strongSide, strongPawn2));
|
||||
|
||||
if ( distance<File>(bksq, wpsq1) <= 1
|
||||
&& distance<File>(bksq, wpsq2) <= 1
|
||||
&& relative_rank(strongSide, bksq) > r)
|
||||
if ( distance<File>(weakKing, strongPawn1) <= 1
|
||||
&& distance<File>(weakKing, strongPawn2) <= 1
|
||||
&& relative_rank(strongSide, weakKing) > pawnRank)
|
||||
{
|
||||
assert(r > RANK_1 && r < RANK_7);
|
||||
return ScaleFactor(7 * r);
|
||||
assert(pawnRank > RANK_1 && pawnRank < RANK_7);
|
||||
return ScaleFactor(7 * pawnRank);
|
||||
}
|
||||
return SCALE_FACTOR_NONE;
|
||||
}
|
||||
|
@ -581,12 +585,12 @@ ScaleFactor Endgame<KPsK>::operator()(const Position& pos) const {
|
|||
assert(pos.count<PAWN>(strongSide) >= 2);
|
||||
assert(verify_material(pos, weakSide, VALUE_ZERO, 0));
|
||||
|
||||
Square ksq = pos.square<KING>(weakSide);
|
||||
Bitboard pawns = pos.pieces(strongSide, PAWN);
|
||||
Square weakKing = pos.square<KING>(weakSide);
|
||||
Bitboard strongPawns = pos.pieces(strongSide, PAWN);
|
||||
|
||||
// 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)))
|
||||
if (!((strongPawns & ~FileABB) || (strongPawns & ~FileHBB)) &&
|
||||
!(strongPawns & ~passed_pawn_span(weakSide, weakKing)))
|
||||
return SCALE_FACTOR_DRAW;
|
||||
|
||||
return SCALE_FACTOR_NONE;
|
||||
|
@ -603,19 +607,19 @@ ScaleFactor Endgame<KBPKB>::operator()(const Position& pos) const {
|
|||
assert(verify_material(pos, strongSide, BishopValueMg, 1));
|
||||
assert(verify_material(pos, weakSide, BishopValueMg, 0));
|
||||
|
||||
Square pawnSq = pos.square<PAWN>(strongSide);
|
||||
Square strongBishopSq = pos.square<BISHOP>(strongSide);
|
||||
Square weakBishopSq = pos.square<BISHOP>(weakSide);
|
||||
Square weakKingSq = pos.square<KING>(weakSide);
|
||||
Square strongPawn = pos.square<PAWN>(strongSide);
|
||||
Square strongBishop = pos.square<BISHOP>(strongSide);
|
||||
Square weakBishop = pos.square<BISHOP>(weakSide);
|
||||
Square weakKing = pos.square<KING>(weakSide);
|
||||
|
||||
// Case 1: Defending king blocks the pawn, and cannot be driven away
|
||||
if ( (forward_file_bb(strongSide, pawnSq) & weakKingSq)
|
||||
&& ( opposite_colors(weakKingSq, strongBishopSq)
|
||||
|| relative_rank(strongSide, weakKingSq) <= RANK_6))
|
||||
if ( (forward_file_bb(strongSide, strongPawn) & weakKing)
|
||||
&& ( opposite_colors(weakKing, strongBishop)
|
||||
|| relative_rank(strongSide, weakKing) <= RANK_6))
|
||||
return SCALE_FACTOR_DRAW;
|
||||
|
||||
// Case 2: Opposite colored bishops
|
||||
if (opposite_colors(strongBishopSq, weakBishopSq))
|
||||
if (opposite_colors(strongBishop, weakBishop))
|
||||
return SCALE_FACTOR_DRAW;
|
||||
|
||||
return SCALE_FACTOR_NONE;
|
||||
|
@ -629,36 +633,36 @@ ScaleFactor Endgame<KBPPKB>::operator()(const Position& pos) const {
|
|||
assert(verify_material(pos, strongSide, BishopValueMg, 2));
|
||||
assert(verify_material(pos, weakSide, BishopValueMg, 0));
|
||||
|
||||
Square wbsq = pos.square<BISHOP>(strongSide);
|
||||
Square bbsq = pos.square<BISHOP>(weakSide);
|
||||
Square strongBishop = pos.square<BISHOP>(strongSide);
|
||||
Square weakBishop = pos.square<BISHOP>(weakSide);
|
||||
|
||||
if (!opposite_colors(wbsq, bbsq))
|
||||
if (!opposite_colors(strongBishop, weakBishop))
|
||||
return SCALE_FACTOR_NONE;
|
||||
|
||||
Square ksq = pos.square<KING>(weakSide);
|
||||
Square psq1 = pos.squares<PAWN>(strongSide)[0];
|
||||
Square psq2 = pos.squares<PAWN>(strongSide)[1];
|
||||
Square weakKing = pos.square<KING>(weakSide);
|
||||
Square strongPawn1 = pos.squares<PAWN>(strongSide)[0];
|
||||
Square strongPawn2 = pos.squares<PAWN>(strongSide)[1];
|
||||
Square blockSq1, blockSq2;
|
||||
|
||||
if (relative_rank(strongSide, psq1) > relative_rank(strongSide, psq2))
|
||||
if (relative_rank(strongSide, strongPawn1) > relative_rank(strongSide, strongPawn2))
|
||||
{
|
||||
blockSq1 = psq1 + pawn_push(strongSide);
|
||||
blockSq2 = make_square(file_of(psq2), rank_of(psq1));
|
||||
blockSq1 = strongPawn1 + pawn_push(strongSide);
|
||||
blockSq2 = make_square(file_of(strongPawn2), rank_of(strongPawn1));
|
||||
}
|
||||
else
|
||||
{
|
||||
blockSq1 = psq2 + pawn_push(strongSide);
|
||||
blockSq2 = make_square(file_of(psq1), rank_of(psq2));
|
||||
blockSq1 = strongPawn2 + pawn_push(strongSide);
|
||||
blockSq2 = make_square(file_of(strongPawn1), rank_of(strongPawn2));
|
||||
}
|
||||
|
||||
switch (distance<File>(psq1, psq2))
|
||||
switch (distance<File>(strongPawn1, strongPawn2))
|
||||
{
|
||||
case 0:
|
||||
// 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))
|
||||
if ( file_of(weakKing) == file_of(blockSq1)
|
||||
&& relative_rank(strongSide, weakKing) >= relative_rank(strongSide, blockSq1)
|
||||
&& opposite_colors(weakKing, strongBishop))
|
||||
return SCALE_FACTOR_DRAW;
|
||||
else
|
||||
return SCALE_FACTOR_NONE;
|
||||
|
@ -667,16 +671,16 @@ ScaleFactor Endgame<KBPPKB>::operator()(const Position& pos) const {
|
|||
// 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
|
||||
if ( weakKing == blockSq1
|
||||
&& opposite_colors(weakKing, strongBishop)
|
||||
&& ( weakBishop == blockSq2
|
||||
|| (attacks_bb<BISHOP>(blockSq2, pos.pieces()) & pos.pieces(weakSide, BISHOP))
|
||||
|| distance<Rank>(psq1, psq2) >= 2))
|
||||
|| distance<Rank>(strongPawn1, strongPawn2) >= 2))
|
||||
return SCALE_FACTOR_DRAW;
|
||||
|
||||
else if ( ksq == blockSq2
|
||||
&& opposite_colors(ksq, wbsq)
|
||||
&& ( bbsq == blockSq1
|
||||
else if ( weakKing == blockSq2
|
||||
&& opposite_colors(weakKing, strongBishop)
|
||||
&& ( weakBishop == blockSq1
|
||||
|| (attacks_bb<BISHOP>(blockSq1, pos.pieces()) & pos.pieces(weakSide, BISHOP))))
|
||||
return SCALE_FACTOR_DRAW;
|
||||
else
|
||||
|
@ -698,14 +702,14 @@ ScaleFactor Endgame<KBPKN>::operator()(const Position& pos) const {
|
|||
assert(verify_material(pos, strongSide, BishopValueMg, 1));
|
||||
assert(verify_material(pos, weakSide, KnightValueMg, 0));
|
||||
|
||||
Square pawnSq = pos.square<PAWN>(strongSide);
|
||||
Square strongBishopSq = pos.square<BISHOP>(strongSide);
|
||||
Square weakKingSq = pos.square<KING>(weakSide);
|
||||
Square strongPawn = pos.square<PAWN>(strongSide);
|
||||
Square strongBishop = pos.square<BISHOP>(strongSide);
|
||||
Square weakKing = pos.square<KING>(weakSide);
|
||||
|
||||
if ( file_of(weakKingSq) == file_of(pawnSq)
|
||||
&& relative_rank(strongSide, pawnSq) < relative_rank(strongSide, weakKingSq)
|
||||
&& ( opposite_colors(weakKingSq, strongBishopSq)
|
||||
|| relative_rank(strongSide, weakKingSq) <= RANK_6))
|
||||
if ( file_of(weakKing) == file_of(strongPawn)
|
||||
&& relative_rank(strongSide, strongPawn) < relative_rank(strongSide, weakKing)
|
||||
&& ( opposite_colors(weakKing, strongBishop)
|
||||
|| relative_rank(strongSide, weakKing) <= RANK_6))
|
||||
return SCALE_FACTOR_DRAW;
|
||||
|
||||
return SCALE_FACTOR_NONE;
|
||||
|
@ -724,18 +728,18 @@ ScaleFactor Endgame<KPKP>::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 wksq = normalize(pos, strongSide, pos.square<KING>(strongSide));
|
||||
Square bksq = normalize(pos, strongSide, pos.square<KING>(weakSide));
|
||||
Square psq = normalize(pos, strongSide, pos.square<PAWN>(strongSide));
|
||||
Square strongKing = normalize(pos, strongSide, pos.square<KING>(strongSide));
|
||||
Square weakKing = normalize(pos, strongSide, pos.square<KING>(weakSide));
|
||||
Square strongPawn = normalize(pos, strongSide, pos.square<PAWN>(strongSide));
|
||||
|
||||
Color us = strongSide == pos.side_to_move() ? WHITE : BLACK;
|
||||
|
||||
// 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(psq) >= RANK_5 && file_of(psq) != FILE_A)
|
||||
if (rank_of(strongPawn) >= RANK_5 && file_of(strongPawn) != 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(wksq, psq, bksq, us) ? SCALE_FACTOR_NONE : SCALE_FACTOR_DRAW;
|
||||
return Bitbases::probe(strongKing, strongPawn, weakKing, us) ? SCALE_FACTOR_NONE : SCALE_FACTOR_DRAW;
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ namespace Trace {
|
|||
enum Tracing { NO_TRACE, TRACE };
|
||||
|
||||
enum Term { // The first 8 entries are reserved for PieceType
|
||||
MATERIAL = 8, IMBALANCE, MOBILITY, THREAT, PASSED, SPACE, INITIATIVE, TOTAL, TERM_NB
|
||||
MATERIAL = 8, IMBALANCE, MOBILITY, THREAT, PASSED, SPACE, WINNABLE, TOTAL, TERM_NB
|
||||
};
|
||||
|
||||
Score scores[TERM_NB][COLOR_NB];
|
||||
|
@ -61,7 +61,7 @@ namespace Trace {
|
|||
|
||||
std::ostream& operator<<(std::ostream& os, Term t) {
|
||||
|
||||
if (t == MATERIAL || t == IMBALANCE || t == INITIATIVE || t == TOTAL)
|
||||
if (t == MATERIAL || t == IMBALANCE || t == WINNABLE || t == TOTAL)
|
||||
os << " ---- ----" << " | " << " ---- ----";
|
||||
else
|
||||
os << scores[t][WHITE] << " | " << scores[t][BLACK];
|
||||
|
@ -145,16 +145,17 @@ namespace {
|
|||
constexpr Score ReachableOutpost = S( 31, 22);
|
||||
constexpr Score PassedFile = S( 11, 8);
|
||||
constexpr Score PawnlessFlank = S( 17, 95);
|
||||
constexpr Score QueenInfiltration = S( -2, 14);
|
||||
constexpr Score RestrictedPiece = S( 7, 7);
|
||||
constexpr Score RookOnKingRing = S( 16, 0);
|
||||
constexpr Score RookOnQueenFile = S( 5, 9);
|
||||
constexpr Score SliderOnQueen = S( 59, 18);
|
||||
constexpr Score RookOnQueenFile = S( 6, 11);
|
||||
constexpr Score SliderOnQueen = S( 60, 18);
|
||||
constexpr Score ThreatByKing = S( 24, 89);
|
||||
constexpr Score ThreatByPawnPush = S( 48, 39);
|
||||
constexpr Score ThreatBySafePawn = S(173, 94);
|
||||
constexpr Score TrappedRook = S( 55, 13);
|
||||
constexpr Score WeakQueen = S( 51, 14);
|
||||
constexpr Score WeakQueenProtection = S( 15, 0);
|
||||
constexpr Score WeakQueen = S( 56, 15);
|
||||
constexpr Score WeakQueenProtection = S( 14, 0);
|
||||
|
||||
#undef S
|
||||
|
||||
|
@ -175,8 +176,7 @@ namespace {
|
|||
template<Color Us> Score threats() const;
|
||||
template<Color Us> Score passed() const;
|
||||
template<Color Us> Score space() const;
|
||||
ScaleFactor scale_factor(Value eg) const;
|
||||
Score initiative(Score score) const;
|
||||
Value winnable(Score score) const;
|
||||
|
||||
const Position& pos;
|
||||
Material::Entry* me;
|
||||
|
@ -279,7 +279,7 @@ namespace {
|
|||
: attacks_bb<Pt>(s, pos.pieces());
|
||||
|
||||
if (pos.blockers_for_king(Us) & s)
|
||||
b &= LineBB[pos.square<KING>(Us)][s];
|
||||
b &= line_bb(pos.square<KING>(Us), s);
|
||||
|
||||
attackedBy2[Us] |= attackedBy[Us][ALL_PIECES] & b;
|
||||
attackedBy[Us][Pt] |= b;
|
||||
|
@ -376,6 +376,10 @@ namespace {
|
|||
Bitboard queenPinners;
|
||||
if (pos.slider_blockers(pos.pieces(Them, ROOK, BISHOP), s, queenPinners))
|
||||
score -= WeakQueen;
|
||||
|
||||
// Bonus for queen on weak square in enemy camp
|
||||
if (relative_rank(Us, s) > RANK_4 && (~pe->pawn_attacks_span(Them) & s))
|
||||
score += QueenInfiltration;
|
||||
}
|
||||
}
|
||||
if (T)
|
||||
|
@ -679,16 +683,15 @@ namespace {
|
|||
}
|
||||
|
||||
|
||||
// Evaluation::space() computes the space evaluation for a given side. The
|
||||
// space evaluation is a simple bonus based on the number of safe squares
|
||||
// available for minor pieces on the central four files on ranks 2--4. Safe
|
||||
// squares one, two or three squares behind a friendly pawn are counted
|
||||
// twice. Finally, the space bonus is multiplied by a weight. The aim is to
|
||||
// improve play on game opening.
|
||||
// Evaluation::space() computes a space evaluation for a given side, aiming to improve game
|
||||
// play in the opening. It is based on the number of safe squares on the 4 central files
|
||||
// on ranks 2 to 4. Completely safe squares behind a friendly pawn are counted twice.
|
||||
// Finally, the space bonus is multiplied by a weight which decreases according to occupancy.
|
||||
|
||||
template<Tracing T> template<Color Us>
|
||||
Score Evaluation<T>::space() const {
|
||||
|
||||
// Early exit if, for example, both queens or 6 minor pieces have been exchanged
|
||||
if (pos.non_pawn_material() < SpaceThreshold)
|
||||
return SCORE_ZERO;
|
||||
|
||||
|
@ -719,12 +722,12 @@ namespace {
|
|||
}
|
||||
|
||||
|
||||
// Evaluation::initiative() computes the initiative correction value
|
||||
// for the position. It is a second order bonus/malus based on the
|
||||
// Evaluation::winnable() adjusts the mg and eg score components based on the
|
||||
// known attacking/defending status of the players.
|
||||
// A single value is derived from the mg and eg values and returned.
|
||||
|
||||
template<Tracing T>
|
||||
Score Evaluation<T>::initiative(Score score) const {
|
||||
Value Evaluation<T>::winnable(Score score) const {
|
||||
|
||||
int outflanking = distance<File>(pos.square<KING>(WHITE), pos.square<KING>(BLACK))
|
||||
- distance<Rank>(pos.square<KING>(WHITE), pos.square<KING>(BLACK));
|
||||
|
@ -746,7 +749,6 @@ namespace {
|
|||
+ 24 * infiltration
|
||||
+ 51 * !pos.non_pawn_material()
|
||||
- 43 * almostUnwinnable
|
||||
- 2 * pos.rule50_count()
|
||||
-110 ;
|
||||
|
||||
Value mg = mg_value(score);
|
||||
|
@ -758,17 +760,10 @@ namespace {
|
|||
int u = ((mg > 0) - (mg < 0)) * Utility::clamp(complexity + 50, -abs(mg), 0);
|
||||
int v = ((eg > 0) - (eg < 0)) * std::max(complexity, -abs(eg));
|
||||
|
||||
if (T)
|
||||
Trace::add(INITIATIVE, make_score(u, v));
|
||||
mg += u;
|
||||
eg += v;
|
||||
|
||||
return make_score(u, v);
|
||||
}
|
||||
|
||||
|
||||
// Evaluation::scale_factor() computes the scale factor for the winning side
|
||||
|
||||
template<Tracing T>
|
||||
ScaleFactor Evaluation<T>::scale_factor(Value eg) const {
|
||||
// Compute the scale factor for the winning side
|
||||
|
||||
Color strongSide = eg > VALUE_DRAW ? WHITE : BLACK;
|
||||
int sf = me->scale_factor(pos, strongSide);
|
||||
|
@ -788,7 +783,18 @@ namespace {
|
|||
sf = std::min(sf, 36 + 7 * pos.count<PAWN>(strongSide));
|
||||
}
|
||||
|
||||
return ScaleFactor(sf);
|
||||
// Interpolate between the middlegame and (scaled by 'sf') endgame score
|
||||
v = mg * int(me->game_phase())
|
||||
+ eg * int(PHASE_MIDGAME - me->game_phase()) * ScaleFactor(sf) / SCALE_FACTOR_NORMAL;
|
||||
v /= PHASE_MIDGAME;
|
||||
|
||||
if (T)
|
||||
{
|
||||
Trace::add(WINNABLE, make_score(u, eg * ScaleFactor(sf) / SCALE_FACTOR_NORMAL - eg_value(score)));
|
||||
Trace::add(TOTAL, make_score(mg, eg * ScaleFactor(sf) / SCALE_FACTOR_NORMAL));
|
||||
}
|
||||
|
||||
return Value(v);
|
||||
}
|
||||
|
||||
|
||||
|
@ -843,14 +849,8 @@ namespace {
|
|||
+ passed< WHITE>() - passed< BLACK>()
|
||||
+ space< WHITE>() - space< BLACK>();
|
||||
|
||||
score += initiative(score);
|
||||
|
||||
// Interpolate between a middlegame and a (scaled by 'sf') endgame score
|
||||
ScaleFactor sf = scale_factor(eg_value(score));
|
||||
v = mg_value(score) * int(me->game_phase())
|
||||
+ eg_value(score) * int(PHASE_MIDGAME - me->game_phase()) * sf / SCALE_FACTOR_NORMAL;
|
||||
|
||||
v /= PHASE_MIDGAME;
|
||||
// Derive single value from mg and eg parts of score
|
||||
v = winnable(score);
|
||||
|
||||
// In case of tracing add all remaining individual evaluation terms
|
||||
if (T)
|
||||
|
@ -859,11 +859,18 @@ namespace {
|
|||
Trace::add(IMBALANCE, me->imbalance());
|
||||
Trace::add(PAWN, pe->pawn_score(WHITE), pe->pawn_score(BLACK));
|
||||
Trace::add(MOBILITY, mobility[WHITE], mobility[BLACK]);
|
||||
Trace::add(TOTAL, score);
|
||||
}
|
||||
|
||||
// Evaluation grain
|
||||
v = (v / 16) * 16;
|
||||
|
||||
// Side to move point of view
|
||||
return (pos.side_to_move() == WHITE ? v : -v) + Tempo;
|
||||
v = (pos.side_to_move() == WHITE ? v : -v) + Tempo;
|
||||
|
||||
// Damp down the evaluation linearly when shuffling
|
||||
v = v * (100 - pos.rule50_count()) / 100;
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
@ -913,11 +920,11 @@ std::string Eval::trace(const Position& pos) {
|
|||
<< " Threats | " << Term(THREAT)
|
||||
<< " Passed | " << Term(PASSED)
|
||||
<< " Space | " << Term(SPACE)
|
||||
<< " Initiative | " << Term(INITIATIVE)
|
||||
<< " Winnable | " << Term(WINNABLE)
|
||||
<< " ------------+-------------+-------------+------------\n"
|
||||
<< " Total | " << Term(TOTAL);
|
||||
|
||||
ss << "\nTotal evaluation: " << to_cp(v) << " (white side)\n";
|
||||
ss << "\nFinal evaluation: " << to_cp(v) << " (white side)\n";
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
@ -976,7 +983,7 @@ bool EvalList::is_valid(const Position& pos)
|
|||
for (Piece pc = NO_PIECE; pc < PIECE_NB; ++pc)
|
||||
{
|
||||
auto pt = type_of(pc);
|
||||
if (pt == NO_PIECE || pt == 7) // ‘¶<E28098>Ý‚µ‚È‚¢‹î
|
||||
if (pt == NO_PIECE_TYPE || pt == 7) // ‘¶<E28098>Ý‚µ‚È‚¢‹î
|
||||
continue;
|
||||
|
||||
// ‹îpc‚ÌBonaPiece‚ÌŠJŽn”Ô<E2809D>†
|
||||
|
|
14
src/misc.h
14
src/misc.h
|
@ -130,6 +130,20 @@ inline std::ostream& operator<<(std::ostream& os, PRNG& prng)
|
|||
return os;
|
||||
}
|
||||
|
||||
inline uint64_t mul_hi64(uint64_t a, uint64_t b) {
|
||||
#if defined(__GNUC__) && defined(IS_64BIT)
|
||||
__extension__ typedef unsigned __int128 uint128;
|
||||
return ((uint128)a * (uint128)b) >> 64;
|
||||
#else
|
||||
uint64_t aL = (uint32_t)a, aH = a >> 32;
|
||||
uint64_t bL = (uint32_t)b, bH = b >> 32;
|
||||
uint64_t c1 = (aL * bL) >> 32;
|
||||
uint64_t c2 = aH * bL + c1;
|
||||
uint64_t c3 = aL * bH + (uint32_t)c2;
|
||||
return aH * bH + (c2 >> 32) + (c3 >> 32);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Under Windows it is not possible for a process to run on more than one
|
||||
/// logical processor group. This usually means to be limited to use max 64
|
||||
/// cores. To overcome this, some special platform specific API should be
|
||||
|
|
|
@ -332,7 +332,7 @@ ExtMove* generate<EVASIONS>(const Position& pos, ExtMove* moveList) {
|
|||
// the king evasions in order to skip known illegal moves, which avoids any
|
||||
// useless legality checks later on.
|
||||
while (sliders)
|
||||
sliderAttacks |= LineBB[ksq][pop_lsb(&sliders)] & ~pos.checkers();
|
||||
sliderAttacks |= line_bb(ksq, pop_lsb(&sliders)) & ~pos.checkers();
|
||||
|
||||
// Generate evasions for king, capture and non capture moves
|
||||
Bitboard b = attacks_bb<KING>(ksq) & ~pos.pieces(us) & ~sliderAttacks;
|
||||
|
|
|
@ -57,7 +57,7 @@ namespace {
|
|||
|
||||
/// MovePicker constructor for the main search
|
||||
MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const ButterflyHistory* mh, const LowPlyHistory* lp,
|
||||
const CapturePieceToHistory* cph, const PieceToHistory** ch, Move cm, Move* killers, int pl)
|
||||
const CapturePieceToHistory* cph, const PieceToHistory** ch, Move cm, const Move* killers, int pl)
|
||||
: pos(p), mainHistory(mh), lowPlyHistory(lp), captureHistory(cph), continuationHistory(ch),
|
||||
ttMove(ttm), refutations{{killers[0], 0}, {killers[1], 0}, {cm, 0}}, depth(d), ply(pl) {
|
||||
|
||||
|
|
|
@ -88,9 +88,9 @@ enum StatsType { NoCaptures, Captures };
|
|||
/// the move's from and to squares, see www.chessprogramming.org/Butterfly_Boards
|
||||
typedef Stats<int16_t, 10692, COLOR_NB, int(SQUARE_NB) * int(SQUARE_NB)> ButterflyHistory;
|
||||
|
||||
/// LowPlyHistory at higher depths records successful quiet moves on plies 0 to 3
|
||||
/// and quiet moves which are/were in the PV (ttPv)
|
||||
/// It get cleared with each new search and get filled during iterative deepening
|
||||
/// At higher depths LowPlyHistory records successful quiet moves near the root and quiet
|
||||
/// moves which are/were in the PV (ttPv)
|
||||
/// It is cleared with each new search and filled during iterative deepening
|
||||
constexpr int MAX_LPH = 4;
|
||||
typedef Stats<int16_t, 10692, MAX_LPH, int(SQUARE_NB) * int(SQUARE_NB)> LowPlyHistory;
|
||||
|
||||
|
@ -133,7 +133,7 @@ public:
|
|||
const CapturePieceToHistory*,
|
||||
const PieceToHistory**,
|
||||
Move,
|
||||
Move*,
|
||||
const Move*,
|
||||
int);
|
||||
Move next_move(bool skipQuiets = false);
|
||||
|
||||
|
|
|
@ -150,17 +150,17 @@ namespace {
|
|||
&& !(theirPawns & adjacent_files_bb(s)))
|
||||
score -= Doubled;
|
||||
else
|
||||
score -= Isolated
|
||||
+ WeakUnopposed * !opposed;
|
||||
score -= Isolated
|
||||
+ WeakUnopposed * !opposed;
|
||||
}
|
||||
|
||||
else if (backward)
|
||||
score -= Backward
|
||||
+ WeakUnopposed * !opposed;
|
||||
score -= Backward
|
||||
+ WeakUnopposed * !opposed;
|
||||
|
||||
if (!support)
|
||||
score -= Doubled * doubled
|
||||
+ WeakLever * more_than_one(lever);
|
||||
score -= Doubled * doubled
|
||||
+ WeakLever * more_than_one(lever);
|
||||
}
|
||||
|
||||
return score;
|
||||
|
@ -196,7 +196,7 @@ Entry* probe(const Position& pos) {
|
|||
/// penalty for a king, looking at the king file and the two closest files.
|
||||
|
||||
template<Color Us>
|
||||
Score Entry::evaluate_shelter(const Position& pos, Square ksq) {
|
||||
Score Entry::evaluate_shelter(const Position& pos, Square ksq) const {
|
||||
|
||||
constexpr Color Them = ~Us;
|
||||
|
||||
|
|
|
@ -50,7 +50,7 @@ struct Entry {
|
|||
Score do_king_safety(const Position& pos);
|
||||
|
||||
template<Color Us>
|
||||
Score evaluate_shelter(const Position& pos, Square ksq);
|
||||
Score evaluate_shelter(const Position& pos, Square ksq) const;
|
||||
|
||||
Key key;
|
||||
Score scores[COLOR_NB];
|
||||
|
|
|
@ -64,10 +64,11 @@ std::ostream& operator<<(std::ostream& os, const Position& pos) {
|
|||
for (File f = FILE_A; f <= FILE_H; ++f)
|
||||
os << " | " << PieceToChar[pos.piece_on(make_square(f, r))];
|
||||
|
||||
os << " |\n +---+---+---+---+---+---+---+---+\n";
|
||||
os << " | " << (1 + r) << "\n +---+---+---+---+---+---+---+---+\n";
|
||||
}
|
||||
|
||||
os << "\nFen: " << pos.fen() << "\nKey: " << std::hex << std::uppercase
|
||||
os << " a b c d e f g h\n"
|
||||
<< "\nFen: " << pos.fen() << "\nKey: " << std::hex << std::uppercase
|
||||
<< std::setfill('0') << std::setw(16) << pos.key()
|
||||
<< std::setfill(' ') << std::dec << "\nCheckers: ";
|
||||
|
||||
|
|
|
@ -91,9 +91,9 @@ constexpr Score PBonus[RANK_NB][FILE_NB] =
|
|||
{ },
|
||||
{ S( 3,-10), S( 3, -6), S( 10, 10), S( 19, 0), S( 16, 14), S( 19, 7), S( 7, -5), S( -5,-19) },
|
||||
{ S( -9,-10), S(-15,-10), S( 11,-10), S( 15, 4), S( 32, 4), S( 22, 3), S( 5, -6), S(-22, -4) },
|
||||
{ S( -8, 6), S(-23, -2), S( 6, -8), S( 20, -4), S( 40,-13), S( 17,-12), S( 4,-10), S(-12, -9) },
|
||||
{ S( -4, 6), S(-23, -2), S( 6, -8), S( 20, -4), S( 40,-13), S( 17,-12), S( 4,-10), S( -8, -9) },
|
||||
{ S( 13, 9), S( 0, 4), S(-13, 3), S( 1,-12), S( 11,-12), S( -2, -6), S(-13, 13), S( 5, 8) },
|
||||
{ S( -5, 28), S(-12, 20), S( -7, 21), S( 22, 28), S( -8, 30), S( -5, 7), S(-15, 6), S(-18, 13) },
|
||||
{ S( 5, 28), S(-12, 20), S( -7, 21), S( 22, 28), S( -8, 30), S( -5, 7), S(-15, 6), S( -8, 13) },
|
||||
{ S( -7, 0), S( 7,-11), S( -3, 12), S(-13, 21), S( 5, 25), S(-16, 19), S( 10, 4), S( -8, 7) }
|
||||
};
|
||||
|
||||
|
@ -106,7 +106,7 @@ Score psq[PIECE_NB][SQUARE_NB];
|
|||
// tables are initialized by flipping and changing the sign of the white scores.
|
||||
void init() {
|
||||
|
||||
for (Piece pc = W_PAWN; pc <= W_KING; ++pc)
|
||||
for (Piece pc : {W_PAWN, W_KNIGHT, W_BISHOP, W_ROOK, W_QUEEN, W_KING})
|
||||
{
|
||||
Score score = make_score(PieceValue[MG][pc], PieceValue[EG][pc]);
|
||||
|
||||
|
|
123
src/search.cpp
123
src/search.cpp
|
@ -65,9 +65,9 @@ namespace {
|
|||
constexpr uint64_t TtHitAverageResolution = 1024;
|
||||
|
||||
// Razor and futility margins
|
||||
constexpr int RazorMargin = 531;
|
||||
constexpr int RazorMargin = 527;
|
||||
Value futility_margin(Depth d, bool improving) {
|
||||
return Value(217 * (d - improving));
|
||||
return Value(227 * (d - improving));
|
||||
}
|
||||
|
||||
// Reductions lookup table, initialized at startup
|
||||
|
@ -75,16 +75,16 @@ namespace {
|
|||
|
||||
Depth reduction(bool i, Depth d, int mn) {
|
||||
int r = Reductions[d] * Reductions[mn];
|
||||
return (r + 511) / 1024 + (!i && r > 1007);
|
||||
return (r + 570) / 1024 + (!i && r > 1018);
|
||||
}
|
||||
|
||||
constexpr int futility_move_count(bool improving, Depth depth) {
|
||||
return (4 + depth * depth) / (2 - improving);
|
||||
return (3 + depth * depth) / (2 - improving);
|
||||
}
|
||||
|
||||
// History and stats update bonus, based on depth
|
||||
int stat_bonus(Depth d) {
|
||||
return d > 15 ? -8 : 19 * d * d + 155 * d - 132;
|
||||
return d > 15 ? 27 : 17 * d * d + 133 * d - 134;
|
||||
}
|
||||
|
||||
// Add a small random component to draw evaluations to avoid 3fold-blindness
|
||||
|
@ -236,14 +236,8 @@ void MainThread::search() {
|
|||
}
|
||||
else
|
||||
{
|
||||
for (Thread* th : Threads)
|
||||
{
|
||||
th->bestMoveChanges = 0;
|
||||
if (th != this)
|
||||
th->start_searching();
|
||||
}
|
||||
|
||||
Thread::search(); // Let's start searching!
|
||||
Threads.start_searching(); // start non-main threads
|
||||
Thread::search(); // main thread start searching
|
||||
}
|
||||
|
||||
// When we reach the maximum depth, we can arrive here without a raise of
|
||||
|
@ -260,9 +254,7 @@ void MainThread::search() {
|
|||
Threads.stop = true;
|
||||
|
||||
// Wait until all threads have finished
|
||||
for (Thread* th : Threads)
|
||||
if (th != this)
|
||||
th->wait_for_search_finished();
|
||||
Threads.wait_for_search_finished();
|
||||
|
||||
// When playing in 'nodes as time' mode, subtract the searched nodes from
|
||||
// the available ones before exiting.
|
||||
|
@ -271,37 +263,11 @@ void MainThread::search() {
|
|||
|
||||
Thread* bestThread = this;
|
||||
|
||||
// Check if there are threads with a better score than main thread
|
||||
if ( int(Options["MultiPV"]) == 1
|
||||
&& !Limits.depth
|
||||
&& !(Skill(Options["Skill Level"]).enabled() || int(Options["UCI_LimitStrength"]))
|
||||
&& rootMoves[0].pv[0] != MOVE_NONE)
|
||||
{
|
||||
std::map<Move, int64_t> votes;
|
||||
Value minScore = this->rootMoves[0].score;
|
||||
|
||||
// Find minimum score
|
||||
for (Thread* th: Threads)
|
||||
minScore = std::min(minScore, th->rootMoves[0].score);
|
||||
|
||||
// Vote according to score and depth, and select the best thread
|
||||
for (Thread* th : Threads)
|
||||
{
|
||||
votes[th->rootMoves[0].pv[0]] +=
|
||||
(th->rootMoves[0].score - minScore + 14) * int(th->completedDepth);
|
||||
|
||||
if (abs(bestThread->rootMoves[0].score) >= VALUE_TB_WIN_IN_MAX_PLY)
|
||||
{
|
||||
// Make sure we pick the shortest mate / TB conversion or stave off mate the longest
|
||||
if (th->rootMoves[0].score > bestThread->rootMoves[0].score)
|
||||
bestThread = th;
|
||||
}
|
||||
else if ( th->rootMoves[0].score >= VALUE_TB_WIN_IN_MAX_PLY
|
||||
|| ( th->rootMoves[0].score > VALUE_TB_LOSS_IN_MAX_PLY
|
||||
&& votes[th->rootMoves[0].pv[0]] > votes[bestThread->rootMoves[0].pv[0]]))
|
||||
bestThread = th;
|
||||
}
|
||||
}
|
||||
if (int(Options["MultiPV"]) == 1 &&
|
||||
!Limits.depth &&
|
||||
!(Skill(Options["Skill Level"]).enabled() || int(Options["UCI_LimitStrength"])) &&
|
||||
rootMoves[0].pv[0] != MOVE_NONE)
|
||||
bestThread = Threads.get_best_thread();
|
||||
|
||||
bestPreviousScore = bestThread->rootMoves[0].score;
|
||||
|
||||
|
@ -437,12 +403,12 @@ void Thread::search() {
|
|||
if (rootDepth >= 4)
|
||||
{
|
||||
Value prev = rootMoves[pvIdx].previousScore;
|
||||
delta = Value(21);
|
||||
delta = Value(19);
|
||||
alpha = std::max(prev - delta,-VALUE_INFINITE);
|
||||
beta = std::min(prev + delta, VALUE_INFINITE);
|
||||
|
||||
// Adjust contempt based on root move's previousScore (dynamic contempt)
|
||||
int dct = ct + (102 - ct / 2) * prev / (abs(prev) + 157);
|
||||
int dct = ct + (110 - ct / 2) * prev / (abs(prev) + 140);
|
||||
|
||||
contempt = (us == WHITE ? make_score(dct, dct / 2)
|
||||
: -make_score(dct, dct / 2));
|
||||
|
@ -540,13 +506,13 @@ void Thread::search() {
|
|||
&& !Threads.stop
|
||||
&& !mainThread->stopOnPonderhit)
|
||||
{
|
||||
double fallingEval = (332 + 6 * (mainThread->bestPreviousScore - bestValue)
|
||||
+ 6 * (mainThread->iterValue[iterIdx] - bestValue)) / 704.0;
|
||||
double fallingEval = (296 + 6 * (mainThread->bestPreviousScore - bestValue)
|
||||
+ 6 * (mainThread->iterValue[iterIdx] - bestValue)) / 725.0;
|
||||
fallingEval = Utility::clamp(fallingEval, 0.5, 1.5);
|
||||
|
||||
// If the bestMove is stable over several iterations, reduce time accordingly
|
||||
timeReduction = lastBestMoveDepth + 9 < completedDepth ? 1.94 : 0.91;
|
||||
double reduction = (1.41 + mainThread->previousTimeReduction) / (2.27 * timeReduction);
|
||||
timeReduction = lastBestMoveDepth + 10 < completedDepth ? 1.92 : 0.95;
|
||||
double reduction = (1.47 + mainThread->previousTimeReduction) / (2.22 * timeReduction);
|
||||
|
||||
// Use part of the gained time from a previous stable move for the current move
|
||||
for (Thread* th : Threads)
|
||||
|
@ -571,7 +537,7 @@ void Thread::search() {
|
|||
}
|
||||
else if ( Threads.increaseDepth
|
||||
&& !mainThread->ponder
|
||||
&& Time.elapsed() > totalTime * 0.6)
|
||||
&& Time.elapsed() > totalTime * 0.56)
|
||||
Threads.increaseDepth = false;
|
||||
else
|
||||
Threads.increaseDepth = true;
|
||||
|
@ -696,7 +662,7 @@ namespace {
|
|||
// search to overwrite a previous full search TT value, so we use a different
|
||||
// position key in case of an excluded move.
|
||||
excludedMove = ss->excludedMove;
|
||||
posKey = pos.key() ^ Key(excludedMove << 16); // Isn't a very good hash
|
||||
posKey = pos.key() ^ (Key(excludedMove) << 48); // Isn't a very good hash
|
||||
tte = TT.probe(posKey, ttHit);
|
||||
ttValue = ttHit ? value_from_tt(tte->value(), ss->ply, pos.rule50_count()) : VALUE_NONE;
|
||||
ttMove = rootNode ? thisThread->rootMoves[thisThread->pvIdx].pv[0]
|
||||
|
@ -704,7 +670,7 @@ namespace {
|
|||
ttPv = PvNode || (ttHit && tte->is_pv());
|
||||
formerPv = ttPv && !PvNode;
|
||||
|
||||
if (ttPv && depth > 12 && ss->ply - 1 < MAX_LPH && !pos.captured_piece() && is_ok((ss-1)->currentMove))
|
||||
if (ttPv && depth > 12 && ss->ply - 1 < MAX_LPH && !priorCapture && is_ok((ss-1)->currentMove))
|
||||
thisThread->lowPlyHistory[ss->ply - 1][from_to((ss-1)->currentMove)] << stat_bonus(depth - 5);
|
||||
|
||||
// thisThread->ttHitAverage can be used to approximate the running average of ttHit
|
||||
|
@ -853,10 +819,10 @@ namespace {
|
|||
// Step 9. Null move search with verification search (~40 Elo)
|
||||
if ( !PvNode
|
||||
&& (ss-1)->currentMove != MOVE_NULL
|
||||
&& (ss-1)->statScore < 23397
|
||||
&& (ss-1)->statScore < 23824
|
||||
&& eval >= beta
|
||||
&& eval >= ss->staticEval
|
||||
&& ss->staticEval >= beta - 32 * depth - 30 * improving + 120 * ttPv + 292
|
||||
&& ss->staticEval >= beta - 33 * depth - 33 * improving + 112 * ttPv + 311
|
||||
&& !excludedMove
|
||||
&& pos.non_pawn_material(us)
|
||||
&& (ss->ply >= thisThread->nmpMinPly || us != thisThread->nmpColor))
|
||||
|
@ -864,7 +830,7 @@ namespace {
|
|||
assert(eval - beta >= 0);
|
||||
|
||||
// Null move dynamic reduction based on depth and value
|
||||
Depth R = (854 + 68 * depth) / 258 + std::min(int(eval - beta) / 192, 3);
|
||||
Depth R = (737 + 77 * depth) / 246 + std::min(int(eval - beta) / 192, 3);
|
||||
|
||||
ss->currentMove = MOVE_NULL;
|
||||
ss->continuationHistory = &thisThread->continuationHistory[0][0][NO_PIECE][0];
|
||||
|
@ -904,10 +870,10 @@ namespace {
|
|||
// If we have a good enough capture and a reduced search returns a value
|
||||
// much above beta, we can (almost) safely prune the previous move.
|
||||
if ( !PvNode
|
||||
&& depth >= 5
|
||||
&& depth > 4
|
||||
&& abs(beta) < VALUE_TB_WIN_IN_MAX_PLY)
|
||||
{
|
||||
Value raisedBeta = beta + 189 - 45 * improving;
|
||||
Value raisedBeta = beta + 176 - 49 * improving;
|
||||
assert(raisedBeta < VALUE_INFINITE);
|
||||
MovePicker mp(pos, ttMove, raisedBeta - ss->staticEval, &captureHistory);
|
||||
int probCutCount = 0;
|
||||
|
@ -1037,14 +1003,15 @@ moves_loop: // When in check, search starts from here
|
|||
// Futility pruning: parent node (~5 Elo)
|
||||
if ( lmrDepth < 6
|
||||
&& !ss->inCheck
|
||||
&& ss->staticEval + 235 + 172 * lmrDepth <= alpha
|
||||
&& ss->staticEval + 284 + 188 * lmrDepth <= alpha
|
||||
&& (*contHist[0])[movedPiece][to_sq(move)]
|
||||
+ (*contHist[1])[movedPiece][to_sq(move)]
|
||||
+ (*contHist[3])[movedPiece][to_sq(move)] < 27400)
|
||||
+ (*contHist[3])[movedPiece][to_sq(move)]
|
||||
+ (*contHist[5])[movedPiece][to_sq(move)] / 2 < 28388)
|
||||
continue;
|
||||
|
||||
// Prune moves with negative SEE (~20 Elo)
|
||||
if (!pos.see_ge(move, Value(-(32 - std::min(lmrDepth, 18)) * lmrDepth * lmrDepth)))
|
||||
if (!pos.see_ge(move, Value(-(29 - std::min(lmrDepth, 17)) * lmrDepth * lmrDepth)))
|
||||
continue;
|
||||
}
|
||||
else
|
||||
|
@ -1060,11 +1027,11 @@ moves_loop: // When in check, search starts from here
|
|||
&& lmrDepth < 6
|
||||
&& !(PvNode && abs(bestValue) < 2)
|
||||
&& !ss->inCheck
|
||||
&& ss->staticEval + 270 + 384 * lmrDepth + PieceValue[MG][type_of(pos.piece_on(to_sq(move)))] <= alpha)
|
||||
&& ss->staticEval + 267 + 391 * lmrDepth + PieceValue[MG][type_of(pos.piece_on(to_sq(move)))] <= alpha)
|
||||
continue;
|
||||
|
||||
// See based pruning
|
||||
if (!pos.see_ge(move, Value(-194) * depth)) // (~25 Elo)
|
||||
if (!pos.see_ge(move, Value(-202) * depth)) // (~25 Elo)
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
@ -1177,12 +1144,12 @@ moves_loop: // When in check, search starts from here
|
|||
|| moveCountPruning
|
||||
|| ss->staticEval + PieceValue[EG][pos.captured_piece()] <= alpha
|
||||
|| cutNode
|
||||
|| thisThread->ttHitAverage < 375 * TtHitAverageResolution * TtHitAverageWindow / 1024))
|
||||
|| thisThread->ttHitAverage < 415 * TtHitAverageResolution * TtHitAverageWindow / 1024))
|
||||
{
|
||||
Depth r = reduction(improving, depth, moveCount);
|
||||
|
||||
// Decrease reduction if the ttHit running average is large
|
||||
if (thisThread->ttHitAverage > 500 * TtHitAverageResolution * TtHitAverageWindow / 1024)
|
||||
if (thisThread->ttHitAverage > 473 * TtHitAverageResolution * TtHitAverageWindow / 1024)
|
||||
r--;
|
||||
|
||||
// Reduction if other threads are searching this position.
|
||||
|
@ -1197,7 +1164,7 @@ moves_loop: // When in check, search starts from here
|
|||
r++;
|
||||
|
||||
// Decrease reduction if opponent's move count is high (~5 Elo)
|
||||
if ((ss-1)->moveCount > 14)
|
||||
if ((ss-1)->moveCount > 13)
|
||||
r--;
|
||||
|
||||
// Decrease reduction if ttMove has been singularly extended (~3 Elo)
|
||||
|
@ -1219,23 +1186,23 @@ moves_loop: // When in check, search starts from here
|
|||
// hence break make_move(). (~2 Elo)
|
||||
else if ( type_of(move) == NORMAL
|
||||
&& !pos.see_ge(reverse_move(move)))
|
||||
r -= 2 + ttPv;
|
||||
r -= 2 + ttPv - (type_of(movedPiece) == PAWN);
|
||||
|
||||
ss->statScore = thisThread->mainHistory[us][from_to(move)]
|
||||
+ (*contHist[0])[movedPiece][to_sq(move)]
|
||||
+ (*contHist[1])[movedPiece][to_sq(move)]
|
||||
+ (*contHist[3])[movedPiece][to_sq(move)]
|
||||
- 4926;
|
||||
- 4826;
|
||||
|
||||
// Decrease/increase reduction by comparing opponent's stat score (~10 Elo)
|
||||
if (ss->statScore >= -102 && (ss-1)->statScore < -114)
|
||||
if (ss->statScore >= -100 && (ss-1)->statScore < -112)
|
||||
r--;
|
||||
|
||||
else if ((ss-1)->statScore >= -116 && ss->statScore < -154)
|
||||
else if ((ss-1)->statScore >= -125 && ss->statScore < -138)
|
||||
r++;
|
||||
|
||||
// Decrease/increase reduction for moves with a good/bad history (~30 Elo)
|
||||
r -= ss->statScore / 16434;
|
||||
r -= ss->statScore / 14615;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1245,7 +1212,7 @@ moves_loop: // When in check, search starts from here
|
|||
|
||||
// Unless giving check, this capture is likely bad
|
||||
if ( !givesCheck
|
||||
&& ss->staticEval + PieceValue[EG][pos.captured_piece()] + 200 * depth <= alpha)
|
||||
&& ss->staticEval + PieceValue[EG][pos.captured_piece()] + 211 * depth <= alpha)
|
||||
r++;
|
||||
}
|
||||
|
||||
|
@ -1507,7 +1474,7 @@ moves_loop: // When in check, search starts from here
|
|||
if (PvNode && bestValue > alpha)
|
||||
alpha = bestValue;
|
||||
|
||||
futilityBase = bestValue + 154;
|
||||
futilityBase = bestValue + 141;
|
||||
}
|
||||
|
||||
const PieceToHistory* contHist[] = { (ss-1)->continuationHistory, (ss-2)->continuationHistory,
|
||||
|
@ -1763,8 +1730,8 @@ moves_loop: // When in check, search starts from here
|
|||
thisThread->counterMoves[pos.piece_on(prevSq)][prevSq] = move;
|
||||
}
|
||||
|
||||
if (depth > 12 && ss->ply < MAX_LPH)
|
||||
thisThread->lowPlyHistory[ss->ply][from_to(move)] << stat_bonus(depth - 7);
|
||||
if (depth > 11 && ss->ply < MAX_LPH)
|
||||
thisThread->lowPlyHistory[ss->ply][from_to(move)] << stat_bonus(depth - 6);
|
||||
}
|
||||
|
||||
// When playing with strength handicap, choose best move among a set of RootMoves
|
||||
|
|
|
@ -1200,7 +1200,7 @@ WDLScore search(Position& pos, ProbeState* result) {
|
|||
auto moveList = MoveList<LEGAL>(pos);
|
||||
size_t totalCount = moveList.size(), moveCount = 0;
|
||||
|
||||
for (const Move& move : moveList)
|
||||
for (const Move move : moveList)
|
||||
{
|
||||
if ( !pos.capture(move)
|
||||
&& (!CheckZeroingMoves || type_of(pos.moved_piece(move)) != PAWN))
|
||||
|
@ -1362,7 +1362,7 @@ void Tablebases::init(const std::string& paths) {
|
|||
LeadPawnsSize[leadPawnsCnt][f] = idx;
|
||||
}
|
||||
|
||||
// Add entries in TB tables if the corresponding ".rtbw" file exsists
|
||||
// Add entries in TB tables if the corresponding ".rtbw" file exists
|
||||
for (PieceType p1 = PAWN; p1 < KING; ++p1) {
|
||||
TBTables.add({KING, p1, KING});
|
||||
|
||||
|
@ -1469,7 +1469,7 @@ int Tablebases::probe_dtz(Position& pos, ProbeState* result) {
|
|||
StateInfo st;
|
||||
int minDTZ = 0xFFFF;
|
||||
|
||||
for (const Move& move : MoveList<LEGAL>(pos))
|
||||
for (const Move move : MoveList<LEGAL>(pos))
|
||||
{
|
||||
bool zeroing = pos.capture(move) || type_of(pos.moved_piece(move)) == PAWN;
|
||||
|
||||
|
|
|
@ -208,7 +208,7 @@ void ThreadPool::start_thinking(Position& pos, StateListPtr& states,
|
|||
|
||||
for (Thread* th : *this)
|
||||
{
|
||||
th->nodes = th->tbHits = th->nmpMinPly = 0;
|
||||
th->nodes = th->tbHits = th->nmpMinPly = th->bestMoveChanges = 0;
|
||||
th->rootDepth = th->completedDepth = 0;
|
||||
th->rootMoves = rootMoves;
|
||||
th->rootPos.set(pos.fen(), pos.is_chess960(), &setupStates->back(), th);
|
||||
|
@ -218,3 +218,52 @@ void ThreadPool::start_thinking(Position& pos, StateListPtr& states,
|
|||
|
||||
main()->start_searching();
|
||||
}
|
||||
|
||||
Thread* ThreadPool::get_best_thread() const {
|
||||
|
||||
Thread* bestThread = front();
|
||||
std::map<Move, int64_t> votes;
|
||||
Value minScore = VALUE_NONE;
|
||||
|
||||
// Find minimum score of all threads
|
||||
for (Thread* th: *this)
|
||||
minScore = std::min(minScore, th->rootMoves[0].score);
|
||||
|
||||
// Vote according to score and depth, and select the best thread
|
||||
for (Thread* th : *this)
|
||||
{
|
||||
votes[th->rootMoves[0].pv[0]] +=
|
||||
(th->rootMoves[0].score - minScore + 14) * int(th->completedDepth);
|
||||
|
||||
if (abs(bestThread->rootMoves[0].score) >= VALUE_TB_WIN_IN_MAX_PLY)
|
||||
{
|
||||
// Make sure we pick the shortest mate / TB conversion or stave off mate the longest
|
||||
if (th->rootMoves[0].score > bestThread->rootMoves[0].score)
|
||||
bestThread = th;
|
||||
}
|
||||
else if ( th->rootMoves[0].score >= VALUE_TB_WIN_IN_MAX_PLY
|
||||
|| ( th->rootMoves[0].score > VALUE_TB_LOSS_IN_MAX_PLY
|
||||
&& votes[th->rootMoves[0].pv[0]] > votes[bestThread->rootMoves[0].pv[0]]))
|
||||
bestThread = th;
|
||||
}
|
||||
|
||||
return bestThread;
|
||||
}
|
||||
|
||||
/// Start non-main threads.
|
||||
|
||||
void ThreadPool::start_searching() {
|
||||
|
||||
for (Thread* th : *this)
|
||||
if (th != front())
|
||||
th->start_searching();
|
||||
}
|
||||
|
||||
/// Wait for non-main threads.
|
||||
|
||||
void ThreadPool::wait_for_search_finished() const {
|
||||
|
||||
for (Thread* th : *this)
|
||||
if (th != front())
|
||||
th->wait_for_search_finished();
|
||||
}
|
||||
|
|
|
@ -109,6 +109,9 @@ struct ThreadPool : public std::vector<Thread*> {
|
|||
MainThread* main() const { return static_cast<MainThread*>(front()); }
|
||||
uint64_t nodes_searched() const { return accumulate(&Thread::nodes); }
|
||||
uint64_t tb_hits() const { return accumulate(&Thread::tbHits); }
|
||||
Thread* get_best_thread() const;
|
||||
void start_searching();
|
||||
void wait_for_search_finished() const;
|
||||
|
||||
std::atomic_bool stop, increaseDepth;
|
||||
|
||||
|
|
|
@ -79,7 +79,7 @@ void TimeManagement::init(Search::LimitsType& limits, Color us, int ply) {
|
|||
{
|
||||
opt_scale = std::min(0.008 + std::pow(ply + 3.0, 0.5) / 250.0,
|
||||
0.2 * limits.time[us] / double(timeLeft));
|
||||
max_scale = 4 + std::min(36, ply) / 12.0;
|
||||
max_scale = std::min(7.0, 4.0 + ply / 12.0);
|
||||
}
|
||||
|
||||
// x moves in y seconds (+ z increment)
|
||||
|
|
|
@ -36,17 +36,17 @@ TranspositionTable TT; // Our global transposition table
|
|||
void TTEntry::save(Key k, Value v, bool pv, Bound b, Depth d, Move m, Value ev) {
|
||||
|
||||
// Preserve any existing move for the same position
|
||||
if (m || (k >> 48) != key16)
|
||||
if (m || (uint16_t)k != key16)
|
||||
move16 = (uint16_t)m;
|
||||
|
||||
// Overwrite less valuable entries
|
||||
if ( (k >> 48) != key16
|
||||
if ((uint16_t)k != key16
|
||||
|| d - DEPTH_OFFSET > depth8 - 4
|
||||
|| b == BOUND_EXACT)
|
||||
{
|
||||
assert(d >= DEPTH_OFFSET);
|
||||
|
||||
key16 = (uint16_t)(k >> 48);
|
||||
key16 = (uint16_t)k;
|
||||
value16 = (int16_t)v;
|
||||
eval16 = (int16_t)ev;
|
||||
genBound8 = (uint8_t)(TT.generation8 | uint8_t(pv) << 2 | b);
|
||||
|
@ -120,7 +120,7 @@ TTEntry* TranspositionTable::probe(const Key key, bool& found) const {
|
|||
#else
|
||||
|
||||
TTEntry* const tte = first_entry(key);
|
||||
const uint16_t key16 = key >> 48; // Use the high 16 bits as key inside the cluster
|
||||
const uint16_t key16 = (uint16_t)key; // Use the low 16 bits as key inside the cluster
|
||||
|
||||
for (int i = 0; i < ClusterSize; ++i)
|
||||
if (!tte[i].key16 || tte[i].key16 == key16)
|
||||
|
|
3
src/tt.h
3
src/tt.h
|
@ -82,9 +82,8 @@ public:
|
|||
void resize(size_t mbSize);
|
||||
void clear();
|
||||
|
||||
// The 32 lowest order bits of the key are used to get the index of the cluster
|
||||
TTEntry* first_entry(const Key key) const {
|
||||
return &table[(uint32_t(key) * uint64_t(clusterCount)) >> 32].entry[0];
|
||||
return &table[mul_hi64(key, clusterCount)].entry[0];
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
16
src/types.h
16
src/types.h
|
@ -40,7 +40,6 @@
|
|||
|
||||
#include <cassert>
|
||||
#include <cctype>
|
||||
#include <climits>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <algorithm>
|
||||
|
@ -219,7 +218,6 @@ constexpr Value PieceValue[PHASE_NB][PIECE_NB] = {
|
|||
typedef int Depth;
|
||||
|
||||
enum : int {
|
||||
|
||||
DEPTH_QS_CHECKS = 0,
|
||||
DEPTH_QS_NO_CHECKS = -1,
|
||||
DEPTH_QS_RECAPTURES = -5,
|
||||
|
@ -288,11 +286,11 @@ inline Value mg_value(Score s) {
|
|||
}
|
||||
|
||||
#define ENABLE_BASE_OPERATORS_ON(T) \
|
||||
constexpr T operator+(T d1, T d2) { return T(int(d1) + int(d2)); } \
|
||||
constexpr T operator-(T d1, T d2) { return T(int(d1) - int(d2)); } \
|
||||
constexpr T operator+(T d1, int d2) { return T(int(d1) + d2); } \
|
||||
constexpr T operator-(T d1, int d2) { return T(int(d1) - d2); } \
|
||||
constexpr T operator-(T d) { return T(-int(d)); } \
|
||||
inline T& operator+=(T& d1, T d2) { return d1 = d1 + d2; } \
|
||||
inline T& operator-=(T& d1, T d2) { return d1 = d1 - d2; }
|
||||
inline T& operator+=(T& d1, int d2) { return d1 = d1 + d2; } \
|
||||
inline T& operator-=(T& d1, int d2) { return d1 = d1 - d2; }
|
||||
|
||||
#define ENABLE_INCR_OPERATORS_ON(T) \
|
||||
inline T& operator++(T& d) { return d = T(int(d) + 1); } \
|
||||
|
@ -322,12 +320,6 @@ ENABLE_BASE_OPERATORS_ON(Score)
|
|||
#undef ENABLE_INCR_OPERATORS_ON
|
||||
#undef ENABLE_BASE_OPERATORS_ON
|
||||
|
||||
/// Additional operators to add integers to a Value
|
||||
constexpr Value operator+(Value v, int i) { return Value(int(v) + i); }
|
||||
constexpr Value operator-(Value v, int i) { return Value(int(v) - i); }
|
||||
inline Value& operator+=(Value& v, int i) { return v = v + i; }
|
||||
inline Value& operator-=(Value& v, int i) { return v = v - i; }
|
||||
|
||||
/// Additional operators to add a Direction to a Square
|
||||
constexpr Square operator+(Square s, Direction d) { return Square(int(s) + int(d)); }
|
||||
constexpr Square operator-(Square s, Direction d) { return Square(int(s) - int(d)); }
|
||||
|
|
|
@ -57,8 +57,7 @@ bool CaseInsensitiveLess::operator() (const string& s1, const string& s2) const
|
|||
|
||||
void init(OptionsMap& o) {
|
||||
|
||||
// at most 2^32 clusters.
|
||||
constexpr int MaxHashMB = Is64Bit ? 131072 : 2048;
|
||||
constexpr int MaxHashMB = Is64Bit ? 33554432 : 2048;
|
||||
|
||||
o["Debug Log File"] << Option("", on_logger);
|
||||
o["Contempt"] << Option(24, -100, 100);
|
||||
|
|
Loading…
Add table
Reference in a new issue