mirror of
https://github.com/sockspls/badfish
synced 2025-05-03 10:09:35 +00:00
Retire probe_dtz() from Tablebases
It is not needed in SF.
This commit is contained in:
parent
7aeef7285f
commit
39e4398133
2 changed files with 236 additions and 235 deletions
|
@ -505,7 +505,7 @@ public:
|
||||||
|
|
||||||
// Given a position, produce a 64-bit material signature key. If the engine
|
// Given a position, produce a 64-bit material signature key. If the engine
|
||||||
// supports such a key, it should equal the engine's key.
|
// supports such a key, it should equal the engine's key.
|
||||||
Key get_key(Position& pos, bool mirror)
|
Key get_key(const Position& pos, bool mirror)
|
||||||
{
|
{
|
||||||
Key key = 0;
|
Key key = 0;
|
||||||
|
|
||||||
|
@ -1520,7 +1520,7 @@ WDLScore probe_wdl_table(Position& pos, int* success)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int probe_dtz_table(Position& pos, int wdl, int *success)
|
int probe_dtz_table(const Position& pos, int wdl, int *success)
|
||||||
{
|
{
|
||||||
uint64_t idx;
|
uint64_t idx;
|
||||||
int i, res;
|
int i, res;
|
||||||
|
@ -1727,6 +1727,238 @@ WDLScore probe_ab(Position& pos, WDLScore alpha, WDLScore beta, int *success)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int probe_dtz(Position& pos, int *success);
|
||||||
|
|
||||||
|
// This routine treats a position with en passant captures as one without.
|
||||||
|
int probe_dtz_no_ep(Position& pos, int *success)
|
||||||
|
{
|
||||||
|
int dtz;
|
||||||
|
|
||||||
|
WDLScore wdl = probe_ab(pos, WDLHardLoss, WDLHardWin, success);
|
||||||
|
|
||||||
|
if (*success == 0) return 0;
|
||||||
|
|
||||||
|
if (wdl == WDLDraw) return 0;
|
||||||
|
|
||||||
|
if (*success == 2)
|
||||||
|
return wdl == WDLHardWin ? 1 : 101;
|
||||||
|
|
||||||
|
ExtMove stack[MAX_MOVES];
|
||||||
|
ExtMove *moves, *end = NULL;
|
||||||
|
StateInfo st;
|
||||||
|
CheckInfo ci(pos);
|
||||||
|
|
||||||
|
if (wdl > 0) {
|
||||||
|
// Generate at least all legal non-capturing pawn moves
|
||||||
|
// including non-capturing promotions.
|
||||||
|
if (!pos.checkers())
|
||||||
|
end = generate<NON_EVASIONS>(pos, stack);
|
||||||
|
else
|
||||||
|
end = generate<EVASIONS>(pos, stack);
|
||||||
|
|
||||||
|
for (moves = stack; moves < end; ++moves) {
|
||||||
|
Move move = moves->move;
|
||||||
|
|
||||||
|
if ( type_of(pos.moved_piece(move)) != PAWN
|
||||||
|
|| pos.capture(move)
|
||||||
|
|| !pos.legal(move, ci.pinned))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
pos.do_move(move, st, pos.gives_check(move, ci));
|
||||||
|
WDLScore v = -probe_ab(pos, WDLHardLoss, -wdl + WDLSoftWin, success);
|
||||||
|
pos.undo_move(move);
|
||||||
|
|
||||||
|
if (*success == 0) return 0;
|
||||||
|
|
||||||
|
if (v == wdl)
|
||||||
|
return v == WDLHardWin ? 1 : 101;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dtz = 1 + probe_dtz_table(pos, wdl, success);
|
||||||
|
|
||||||
|
if (*success >= 0) {
|
||||||
|
if (wdl & 1) dtz += 100;
|
||||||
|
|
||||||
|
return wdl >= 0 ? dtz : -dtz;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wdl > 0) {
|
||||||
|
int best = 0xffff;
|
||||||
|
|
||||||
|
for (moves = stack; moves < end; ++moves) {
|
||||||
|
Move move = moves->move;
|
||||||
|
|
||||||
|
if (pos.capture(move) || type_of(pos.moved_piece(move)) == PAWN
|
||||||
|
|| !pos.legal(move, ci.pinned))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
pos.do_move(move, st, pos.gives_check(move, ci));
|
||||||
|
int v = -probe_dtz(pos, success);
|
||||||
|
pos.undo_move(move);
|
||||||
|
|
||||||
|
if (*success == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (v > 0 && v + 1 < best)
|
||||||
|
best = v + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return best;
|
||||||
|
} else {
|
||||||
|
int best = -1;
|
||||||
|
|
||||||
|
if (!pos.checkers())
|
||||||
|
end = generate<NON_EVASIONS>(pos, stack);
|
||||||
|
else
|
||||||
|
end = generate<EVASIONS>(pos, stack);
|
||||||
|
|
||||||
|
for (moves = stack; moves < end; ++moves) {
|
||||||
|
int v;
|
||||||
|
Move move = moves->move;
|
||||||
|
|
||||||
|
if (!pos.legal(move, ci.pinned))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
pos.do_move(move, st, pos.gives_check(move, ci));
|
||||||
|
|
||||||
|
if (st.rule50 == 0) {
|
||||||
|
if (wdl == -2) v = -1;
|
||||||
|
else {
|
||||||
|
v = probe_ab(pos, WDLSoftWin, WDLHardWin, success);
|
||||||
|
v = (v == 2) ? 0 : -101;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
v = -probe_dtz(pos, success) - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pos.undo_move(move);
|
||||||
|
|
||||||
|
if (*success == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (v < best)
|
||||||
|
best = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
return best;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Probe the DTZ table for a particular position.
|
||||||
|
// If *success != 0, the probe was successful.
|
||||||
|
// The return value is from the point of view of the side to move:
|
||||||
|
// n < -100 : loss, but draw under 50-move rule
|
||||||
|
// -100 <= n < -1 : loss in n ply (assuming 50-move counter == 0)
|
||||||
|
// 0 : draw
|
||||||
|
// 1 < n <= 100 : win in n ply (assuming 50-move counter == 0)
|
||||||
|
// 100 < n : win, but draw under 50-move rule
|
||||||
|
//
|
||||||
|
// The return value n can be off by 1: a return value -n can mean a loss
|
||||||
|
// in n+1 ply and a return value +n can mean a win in n+1 ply. This
|
||||||
|
// cannot happen for tables with positions exactly on the "edge" of
|
||||||
|
// the 50-move rule.
|
||||||
|
//
|
||||||
|
// This implies that if dtz > 0 is returned, the position is certainly
|
||||||
|
// a win if dtz + 50-move-counter <= 99. Care must be taken that the engine
|
||||||
|
// picks moves that preserve dtz + 50-move-counter <= 99.
|
||||||
|
//
|
||||||
|
// If n = 100 immediately after a capture or pawn move, then the position
|
||||||
|
// is also certainly a win, and during the whole phase until the next
|
||||||
|
// capture or pawn move, the inequality to be preserved is
|
||||||
|
// dtz + 50-movecounter <= 100.
|
||||||
|
//
|
||||||
|
// In short, if a move is available resulting in dtz + 50-move-counter <= 99,
|
||||||
|
// then do not accept moves leading to dtz + 50-move-counter == 100.
|
||||||
|
//
|
||||||
|
int probe_dtz(Position& pos, int *success)
|
||||||
|
{
|
||||||
|
*success = 1;
|
||||||
|
int v = probe_dtz_no_ep(pos, success);
|
||||||
|
|
||||||
|
if (pos.ep_square() == SQ_NONE)
|
||||||
|
return v;
|
||||||
|
|
||||||
|
if (*success == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Now handle en passant.
|
||||||
|
int v1 = -3;
|
||||||
|
|
||||||
|
ExtMove stack[MAX_MOVES];
|
||||||
|
ExtMove *moves, *end;
|
||||||
|
StateInfo st;
|
||||||
|
|
||||||
|
if (!pos.checkers())
|
||||||
|
end = generate<CAPTURES>(pos, stack);
|
||||||
|
else
|
||||||
|
end = generate<EVASIONS>(pos, stack);
|
||||||
|
|
||||||
|
CheckInfo ci(pos);
|
||||||
|
|
||||||
|
for (moves = stack; moves < end; ++moves) {
|
||||||
|
Move capture = moves->move;
|
||||||
|
|
||||||
|
if (type_of(capture) != ENPASSANT
|
||||||
|
|| !pos.legal(capture, ci.pinned))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
pos.do_move(capture, st, pos.gives_check(capture, ci));
|
||||||
|
WDLScore v0 = -probe_ab(pos, WDLHardLoss, WDLHardWin, success);
|
||||||
|
pos.undo_move(capture);
|
||||||
|
|
||||||
|
if (*success == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (v0 > v1) v1 = v0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (v1 > -3) {
|
||||||
|
v1 = wdl_to_dtz[v1 + 2];
|
||||||
|
|
||||||
|
if (v < -100) {
|
||||||
|
if (v1 >= 0)
|
||||||
|
v = v1;
|
||||||
|
} else if (v < 0) {
|
||||||
|
if (v1 >= 0 || v1 < -100)
|
||||||
|
v = v1;
|
||||||
|
} else if (v > 100) {
|
||||||
|
if (v1 > 0)
|
||||||
|
v = v1;
|
||||||
|
} else if (v > 0) {
|
||||||
|
if (v1 == 1)
|
||||||
|
v = v1;
|
||||||
|
} else if (v1 >= 0) {
|
||||||
|
v = v1;
|
||||||
|
} else {
|
||||||
|
for (moves = stack; moves < end; ++moves) {
|
||||||
|
Move move = moves->move;
|
||||||
|
|
||||||
|
if (type_of(move) == ENPASSANT) continue;
|
||||||
|
|
||||||
|
if (pos.legal(move, ci.pinned))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (moves == end && !pos.checkers()) {
|
||||||
|
end = generate<QUIETS>(pos, end);
|
||||||
|
|
||||||
|
for (; moves < end; ++moves) {
|
||||||
|
Move move = moves->move;
|
||||||
|
|
||||||
|
if (pos.legal(move, ci.pinned))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (moves == end)
|
||||||
|
v = v1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void Tablebases::free()
|
void Tablebases::free()
|
||||||
|
@ -1895,236 +2127,6 @@ WDLScore Tablebases::probe_wdl(Position& pos, int *success)
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This routine treats a position with en passant captures as one without.
|
|
||||||
static int probe_dtz_no_ep(Position& pos, int *success)
|
|
||||||
{
|
|
||||||
int dtz;
|
|
||||||
|
|
||||||
WDLScore wdl = probe_ab(pos, WDLHardLoss, WDLHardWin, success);
|
|
||||||
|
|
||||||
if (*success == 0) return 0;
|
|
||||||
|
|
||||||
if (wdl == WDLDraw) return 0;
|
|
||||||
|
|
||||||
if (*success == 2)
|
|
||||||
return wdl == WDLHardWin ? 1 : 101;
|
|
||||||
|
|
||||||
ExtMove stack[MAX_MOVES];
|
|
||||||
ExtMove *moves, *end = NULL;
|
|
||||||
StateInfo st;
|
|
||||||
CheckInfo ci(pos);
|
|
||||||
|
|
||||||
if (wdl > 0) {
|
|
||||||
// Generate at least all legal non-capturing pawn moves
|
|
||||||
// including non-capturing promotions.
|
|
||||||
if (!pos.checkers())
|
|
||||||
end = generate<NON_EVASIONS>(pos, stack);
|
|
||||||
else
|
|
||||||
end = generate<EVASIONS>(pos, stack);
|
|
||||||
|
|
||||||
for (moves = stack; moves < end; ++moves) {
|
|
||||||
Move move = moves->move;
|
|
||||||
|
|
||||||
if ( type_of(pos.moved_piece(move)) != PAWN
|
|
||||||
|| pos.capture(move)
|
|
||||||
|| !pos.legal(move, ci.pinned))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
pos.do_move(move, st, pos.gives_check(move, ci));
|
|
||||||
WDLScore v = -probe_ab(pos, WDLHardLoss, -wdl + WDLSoftWin, success);
|
|
||||||
pos.undo_move(move);
|
|
||||||
|
|
||||||
if (*success == 0) return 0;
|
|
||||||
|
|
||||||
if (v == wdl)
|
|
||||||
return v == WDLHardWin ? 1 : 101;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dtz = 1 + probe_dtz_table(pos, wdl, success);
|
|
||||||
|
|
||||||
if (*success >= 0) {
|
|
||||||
if (wdl & 1) dtz += 100;
|
|
||||||
|
|
||||||
return wdl >= 0 ? dtz : -dtz;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (wdl > 0) {
|
|
||||||
int best = 0xffff;
|
|
||||||
|
|
||||||
for (moves = stack; moves < end; ++moves) {
|
|
||||||
Move move = moves->move;
|
|
||||||
|
|
||||||
if (pos.capture(move) || type_of(pos.moved_piece(move)) == PAWN
|
|
||||||
|| !pos.legal(move, ci.pinned))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
pos.do_move(move, st, pos.gives_check(move, ci));
|
|
||||||
int v = -Tablebases::probe_dtz(pos, success);
|
|
||||||
pos.undo_move(move);
|
|
||||||
|
|
||||||
if (*success == 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (v > 0 && v + 1 < best)
|
|
||||||
best = v + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return best;
|
|
||||||
} else {
|
|
||||||
int best = -1;
|
|
||||||
|
|
||||||
if (!pos.checkers())
|
|
||||||
end = generate<NON_EVASIONS>(pos, stack);
|
|
||||||
else
|
|
||||||
end = generate<EVASIONS>(pos, stack);
|
|
||||||
|
|
||||||
for (moves = stack; moves < end; ++moves) {
|
|
||||||
int v;
|
|
||||||
Move move = moves->move;
|
|
||||||
|
|
||||||
if (!pos.legal(move, ci.pinned))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
pos.do_move(move, st, pos.gives_check(move, ci));
|
|
||||||
|
|
||||||
if (st.rule50 == 0) {
|
|
||||||
if (wdl == -2) v = -1;
|
|
||||||
else {
|
|
||||||
v = probe_ab(pos, WDLSoftWin, WDLHardWin, success);
|
|
||||||
v = (v == 2) ? 0 : -101;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
v = -Tablebases::probe_dtz(pos, success) - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
pos.undo_move(move);
|
|
||||||
|
|
||||||
if (*success == 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (v < best)
|
|
||||||
best = v;
|
|
||||||
}
|
|
||||||
|
|
||||||
return best;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Probe the DTZ table for a particular position.
|
|
||||||
// If *success != 0, the probe was successful.
|
|
||||||
// The return value is from the point of view of the side to move:
|
|
||||||
// n < -100 : loss, but draw under 50-move rule
|
|
||||||
// -100 <= n < -1 : loss in n ply (assuming 50-move counter == 0)
|
|
||||||
// 0 : draw
|
|
||||||
// 1 < n <= 100 : win in n ply (assuming 50-move counter == 0)
|
|
||||||
// 100 < n : win, but draw under 50-move rule
|
|
||||||
//
|
|
||||||
// The return value n can be off by 1: a return value -n can mean a loss
|
|
||||||
// in n+1 ply and a return value +n can mean a win in n+1 ply. This
|
|
||||||
// cannot happen for tables with positions exactly on the "edge" of
|
|
||||||
// the 50-move rule.
|
|
||||||
//
|
|
||||||
// This implies that if dtz > 0 is returned, the position is certainly
|
|
||||||
// a win if dtz + 50-move-counter <= 99. Care must be taken that the engine
|
|
||||||
// picks moves that preserve dtz + 50-move-counter <= 99.
|
|
||||||
//
|
|
||||||
// If n = 100 immediately after a capture or pawn move, then the position
|
|
||||||
// is also certainly a win, and during the whole phase until the next
|
|
||||||
// capture or pawn move, the inequality to be preserved is
|
|
||||||
// dtz + 50-movecounter <= 100.
|
|
||||||
//
|
|
||||||
// In short, if a move is available resulting in dtz + 50-move-counter <= 99,
|
|
||||||
// then do not accept moves leading to dtz + 50-move-counter == 100.
|
|
||||||
//
|
|
||||||
int Tablebases::probe_dtz(Position& pos, int *success)
|
|
||||||
{
|
|
||||||
*success = 1;
|
|
||||||
int v = probe_dtz_no_ep(pos, success);
|
|
||||||
|
|
||||||
if (pos.ep_square() == SQ_NONE)
|
|
||||||
return v;
|
|
||||||
|
|
||||||
if (*success == 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
// Now handle en passant.
|
|
||||||
int v1 = -3;
|
|
||||||
|
|
||||||
ExtMove stack[MAX_MOVES];
|
|
||||||
ExtMove *moves, *end;
|
|
||||||
StateInfo st;
|
|
||||||
|
|
||||||
if (!pos.checkers())
|
|
||||||
end = generate<CAPTURES>(pos, stack);
|
|
||||||
else
|
|
||||||
end = generate<EVASIONS>(pos, stack);
|
|
||||||
|
|
||||||
CheckInfo ci(pos);
|
|
||||||
|
|
||||||
for (moves = stack; moves < end; ++moves) {
|
|
||||||
Move capture = moves->move;
|
|
||||||
|
|
||||||
if (type_of(capture) != ENPASSANT
|
|
||||||
|| !pos.legal(capture, ci.pinned))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
pos.do_move(capture, st, pos.gives_check(capture, ci));
|
|
||||||
WDLScore v0 = -probe_ab(pos, WDLHardLoss, WDLHardWin, success);
|
|
||||||
pos.undo_move(capture);
|
|
||||||
|
|
||||||
if (*success == 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (v0 > v1) v1 = v0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (v1 > -3) {
|
|
||||||
v1 = wdl_to_dtz[v1 + 2];
|
|
||||||
|
|
||||||
if (v < -100) {
|
|
||||||
if (v1 >= 0)
|
|
||||||
v = v1;
|
|
||||||
} else if (v < 0) {
|
|
||||||
if (v1 >= 0 || v1 < -100)
|
|
||||||
v = v1;
|
|
||||||
} else if (v > 100) {
|
|
||||||
if (v1 > 0)
|
|
||||||
v = v1;
|
|
||||||
} else if (v > 0) {
|
|
||||||
if (v1 == 1)
|
|
||||||
v = v1;
|
|
||||||
} else if (v1 >= 0) {
|
|
||||||
v = v1;
|
|
||||||
} else {
|
|
||||||
for (moves = stack; moves < end; ++moves) {
|
|
||||||
Move move = moves->move;
|
|
||||||
|
|
||||||
if (type_of(move) == ENPASSANT) continue;
|
|
||||||
|
|
||||||
if (pos.legal(move, ci.pinned))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (moves == end && !pos.checkers()) {
|
|
||||||
end = generate<QUIETS>(pos, end);
|
|
||||||
|
|
||||||
for (; moves < end; ++moves) {
|
|
||||||
Move move = moves->move;
|
|
||||||
|
|
||||||
if (pos.legal(move, ci.pinned))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (moves == end)
|
|
||||||
v = v1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check whether there has been at least one repetition of positions
|
// Check whether there has been at least one repetition of positions
|
||||||
// since the last capture or pawn move.
|
// since the last capture or pawn move.
|
||||||
static int has_repeated(StateInfo *st)
|
static int has_repeated(StateInfo *st)
|
||||||
|
@ -2182,14 +2184,14 @@ bool Tablebases::root_probe(Position& pos, Search::RootMoves& rootMoves, Value&
|
||||||
|
|
||||||
if (!v) {
|
if (!v) {
|
||||||
if (st.rule50 != 0) {
|
if (st.rule50 != 0) {
|
||||||
v = -Tablebases::probe_dtz(pos, &success);
|
v = -probe_dtz(pos, &success);
|
||||||
|
|
||||||
if (v > 0)
|
if (v > 0)
|
||||||
++v;
|
++v;
|
||||||
else if (v < 0)
|
else if (v < 0)
|
||||||
--v;
|
--v;
|
||||||
} else {
|
} else {
|
||||||
v = -Tablebases::probe_wdl(pos, &success);
|
v = -probe_wdl(pos, &success);
|
||||||
v = wdl_to_dtz[v + 2];
|
v = wdl_to_dtz[v + 2];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,6 @@ extern int MaxCardinality;
|
||||||
void init(const std::string& paths);
|
void init(const std::string& paths);
|
||||||
void free();
|
void free();
|
||||||
WDLScore probe_wdl(Position& pos, int* success);
|
WDLScore probe_wdl(Position& pos, int* success);
|
||||||
int probe_dtz(Position& pos, int* success);
|
|
||||||
bool root_probe(Position& pos, Search::RootMoves& rootMoves, Value& score);
|
bool root_probe(Position& pos, Search::RootMoves& rootMoves, Value& score);
|
||||||
bool root_probe_wdl(Position& pos, Search::RootMoves& rootMoves, Value& score);
|
bool root_probe_wdl(Position& pos, Search::RootMoves& rootMoves, Value& score);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue