mirror of
https://github.com/peterosterlund2/droidfish.git
synced 2025-12-13 09:32:39 +01:00
DroidFish: Updated stockfish engine to git version from 2016-07-16.
This commit is contained in:
@@ -77,6 +77,11 @@ namespace {
|
|||||||
// attacked by a given color and piece type (can be also ALL_PIECES).
|
// attacked by a given color and piece type (can be also ALL_PIECES).
|
||||||
Bitboard attackedBy[COLOR_NB][PIECE_TYPE_NB];
|
Bitboard attackedBy[COLOR_NB][PIECE_TYPE_NB];
|
||||||
|
|
||||||
|
// attackedBy2[color] are the squares attacked by 2 pieces of a given color,
|
||||||
|
// possibly via x-ray or by one pawn and one piece. Diagonal x-ray through
|
||||||
|
// pawn or squares attacked by 2 pawns are not explicitly added.
|
||||||
|
Bitboard attackedBy2[COLOR_NB];
|
||||||
|
|
||||||
// kingRing[color] is the zone around the king which is considered
|
// kingRing[color] is the zone around the king which is considered
|
||||||
// by the king safety evaluation. This consists of the squares directly
|
// by the king safety evaluation. This consists of the squares directly
|
||||||
// adjacent to the king, and the three (or two, for a king on an edge file)
|
// adjacent to the king, and the three (or two, for a king on an edge file)
|
||||||
@@ -211,10 +216,10 @@ namespace {
|
|||||||
|
|
||||||
// Penalties for enemy's safe checks
|
// Penalties for enemy's safe checks
|
||||||
const int QueenContactCheck = 89;
|
const int QueenContactCheck = 89;
|
||||||
const int QueenCheck = 52;
|
const int QueenCheck = 62;
|
||||||
const int RookCheck = 45;
|
const int RookCheck = 57;
|
||||||
const int BishopCheck = 5;
|
const int BishopCheck = 48;
|
||||||
const int KnightCheck = 17;
|
const int KnightCheck = 78;
|
||||||
|
|
||||||
|
|
||||||
// eval_init() initializes king and attack bitboards for a given color
|
// eval_init() initializes king and attack bitboards for a given color
|
||||||
@@ -227,9 +232,10 @@ namespace {
|
|||||||
const Square Down = (Us == WHITE ? DELTA_S : DELTA_N);
|
const Square Down = (Us == WHITE ? DELTA_S : DELTA_N);
|
||||||
|
|
||||||
ei.pinnedPieces[Us] = pos.pinned_pieces(Us);
|
ei.pinnedPieces[Us] = pos.pinned_pieces(Us);
|
||||||
Bitboard b = ei.attackedBy[Them][KING] = pos.attacks_from<KING>(pos.square<KING>(Them));
|
Bitboard b = ei.attackedBy[Them][KING];
|
||||||
ei.attackedBy[Them][ALL_PIECES] |= b;
|
ei.attackedBy[Them][ALL_PIECES] |= b;
|
||||||
ei.attackedBy[Us][ALL_PIECES] |= ei.attackedBy[Us][PAWN] = ei.pi->pawn_attacks(Us);
|
ei.attackedBy[Us][ALL_PIECES] |= ei.attackedBy[Us][PAWN] = ei.pi->pawn_attacks(Us);
|
||||||
|
ei.attackedBy2[Us] = ei.attackedBy[Us][PAWN] & ei.attackedBy[Us][KING];
|
||||||
|
|
||||||
// Init king safety tables only if we are going to use them
|
// Init king safety tables only if we are going to use them
|
||||||
if (pos.non_pawn_material(Us) >= QueenValueMg)
|
if (pos.non_pawn_material(Us) >= QueenValueMg)
|
||||||
@@ -272,6 +278,7 @@ namespace {
|
|||||||
if (ei.pinnedPieces[Us] & s)
|
if (ei.pinnedPieces[Us] & s)
|
||||||
b &= LineBB[pos.square<KING>(Us)][s];
|
b &= LineBB[pos.square<KING>(Us)][s];
|
||||||
|
|
||||||
|
ei.attackedBy2[Us] |= ei.attackedBy[Us][ALL_PIECES] & b;
|
||||||
ei.attackedBy[Us][ALL_PIECES] |= ei.attackedBy[Us][Pt] |= b;
|
ei.attackedBy[Us][ALL_PIECES] |= ei.attackedBy[Us][Pt] |= b;
|
||||||
|
|
||||||
if (b & ei.kingRing[Them])
|
if (b & ei.kingRing[Them])
|
||||||
@@ -348,6 +355,13 @@ namespace {
|
|||||||
score -= (TrappedRook - make_score(mob * 22, 0)) * (1 + !pos.can_castle(Us));
|
score -= (TrappedRook - make_score(mob * 22, 0)) * (1 + !pos.can_castle(Us));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Pt == QUEEN)
|
||||||
|
{
|
||||||
|
// Penalty if any relative pin or discovered attack against the queen
|
||||||
|
if (pos.slider_blockers(pos.pieces(), pos.pieces(Them, ROOK, BISHOP), s))
|
||||||
|
score -= WeakQueen;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (DoTrace)
|
if (DoTrace)
|
||||||
@@ -382,11 +396,9 @@ namespace {
|
|||||||
if (ei.kingAttackersCount[Them])
|
if (ei.kingAttackersCount[Them])
|
||||||
{
|
{
|
||||||
// Find the attacked squares which are defended only by the king...
|
// Find the attacked squares which are defended only by the king...
|
||||||
undefended = ei.attackedBy[Them][ALL_PIECES]
|
undefended = ei.attackedBy[Them][ALL_PIECES]
|
||||||
& ei.attackedBy[Us][KING]
|
& ei.attackedBy[Us][KING]
|
||||||
& ~( ei.attackedBy[Us][PAWN] | ei.attackedBy[Us][KNIGHT]
|
& ~ei.attackedBy2[Us];
|
||||||
| ei.attackedBy[Us][BISHOP] | ei.attackedBy[Us][ROOK]
|
|
||||||
| ei.attackedBy[Us][QUEEN]);
|
|
||||||
|
|
||||||
// ... and those which are not defended at all in the larger king ring
|
// ... and those which are not defended at all in the larger king ring
|
||||||
b = ei.attackedBy[Them][ALL_PIECES] & ~ei.attackedBy[Us][ALL_PIECES]
|
b = ei.attackedBy[Them][ALL_PIECES] & ~ei.attackedBy[Us][ALL_PIECES]
|
||||||
@@ -399,23 +411,17 @@ namespace {
|
|||||||
// the pawn shelter (current 'score' value).
|
// the pawn shelter (current 'score' value).
|
||||||
attackUnits = std::min(72, ei.kingAttackersCount[Them] * ei.kingAttackersWeight[Them])
|
attackUnits = std::min(72, ei.kingAttackersCount[Them] * ei.kingAttackersWeight[Them])
|
||||||
+ 9 * ei.kingAdjacentZoneAttacksCount[Them]
|
+ 9 * ei.kingAdjacentZoneAttacksCount[Them]
|
||||||
+ 27 * popcount(undefended)
|
+ 21 * popcount(undefended)
|
||||||
+ 11 * (popcount(b) + !!ei.pinnedPieces[Us])
|
+ 12 * (popcount(b) + !!ei.pinnedPieces[Us])
|
||||||
- 64 * !pos.count<QUEEN>(Them)
|
- 64 * !pos.count<QUEEN>(Them)
|
||||||
- mg_value(score) / 8;
|
- mg_value(score) / 8;
|
||||||
|
|
||||||
// Analyse the enemy's safe queen contact checks. Firstly, find the
|
// Analyse the enemy's safe queen contact checks. Firstly, find the
|
||||||
// undefended squares around the king reachable by the enemy queen...
|
// undefended squares around the king reachable by the enemy queen...
|
||||||
b = undefended & ei.attackedBy[Them][QUEEN] & ~pos.pieces(Them);
|
b = undefended & ei.attackedBy[Them][QUEEN] & ~pos.pieces(Them);
|
||||||
if (b)
|
|
||||||
{
|
|
||||||
// ...and then remove squares not supported by another enemy piece
|
|
||||||
b &= ei.attackedBy[Them][PAWN] | ei.attackedBy[Them][KNIGHT]
|
|
||||||
| ei.attackedBy[Them][BISHOP] | ei.attackedBy[Them][ROOK]
|
|
||||||
| ei.attackedBy[Them][KING];
|
|
||||||
|
|
||||||
attackUnits += QueenContactCheck * popcount(b);
|
// ...and keep squares supported by another enemy piece
|
||||||
}
|
attackUnits += QueenContactCheck * popcount(b & ei.attackedBy2[Them]);
|
||||||
|
|
||||||
// Analyse the safe enemy's checks which are possible on next move...
|
// Analyse the safe enemy's checks which are possible on next move...
|
||||||
safe = ~(ei.attackedBy[Us][ALL_PIECES] | pos.pieces(Them));
|
safe = ~(ei.attackedBy[Us][ALL_PIECES] | pos.pieces(Them));
|
||||||
@@ -432,6 +438,12 @@ namespace {
|
|||||||
if ((b1 | b2) & ei.attackedBy[Them][QUEEN] & safe)
|
if ((b1 | b2) & ei.attackedBy[Them][QUEEN] & safe)
|
||||||
attackUnits += QueenCheck, score -= SafeCheck;
|
attackUnits += QueenCheck, score -= SafeCheck;
|
||||||
|
|
||||||
|
// For other pieces, also consider the square safe if attacked twice,
|
||||||
|
// and only defended by a queen.
|
||||||
|
safe |= ei.attackedBy2[Them]
|
||||||
|
& ~(ei.attackedBy2[Us] | pos.pieces(Them))
|
||||||
|
& ei.attackedBy[Us][QUEEN];
|
||||||
|
|
||||||
// Enemy rooks safe and other checks
|
// Enemy rooks safe and other checks
|
||||||
if (b1 & ei.attackedBy[Them][ROOK] & safe)
|
if (b1 & ei.attackedBy[Them][ROOK] & safe)
|
||||||
attackUnits += RookCheck, score -= SafeCheck;
|
attackUnits += RookCheck, score -= SafeCheck;
|
||||||
@@ -469,6 +481,19 @@ namespace {
|
|||||||
// evaluate_threats() assigns bonuses according to the types of the attacking
|
// evaluate_threats() assigns bonuses according to the types of the attacking
|
||||||
// and the attacked pieces.
|
// and the attacked pieces.
|
||||||
|
|
||||||
|
const Bitboard WhiteCamp = Rank4BB | Rank5BB | Rank6BB | Rank7BB | Rank8BB;
|
||||||
|
const Bitboard BlackCamp = Rank5BB | Rank4BB | Rank3BB | Rank2BB | Rank1BB;
|
||||||
|
const Bitboard QueenSide = FileABB | FileBBB | FileCBB | FileDBB;
|
||||||
|
const Bitboard CenterFiles = FileCBB | FileDBB | FileEBB | FileFBB;
|
||||||
|
const Bitboard KingSide = FileEBB | FileFBB | FileGBB | FileHBB;
|
||||||
|
|
||||||
|
const Bitboard KingFlank[COLOR_NB][FILE_NB] = {
|
||||||
|
{ QueenSide & WhiteCamp, QueenSide & WhiteCamp, QueenSide & WhiteCamp, CenterFiles & WhiteCamp,
|
||||||
|
CenterFiles & WhiteCamp, KingSide & WhiteCamp, KingSide & WhiteCamp, KingSide & WhiteCamp },
|
||||||
|
{ QueenSide & BlackCamp, QueenSide & BlackCamp, QueenSide & BlackCamp, CenterFiles & BlackCamp,
|
||||||
|
CenterFiles & BlackCamp, KingSide & BlackCamp, KingSide & BlackCamp, KingSide & BlackCamp },
|
||||||
|
};
|
||||||
|
|
||||||
template<Color Us, bool DoTrace>
|
template<Color Us, bool DoTrace>
|
||||||
Score evaluate_threats(const Position& pos, const EvalInfo& ei) {
|
Score evaluate_threats(const Position& pos, const EvalInfo& ei) {
|
||||||
|
|
||||||
@@ -489,13 +514,6 @@ namespace {
|
|||||||
& ~(ei.attackedBy[Us][ALL_PIECES] | ei.attackedBy[Them][ALL_PIECES]))
|
& ~(ei.attackedBy[Us][ALL_PIECES] | ei.attackedBy[Them][ALL_PIECES]))
|
||||||
score += LooseEnemies;
|
score += LooseEnemies;
|
||||||
|
|
||||||
// Bonus for pin or discovered attack on the opponent queen
|
|
||||||
if ( pos.count<QUEEN>(Them) == 1
|
|
||||||
&& pos.slider_blockers(pos.pieces(),
|
|
||||||
pos.pieces(Us, ROOK, BISHOP),
|
|
||||||
pos.square<QUEEN>(Them)))
|
|
||||||
score += WeakQueen;
|
|
||||||
|
|
||||||
// Non-pawn enemies attacked by a pawn
|
// Non-pawn enemies attacked by a pawn
|
||||||
weak = (pos.pieces(Them) ^ pos.pieces(Them, PAWN)) & ei.attackedBy[Us][PAWN];
|
weak = (pos.pieces(Them) ^ pos.pieces(Them, PAWN)) & ei.attackedBy[Us][PAWN];
|
||||||
|
|
||||||
@@ -553,6 +571,18 @@ namespace {
|
|||||||
|
|
||||||
score += ThreatByPawnPush * popcount(b);
|
score += ThreatByPawnPush * popcount(b);
|
||||||
|
|
||||||
|
// King tropism: firstly, find squares that we attack in the enemy king flank
|
||||||
|
b = ei.attackedBy[Us][ALL_PIECES] & KingFlank[Us][file_of(pos.square<KING>(Them))];
|
||||||
|
|
||||||
|
// Secondly, add to the bitboard the squares which we attack twice in that flank
|
||||||
|
// but which are not protected by a enemy pawn. Note the trick to shift away the
|
||||||
|
// previous attack bits to the empty part of the bitboard.
|
||||||
|
b = (b & ei.attackedBy2[Us] & ~ei.attackedBy[Them][PAWN])
|
||||||
|
| (Us == WHITE ? b >> 4 : b << 4);
|
||||||
|
|
||||||
|
// Count all these squares with a single popcount
|
||||||
|
score += make_score(7 * popcount(b), 0);
|
||||||
|
|
||||||
if (DoTrace)
|
if (DoTrace)
|
||||||
Trace::add(THREAT, Us, score);
|
Trace::add(THREAT, Us, score);
|
||||||
|
|
||||||
@@ -577,6 +607,7 @@ namespace {
|
|||||||
Square s = pop_lsb(&b);
|
Square s = pop_lsb(&b);
|
||||||
|
|
||||||
assert(pos.pawn_passed(Us, s));
|
assert(pos.pawn_passed(Us, s));
|
||||||
|
assert(!(pos.pieces(PAWN) & forward_bb(Us, s)));
|
||||||
|
|
||||||
int r = relative_rank(Us, s) - RANK_2;
|
int r = relative_rank(Us, s) - RANK_2;
|
||||||
int rr = r * (r - 1);
|
int rr = r * (r - 1);
|
||||||
@@ -722,7 +753,7 @@ namespace {
|
|||||||
// Endgame with opposite-colored bishops, but also other pieces. Still
|
// Endgame with opposite-colored bishops, but also other pieces. Still
|
||||||
// a bit drawish, but not as drawish as with only the two bishops.
|
// a bit drawish, but not as drawish as with only the two bishops.
|
||||||
else
|
else
|
||||||
sf = ScaleFactor(46 * sf / SCALE_FACTOR_NORMAL);
|
sf = ScaleFactor(46);
|
||||||
}
|
}
|
||||||
// Endings where weaker side can place his king in front of the opponent's
|
// Endings where weaker side can place his king in front of the opponent's
|
||||||
// pawns are drawish.
|
// pawns are drawish.
|
||||||
@@ -769,6 +800,8 @@ Value Eval::evaluate(const Position& pos) {
|
|||||||
|
|
||||||
// Initialize attack and king safety bitboards
|
// Initialize attack and king safety bitboards
|
||||||
ei.attackedBy[WHITE][ALL_PIECES] = ei.attackedBy[BLACK][ALL_PIECES] = 0;
|
ei.attackedBy[WHITE][ALL_PIECES] = ei.attackedBy[BLACK][ALL_PIECES] = 0;
|
||||||
|
ei.attackedBy[WHITE][KING] = pos.attacks_from<KING>(pos.square<KING>(WHITE));
|
||||||
|
ei.attackedBy[BLACK][KING] = pos.attacks_from<KING>(pos.square<KING>(BLACK));
|
||||||
eval_init<WHITE>(pos, ei);
|
eval_init<WHITE>(pos, ei);
|
||||||
eval_init<BLACK>(pos, ei);
|
eval_init<BLACK>(pos, ei);
|
||||||
|
|
||||||
|
|||||||
@@ -50,9 +50,9 @@ struct Entry {
|
|||||||
// the position. For instance, in KBP vs K endgames, the scaling function looks
|
// the position. For instance, in KBP vs K endgames, the scaling function looks
|
||||||
// for rook pawns and wrong-colored bishops.
|
// for rook pawns and wrong-colored bishops.
|
||||||
ScaleFactor scale_factor(const Position& pos, Color c) const {
|
ScaleFactor scale_factor(const Position& pos, Color c) const {
|
||||||
return !scalingFunction[c]
|
ScaleFactor sf = scalingFunction[c] ? (*scalingFunction[c])(pos)
|
||||||
|| (*scalingFunction[c])(pos) == SCALE_FACTOR_NONE ? ScaleFactor(factor[c])
|
: SCALE_FACTOR_NONE;
|
||||||
: (*scalingFunction[c])(pos);
|
return sf != SCALE_FACTOR_NONE ? sf : ScaleFactor(factor[c]);
|
||||||
}
|
}
|
||||||
|
|
||||||
Key key;
|
Key key;
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ namespace {
|
|||||||
|
|
||||||
/// Version number. If Version is left empty, then compile date in the format
|
/// Version number. If Version is left empty, then compile date in the format
|
||||||
/// DD-MM-YY and show in engine_info.
|
/// DD-MM-YY and show in engine_info.
|
||||||
const string Version = "2016-05-28";
|
const string Version = "2016-07-16";
|
||||||
|
|
||||||
/// Our fancy logging facility. The trick here is to replace cin.rdbuf() and
|
/// Our fancy logging facility. The trick here is to replace cin.rdbuf() and
|
||||||
/// cout.rdbuf() with two Tie objects that tie cin and cout to a file stream. We
|
/// cout.rdbuf() with two Tie objects that tie cin and cout to a file stream. We
|
||||||
@@ -65,23 +65,23 @@ struct Tie: public streambuf { // MSVC requires split streambuf for cin and cout
|
|||||||
class Logger {
|
class Logger {
|
||||||
|
|
||||||
Logger() : in(cin.rdbuf(), file.rdbuf()), out(cout.rdbuf(), file.rdbuf()) {}
|
Logger() : in(cin.rdbuf(), file.rdbuf()), out(cout.rdbuf(), file.rdbuf()) {}
|
||||||
~Logger() { start(false); }
|
~Logger() { start(""); }
|
||||||
|
|
||||||
ofstream file;
|
ofstream file;
|
||||||
Tie in, out;
|
Tie in, out;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static void start(bool b) {
|
static void start(const std::string& fname) {
|
||||||
|
|
||||||
static Logger l;
|
static Logger l;
|
||||||
|
|
||||||
if (b && !l.file.is_open())
|
if (!fname.empty() && !l.file.is_open())
|
||||||
{
|
{
|
||||||
l.file.open("io_log.txt", ifstream::out);
|
l.file.open(fname, ifstream::out);
|
||||||
cin.rdbuf(&l.in);
|
cin.rdbuf(&l.in);
|
||||||
cout.rdbuf(&l.out);
|
cout.rdbuf(&l.out);
|
||||||
}
|
}
|
||||||
else if (!b && l.file.is_open())
|
else if (fname.empty() && l.file.is_open())
|
||||||
{
|
{
|
||||||
cout.rdbuf(l.out.buf);
|
cout.rdbuf(l.out.buf);
|
||||||
cin.rdbuf(l.in.buf);
|
cin.rdbuf(l.in.buf);
|
||||||
@@ -157,7 +157,7 @@ std::ostream& operator<<(std::ostream& os, SyncCout sc) {
|
|||||||
|
|
||||||
|
|
||||||
/// Trampoline helper to avoid moving Logger to misc.h
|
/// Trampoline helper to avoid moving Logger to misc.h
|
||||||
void start_logger(bool b) { Logger::start(b); }
|
void start_logger(const std::string& fname) { Logger::start(fname); }
|
||||||
|
|
||||||
|
|
||||||
/// prefetch() preloads the given address in L1/L2 cache. This is a non-blocking
|
/// prefetch() preloads the given address in L1/L2 cache. This is a non-blocking
|
||||||
|
|||||||
@@ -32,7 +32,7 @@
|
|||||||
|
|
||||||
const std::string engine_info(bool to_uci = false);
|
const std::string engine_info(bool to_uci = false);
|
||||||
void prefetch(void* addr);
|
void prefetch(void* addr);
|
||||||
void start_logger(bool b);
|
void start_logger(const std::string& fname);
|
||||||
|
|
||||||
void dbg_hit_on(bool b);
|
void dbg_hit_on(bool b);
|
||||||
void dbg_hit_on(bool c, bool b);
|
void dbg_hit_on(bool c, bool b);
|
||||||
|
|||||||
@@ -148,9 +148,8 @@ namespace {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Passed pawns will be properly scored in evaluation because we need
|
// Passed pawns will be properly scored in evaluation because we need
|
||||||
// full attack info to evaluate them. Only the frontmost passed
|
// full attack info to evaluate them.
|
||||||
// pawn on each file is considered a true passed pawn.
|
if (!stoppers && !(ourPawns & forward_bb(Us, s)))
|
||||||
if (!(stoppers | doubled)) // FIXME this is just doubled by adjacent pawn
|
|
||||||
e->passedPawns[Us] |= s;
|
e->passedPawns[Us] |= s;
|
||||||
|
|
||||||
// Score this pawn
|
// Score this pawn
|
||||||
|
|||||||
@@ -261,19 +261,6 @@ void MainThread::search() {
|
|||||||
DrawValue[ us] = VALUE_DRAW - Value(contempt);
|
DrawValue[ us] = VALUE_DRAW - Value(contempt);
|
||||||
DrawValue[~us] = VALUE_DRAW + Value(contempt);
|
DrawValue[~us] = VALUE_DRAW + Value(contempt);
|
||||||
|
|
||||||
TB::Hits = 0;
|
|
||||||
TB::RootInTB = false;
|
|
||||||
TB::UseRule50 = Options["Syzygy50MoveRule"];
|
|
||||||
TB::ProbeDepth = Options["SyzygyProbeDepth"] * ONE_PLY;
|
|
||||||
TB::Cardinality = Options["SyzygyProbeLimit"];
|
|
||||||
|
|
||||||
// Skip TB probing when no TB found: !TBLargest -> !TB::Cardinality
|
|
||||||
if (TB::Cardinality > TB::MaxCardinality)
|
|
||||||
{
|
|
||||||
TB::Cardinality = TB::MaxCardinality;
|
|
||||||
TB::ProbeDepth = DEPTH_ZERO;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rootMoves.empty())
|
if (rootMoves.empty())
|
||||||
{
|
{
|
||||||
rootMoves.push_back(RootMove(MOVE_NONE));
|
rootMoves.push_back(RootMove(MOVE_NONE));
|
||||||
@@ -283,38 +270,6 @@ void MainThread::search() {
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if ( TB::Cardinality >= rootPos.count<ALL_PIECES>(WHITE)
|
|
||||||
+ rootPos.count<ALL_PIECES>(BLACK)
|
|
||||||
&& !rootPos.can_castle(ANY_CASTLING))
|
|
||||||
{
|
|
||||||
// If the current root position is in the tablebases, then RootMoves
|
|
||||||
// contains only moves that preserve the draw or the win.
|
|
||||||
TB::RootInTB = Tablebases::root_probe(rootPos, rootMoves, TB::Score);
|
|
||||||
|
|
||||||
if (TB::RootInTB)
|
|
||||||
TB::Cardinality = 0; // Do not probe tablebases during the search
|
|
||||||
|
|
||||||
else // If DTZ tables are missing, use WDL tables as a fallback
|
|
||||||
{
|
|
||||||
// Filter out moves that do not preserve the draw or the win.
|
|
||||||
TB::RootInTB = Tablebases::root_probe_wdl(rootPos, rootMoves, TB::Score);
|
|
||||||
|
|
||||||
// Only probe during search if winning
|
|
||||||
if (TB::RootInTB && TB::Score <= VALUE_DRAW)
|
|
||||||
TB::Cardinality = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (TB::RootInTB)
|
|
||||||
{
|
|
||||||
TB::Hits = rootMoves.size();
|
|
||||||
|
|
||||||
if (!TB::UseRule50)
|
|
||||||
TB::Score = TB::Score > VALUE_DRAW ? VALUE_MATE - MAX_PLY - 1
|
|
||||||
: TB::Score < VALUE_DRAW ? -VALUE_MATE + MAX_PLY + 1
|
|
||||||
: VALUE_DRAW;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (Thread* th : Threads)
|
for (Thread* th : Threads)
|
||||||
if (th != this)
|
if (th != this)
|
||||||
th->start_searching();
|
th->start_searching();
|
||||||
@@ -458,11 +413,6 @@ void Thread::search() {
|
|||||||
// search the already searched PV lines are preserved.
|
// search the already searched PV lines are preserved.
|
||||||
std::stable_sort(rootMoves.begin() + PVIdx, rootMoves.end());
|
std::stable_sort(rootMoves.begin() + PVIdx, rootMoves.end());
|
||||||
|
|
||||||
// Write PV back to the transposition table in case the relevant
|
|
||||||
// entries have been overwritten during the search.
|
|
||||||
for (size_t i = 0; i <= PVIdx; ++i)
|
|
||||||
rootMoves[i].insert_pv_in_tt(rootPos);
|
|
||||||
|
|
||||||
// If search has been stopped, break immediately. Sorting and
|
// If search has been stopped, break immediately. Sorting and
|
||||||
// writing PV back to TT is safe because RootMoves is still
|
// writing PV back to TT is safe because RootMoves is still
|
||||||
// valid, although it refers to the previous iteration.
|
// valid, although it refers to the previous iteration.
|
||||||
@@ -599,6 +549,7 @@ namespace {
|
|||||||
assert(-VALUE_INFINITE <= alpha && alpha < beta && beta <= VALUE_INFINITE);
|
assert(-VALUE_INFINITE <= alpha && alpha < beta && beta <= VALUE_INFINITE);
|
||||||
assert(PvNode || (alpha == beta - 1));
|
assert(PvNode || (alpha == beta - 1));
|
||||||
assert(DEPTH_ZERO < depth && depth < DEPTH_MAX);
|
assert(DEPTH_ZERO < depth && depth < DEPTH_MAX);
|
||||||
|
assert(!(PvNode && cutNode));
|
||||||
|
|
||||||
Move pv[MAX_PLY+1], quietsSearched[64];
|
Move pv[MAX_PLY+1], quietsSearched[64];
|
||||||
StateInfo st;
|
StateInfo st;
|
||||||
@@ -606,9 +557,9 @@ namespace {
|
|||||||
Key posKey;
|
Key posKey;
|
||||||
Move ttMove, move, excludedMove, bestMove;
|
Move ttMove, move, excludedMove, bestMove;
|
||||||
Depth extension, newDepth, predictedDepth;
|
Depth extension, newDepth, predictedDepth;
|
||||||
Value bestValue, value, ttValue, eval, nullValue, futilityValue;
|
Value bestValue, value, ttValue, eval, nullValue;
|
||||||
bool ttHit, inCheck, givesCheck, singularExtensionNode, improving;
|
bool ttHit, inCheck, givesCheck, singularExtensionNode, improving;
|
||||||
bool captureOrPromotion, doFullDepthSearch;
|
bool captureOrPromotion, doFullDepthSearch, moveCountPruning;
|
||||||
Piece moved_piece;
|
Piece moved_piece;
|
||||||
int moveCount, quietCount;
|
int moveCount, quietCount;
|
||||||
|
|
||||||
@@ -780,6 +731,7 @@ namespace {
|
|||||||
if ( !PvNode
|
if ( !PvNode
|
||||||
&& depth >= 2 * ONE_PLY
|
&& depth >= 2 * ONE_PLY
|
||||||
&& eval >= beta
|
&& eval >= beta
|
||||||
|
&& (ss->staticEval >= beta - 35 * (depth / ONE_PLY - 6) || depth >= 13 * ONE_PLY)
|
||||||
&& pos.non_pawn_material(pos.side_to_move()))
|
&& pos.non_pawn_material(pos.side_to_move()))
|
||||||
{
|
{
|
||||||
ss->currentMove = MOVE_NULL;
|
ss->currentMove = MOVE_NULL;
|
||||||
@@ -855,7 +807,7 @@ namespace {
|
|||||||
{
|
{
|
||||||
Depth d = depth - 2 * ONE_PLY - (PvNode ? DEPTH_ZERO : depth / 4);
|
Depth d = depth - 2 * ONE_PLY - (PvNode ? DEPTH_ZERO : depth / 4);
|
||||||
ss->skipEarlyPruning = true;
|
ss->skipEarlyPruning = true;
|
||||||
search<NT>(pos, ss, alpha, beta, d, true);
|
search<NT>(pos, ss, alpha, beta, d, cutNode);
|
||||||
ss->skipEarlyPruning = false;
|
ss->skipEarlyPruning = false;
|
||||||
|
|
||||||
tte = TT.probe(posKey, ttHit);
|
tte = TT.probe(posKey, ttHit);
|
||||||
@@ -864,7 +816,6 @@ namespace {
|
|||||||
|
|
||||||
moves_loop: // When in check search starts from here
|
moves_loop: // When in check search starts from here
|
||||||
|
|
||||||
Square prevSq = to_sq((ss-1)->currentMove);
|
|
||||||
const CounterMoveStats* cmh = (ss-1)->counterMoves;
|
const CounterMoveStats* cmh = (ss-1)->counterMoves;
|
||||||
const CounterMoveStats* fmh = (ss-2)->counterMoves;
|
const CounterMoveStats* fmh = (ss-2)->counterMoves;
|
||||||
const CounterMoveStats* fmh2 = (ss-4)->counterMoves;
|
const CounterMoveStats* fmh2 = (ss-4)->counterMoves;
|
||||||
@@ -873,7 +824,7 @@ moves_loop: // When in check search starts from here
|
|||||||
CheckInfo ci(pos);
|
CheckInfo ci(pos);
|
||||||
value = bestValue; // Workaround a bogus 'uninitialized' warning under gcc
|
value = bestValue; // Workaround a bogus 'uninitialized' warning under gcc
|
||||||
improving = ss->staticEval >= (ss-2)->staticEval
|
improving = ss->staticEval >= (ss-2)->staticEval
|
||||||
|| ss->staticEval == VALUE_NONE
|
/* || ss->staticEval == VALUE_NONE Already implicit in the previous condition */
|
||||||
||(ss-2)->staticEval == VALUE_NONE;
|
||(ss-2)->staticEval == VALUE_NONE;
|
||||||
|
|
||||||
singularExtensionNode = !rootNode
|
singularExtensionNode = !rootNode
|
||||||
@@ -919,8 +870,13 @@ moves_loop: // When in check search starts from here
|
|||||||
? ci.checkSquares[type_of(pos.piece_on(from_sq(move)))] & to_sq(move)
|
? ci.checkSquares[type_of(pos.piece_on(from_sq(move)))] & to_sq(move)
|
||||||
: pos.gives_check(move, ci);
|
: pos.gives_check(move, ci);
|
||||||
|
|
||||||
|
moveCountPruning = depth < 16 * ONE_PLY
|
||||||
|
&& moveCount >= FutilityMoveCounts[improving][depth];
|
||||||
|
|
||||||
// Step 12. Extend checks
|
// Step 12. Extend checks
|
||||||
if (givesCheck && pos.see_sign(move) >= VALUE_ZERO)
|
if ( givesCheck
|
||||||
|
&& !moveCountPruning
|
||||||
|
&& pos.see_sign(move) >= VALUE_ZERO)
|
||||||
extension = ONE_PLY;
|
extension = ONE_PLY;
|
||||||
|
|
||||||
// Singular extension search. If all moves but one fail low on a search of
|
// Singular extension search. If all moves but one fail low on a search of
|
||||||
@@ -956,8 +912,7 @@ moves_loop: // When in check search starts from here
|
|||||||
&& bestValue > VALUE_MATED_IN_MAX_PLY)
|
&& bestValue > VALUE_MATED_IN_MAX_PLY)
|
||||||
{
|
{
|
||||||
// Move count based pruning
|
// Move count based pruning
|
||||||
if ( depth < 16 * ONE_PLY
|
if (moveCountPruning)
|
||||||
&& moveCount >= FutilityMoveCounts[improving][depth])
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Countermoves based pruning
|
// Countermoves based pruning
|
||||||
@@ -971,16 +926,9 @@ moves_loop: // When in check search starts from here
|
|||||||
predictedDepth = std::max(newDepth - reduction<PvNode>(improving, depth, moveCount), DEPTH_ZERO);
|
predictedDepth = std::max(newDepth - reduction<PvNode>(improving, depth, moveCount), DEPTH_ZERO);
|
||||||
|
|
||||||
// Futility pruning: parent node
|
// Futility pruning: parent node
|
||||||
if (predictedDepth < 7 * ONE_PLY)
|
if ( predictedDepth < 7 * ONE_PLY
|
||||||
{
|
&& ss->staticEval + futility_margin(predictedDepth) + 256 <= alpha)
|
||||||
futilityValue = ss->staticEval + futility_margin(predictedDepth) + 256;
|
continue;
|
||||||
|
|
||||||
if (futilityValue <= alpha)
|
|
||||||
{
|
|
||||||
bestValue = std::max(bestValue, futilityValue);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prune moves with negative SEE at low depths
|
// Prune moves with negative SEE at low depths
|
||||||
if (predictedDepth < 4 * ONE_PLY && pos.see_sign(move) < VALUE_ZERO)
|
if (predictedDepth < 4 * ONE_PLY && pos.see_sign(move) < VALUE_ZERO)
|
||||||
@@ -1016,22 +964,21 @@ moves_loop: // When in check search starts from here
|
|||||||
+ (fmh2 ? (*fmh2)[moved_piece][to_sq(move)] : VALUE_ZERO);
|
+ (fmh2 ? (*fmh2)[moved_piece][to_sq(move)] : VALUE_ZERO);
|
||||||
|
|
||||||
// Increase reduction for cut nodes
|
// Increase reduction for cut nodes
|
||||||
if (!PvNode && cutNode)
|
if (cutNode)
|
||||||
r += ONE_PLY;
|
r += 2 * ONE_PLY;
|
||||||
|
|
||||||
// Decrease/increase reduction for moves with a good/bad history
|
|
||||||
int rHist = (val - 10000) / 20000;
|
|
||||||
r = std::max(DEPTH_ZERO, r - rHist * ONE_PLY);
|
|
||||||
|
|
||||||
// Decrease reduction for moves that escape a capture. Filter out
|
// Decrease reduction for moves that escape a capture. Filter out
|
||||||
// castling moves, because they are coded as "king captures rook" and
|
// castling moves, because they are coded as "king captures rook" and
|
||||||
// hence break make_move(). Also use see() instead of see_sign(),
|
// hence break make_move(). Also use see() instead of see_sign(),
|
||||||
// because the destination square is empty.
|
// because the destination square is empty.
|
||||||
if ( r
|
else if ( type_of(move) == NORMAL
|
||||||
&& type_of(move) == NORMAL
|
&& type_of(pos.piece_on(to_sq(move))) != PAWN
|
||||||
&& type_of(pos.piece_on(to_sq(move))) != PAWN
|
&& pos.see(make_move(to_sq(move), from_sq(move))) < VALUE_ZERO)
|
||||||
&& pos.see(make_move(to_sq(move), from_sq(move))) < VALUE_ZERO)
|
r -= 2 * ONE_PLY;
|
||||||
r = std::max(DEPTH_ZERO, r - ONE_PLY);
|
|
||||||
|
// Decrease/increase reduction for moves with a good/bad history
|
||||||
|
int rHist = (val - 10000) / 20000;
|
||||||
|
r = std::max(DEPTH_ZERO, r - rHist * ONE_PLY);
|
||||||
|
|
||||||
Depth d = std::max(newDepth - r, ONE_PLY);
|
Depth d = std::max(newDepth - r, ONE_PLY);
|
||||||
|
|
||||||
@@ -1159,11 +1106,11 @@ moves_loop: // When in check search starts from here
|
|||||||
// Bonus for prior countermove that caused the fail low
|
// Bonus for prior countermove that caused the fail low
|
||||||
else if ( depth >= 3 * ONE_PLY
|
else if ( depth >= 3 * ONE_PLY
|
||||||
&& !bestMove
|
&& !bestMove
|
||||||
&& !inCheck
|
|
||||||
&& !pos.captured_piece_type()
|
&& !pos.captured_piece_type()
|
||||||
&& is_ok((ss-1)->currentMove))
|
&& is_ok((ss-1)->currentMove))
|
||||||
{
|
{
|
||||||
Value bonus = Value((depth / ONE_PLY) * (depth / ONE_PLY) + depth / ONE_PLY - 1);
|
Square prevSq = to_sq((ss-1)->currentMove);
|
||||||
|
Value bonus = Value((depth / ONE_PLY) * (depth / ONE_PLY) + 2 * depth / ONE_PLY - 2);
|
||||||
if ((ss-2)->counterMoves)
|
if ((ss-2)->counterMoves)
|
||||||
(ss-2)->counterMoves->update(pos.piece_on(prevSq), prevSq, bonus);
|
(ss-2)->counterMoves->update(pos.piece_on(prevSq), prevSq, bonus);
|
||||||
|
|
||||||
@@ -1443,7 +1390,7 @@ moves_loop: // When in check search starts from here
|
|||||||
ss->killers[0] = move;
|
ss->killers[0] = move;
|
||||||
}
|
}
|
||||||
|
|
||||||
Value bonus = Value((depth / ONE_PLY) * (depth / ONE_PLY) + depth / ONE_PLY - 1);
|
Value bonus = Value((depth / ONE_PLY) * (depth / ONE_PLY) + 2 * depth / ONE_PLY - 2);
|
||||||
|
|
||||||
Square prevSq = to_sq((ss-1)->currentMove);
|
Square prevSq = to_sq((ss-1)->currentMove);
|
||||||
CounterMoveStats* cmh = (ss-1)->counterMoves;
|
CounterMoveStats* cmh = (ss-1)->counterMoves;
|
||||||
@@ -1484,13 +1431,13 @@ moves_loop: // When in check search starts from here
|
|||||||
if ((ss-1)->moveCount == 1 && !pos.captured_piece_type())
|
if ((ss-1)->moveCount == 1 && !pos.captured_piece_type())
|
||||||
{
|
{
|
||||||
if ((ss-2)->counterMoves)
|
if ((ss-2)->counterMoves)
|
||||||
(ss-2)->counterMoves->update(pos.piece_on(prevSq), prevSq, -bonus - 2 * (depth + 1) / ONE_PLY);
|
(ss-2)->counterMoves->update(pos.piece_on(prevSq), prevSq, -bonus - 2 * (depth + 1) / ONE_PLY - 1);
|
||||||
|
|
||||||
if ((ss-3)->counterMoves)
|
if ((ss-3)->counterMoves)
|
||||||
(ss-3)->counterMoves->update(pos.piece_on(prevSq), prevSq, -bonus - 2 * (depth + 1) / ONE_PLY);
|
(ss-3)->counterMoves->update(pos.piece_on(prevSq), prevSq, -bonus - 2 * (depth + 1) / ONE_PLY - 1);
|
||||||
|
|
||||||
if ((ss-5)->counterMoves)
|
if ((ss-5)->counterMoves)
|
||||||
(ss-5)->counterMoves->update(pos.piece_on(prevSq), prevSq, -bonus - 2 * (depth + 1) / ONE_PLY);
|
(ss-5)->counterMoves->update(pos.piece_on(prevSq), prevSq, -bonus - 2 * (depth + 1) / ONE_PLY - 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1613,33 +1560,6 @@ string UCI::pv(const Position& pos, Depth depth, Value alpha, Value beta) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// RootMove::insert_pv_in_tt() is called at the end of a search iteration, and
|
|
||||||
/// inserts the PV back into the TT. This makes sure the old PV moves are searched
|
|
||||||
/// first, even if the old TT entries have been overwritten.
|
|
||||||
|
|
||||||
void RootMove::insert_pv_in_tt(Position& pos) {
|
|
||||||
|
|
||||||
StateInfo state[MAX_PLY], *st = state;
|
|
||||||
bool ttHit;
|
|
||||||
|
|
||||||
for (Move m : pv)
|
|
||||||
{
|
|
||||||
assert(MoveList<LEGAL>(pos).contains(m));
|
|
||||||
|
|
||||||
TTEntry* tte = TT.probe(pos.key(), ttHit);
|
|
||||||
|
|
||||||
if (!ttHit || tte->move() != m) // Don't overwrite correct entries
|
|
||||||
tte->save(pos.key(), VALUE_NONE, BOUND_NONE, DEPTH_NONE,
|
|
||||||
m, VALUE_NONE, TT.generation());
|
|
||||||
|
|
||||||
pos.do_move(m, *st++, pos.gives_check(m, CheckInfo(pos)));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = pv.size(); i > 0; )
|
|
||||||
pos.undo_move(pv[--i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// RootMove::extract_ponder_from_tt() is called in case we have no ponder move
|
/// RootMove::extract_ponder_from_tt() is called in case we have no ponder move
|
||||||
/// before exiting the search, for instance, in case we stop the search during a
|
/// before exiting the search, for instance, in case we stop the search during a
|
||||||
/// fail high at root. We try hard to have a ponder move to return to the GUI,
|
/// fail high at root. We try hard to have a ponder move to return to the GUI,
|
||||||
@@ -1654,14 +1574,60 @@ bool RootMove::extract_ponder_from_tt(Position& pos)
|
|||||||
|
|
||||||
pos.do_move(pv[0], st, pos.gives_check(pv[0], CheckInfo(pos)));
|
pos.do_move(pv[0], st, pos.gives_check(pv[0], CheckInfo(pos)));
|
||||||
TTEntry* tte = TT.probe(pos.key(), ttHit);
|
TTEntry* tte = TT.probe(pos.key(), ttHit);
|
||||||
pos.undo_move(pv[0]);
|
|
||||||
|
|
||||||
if (ttHit)
|
if (ttHit)
|
||||||
{
|
{
|
||||||
Move m = tte->move(); // Local copy to be SMP safe
|
Move m = tte->move(); // Local copy to be SMP safe
|
||||||
if (MoveList<LEGAL>(pos).contains(m))
|
if (MoveList<LEGAL>(pos).contains(m))
|
||||||
return pv.push_back(m), true;
|
pv.push_back(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
pos.undo_move(pv[0]);
|
||||||
|
return pv.size() > 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Tablebases::filter_root_moves(Position& pos, Search::RootMoves& rootMoves) {
|
||||||
|
|
||||||
|
Hits = 0;
|
||||||
|
RootInTB = false;
|
||||||
|
UseRule50 = Options["Syzygy50MoveRule"];
|
||||||
|
ProbeDepth = Options["SyzygyProbeDepth"] * ONE_PLY;
|
||||||
|
Cardinality = Options["SyzygyProbeLimit"];
|
||||||
|
|
||||||
|
// Skip TB probing when no TB found: !TBLargest -> !TB::Cardinality
|
||||||
|
if (Cardinality > MaxCardinality)
|
||||||
|
{
|
||||||
|
Cardinality = MaxCardinality;
|
||||||
|
ProbeDepth = DEPTH_ZERO;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Cardinality < popcount(pos.pieces()) || pos.can_castle(ANY_CASTLING))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// If the current root position is in the tablebases, then RootMoves
|
||||||
|
// contains only moves that preserve the draw or the win.
|
||||||
|
RootInTB = root_probe(pos, rootMoves, TB::Score);
|
||||||
|
|
||||||
|
if (RootInTB)
|
||||||
|
Cardinality = 0; // Do not probe tablebases during the search
|
||||||
|
|
||||||
|
else // If DTZ tables are missing, use WDL tables as a fallback
|
||||||
|
{
|
||||||
|
// Filter out moves that do not preserve the draw or the win.
|
||||||
|
RootInTB = root_probe_wdl(pos, rootMoves, TB::Score);
|
||||||
|
|
||||||
|
// Only probe during search if winning
|
||||||
|
if (TB::RootInTB && TB::Score <= VALUE_DRAW)
|
||||||
|
Cardinality = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (RootInTB)
|
||||||
|
{
|
||||||
|
Hits = rootMoves.size();
|
||||||
|
|
||||||
|
if (!UseRule50)
|
||||||
|
TB::Score = TB::Score > VALUE_DRAW ? VALUE_MATE - MAX_PLY - 1
|
||||||
|
: TB::Score < VALUE_DRAW ? -VALUE_MATE + MAX_PLY + 1
|
||||||
|
: VALUE_DRAW;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,7 +59,6 @@ struct RootMove {
|
|||||||
|
|
||||||
bool operator<(const RootMove& m) const { return m.score < score; } // Descending sort
|
bool operator<(const RootMove& m) const { return m.score < score; } // Descending sort
|
||||||
bool operator==(const Move& m) const { return pv[0] == m; }
|
bool operator==(const Move& m) const { return pv[0] == m; }
|
||||||
void insert_pv_in_tt(Position& pos);
|
|
||||||
bool extract_ponder_from_tt(Position& pos);
|
bool extract_ponder_from_tt(Position& pos);
|
||||||
|
|
||||||
Value score = -VALUE_INFINITE;
|
Value score = -VALUE_INFINITE;
|
||||||
|
|||||||
@@ -343,31 +343,30 @@ void Tablebases::init(const std::string& path)
|
|||||||
init_tb(str);
|
init_tb(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (sizeof(char*) >= 8) {
|
if (sizeof(char*) >= 8) {
|
||||||
for (i = 1; i < 6; i++)
|
for (i = 1; i < 6; i++)
|
||||||
for (j = i; j < 6; j++)
|
for (j = i; j < 6; j++)
|
||||||
for (k = i; k < 6; k++)
|
for (k = i; k < 6; k++)
|
||||||
for (l = (i == k) ? j : k; l < 6; l++) {
|
for (l = (i == k) ? j : k; l < 6; l++) {
|
||||||
sprintf(str, "K%c%cvK%c%c", pchr[i], pchr[j], pchr[k], pchr[l]);
|
sprintf(str, "K%c%cvK%c%c", pchr[i], pchr[j], pchr[k], pchr[l]);
|
||||||
init_tb(str);
|
init_tb(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 1; i < 6; i++)
|
for (i = 1; i < 6; i++)
|
||||||
for (j = i; j < 6; j++)
|
for (j = i; j < 6; j++)
|
||||||
for (k = j; k < 6; k++)
|
for (k = j; k < 6; k++)
|
||||||
for (l = 1; l < 6; l++) {
|
for (l = 1; l < 6; l++) {
|
||||||
sprintf(str, "K%c%c%cvK%c", pchr[i], pchr[j], pchr[k], pchr[l]);
|
sprintf(str, "K%c%c%cvK%c", pchr[i], pchr[j], pchr[k], pchr[l]);
|
||||||
init_tb(str);
|
init_tb(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 1; i < 6; i++)
|
for (i = 1; i < 6; i++)
|
||||||
for (j = i; j < 6; j++)
|
for (j = i; j < 6; j++)
|
||||||
for (k = j; k < 6; k++)
|
for (k = j; k < 6; k++)
|
||||||
for (l = k; l < 6; l++) {
|
for (l = k; l < 6; l++) {
|
||||||
sprintf(str, "K%c%c%c%cvK", pchr[i], pchr[j], pchr[k], pchr[l]);
|
sprintf(str, "K%c%c%c%cvK", pchr[i], pchr[j], pchr[k], pchr[l]);
|
||||||
init_tb(str);
|
init_tb(str);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("info string Found %d tablebases.\n", TBnum_piece + TBnum_pawn);
|
printf("info string Found %d tablebases.\n", TBnum_piece + TBnum_pawn);
|
||||||
|
|||||||
@@ -495,7 +495,7 @@ static int probe_dtz_no_ep(Position& pos, int *success)
|
|||||||
|| !pos.legal(move, ci.pinned))
|
|| !pos.legal(move, ci.pinned))
|
||||||
continue;
|
continue;
|
||||||
pos.do_move(move, st, pos.gives_check(move, ci));
|
pos.do_move(move, st, pos.gives_check(move, ci));
|
||||||
int v = -probe_ab(pos, -2, -wdl + 1, success);
|
int v = -Tablebases::probe_wdl(pos, success);
|
||||||
pos.undo_move(move);
|
pos.undo_move(move);
|
||||||
if (*success == 0) return 0;
|
if (*success == 0) return 0;
|
||||||
if (v == wdl)
|
if (v == wdl)
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ int probe_wdl(Position& pos, int *success);
|
|||||||
int probe_dtz(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);
|
||||||
|
void filter_root_moves(Position& pos, Search::RootMoves& rootMoves);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
#include "search.h"
|
#include "search.h"
|
||||||
#include "thread.h"
|
#include "thread.h"
|
||||||
#include "uci.h"
|
#include "uci.h"
|
||||||
|
#include "syzygy/tbprobe.h"
|
||||||
|
|
||||||
ThreadPool Threads; // Global object
|
ThreadPool Threads; // Global object
|
||||||
|
|
||||||
@@ -169,7 +170,7 @@ int64_t ThreadPool::nodes_searched() {
|
|||||||
/// ThreadPool::start_thinking() wakes up the main thread sleeping in idle_loop()
|
/// ThreadPool::start_thinking() wakes up the main thread sleeping in idle_loop()
|
||||||
/// and starts a new search, then returns immediately.
|
/// and starts a new search, then returns immediately.
|
||||||
|
|
||||||
void ThreadPool::start_thinking(const Position& pos, StateListPtr& states,
|
void ThreadPool::start_thinking(Position& pos, StateListPtr& states,
|
||||||
const Search::LimitsType& limits) {
|
const Search::LimitsType& limits) {
|
||||||
|
|
||||||
main()->wait_for_search_finished();
|
main()->wait_for_search_finished();
|
||||||
@@ -183,6 +184,8 @@ void ThreadPool::start_thinking(const Position& pos, StateListPtr& states,
|
|||||||
|| std::count(limits.searchmoves.begin(), limits.searchmoves.end(), m))
|
|| std::count(limits.searchmoves.begin(), limits.searchmoves.end(), m))
|
||||||
rootMoves.push_back(Search::RootMove(m));
|
rootMoves.push_back(Search::RootMove(m));
|
||||||
|
|
||||||
|
Tablebases::filter_root_moves(pos, rootMoves);
|
||||||
|
|
||||||
// After ownership transfer 'states' becomes empty, so if we stop the search
|
// After ownership transfer 'states' becomes empty, so if we stop the search
|
||||||
// and call 'go' again without setting a new position states.get() == NULL.
|
// and call 'go' again without setting a new position states.get() == NULL.
|
||||||
assert(states.get() || setupStates.get());
|
assert(states.get() || setupStates.get());
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ struct ThreadPool : public std::vector<Thread*> {
|
|||||||
void exit(); // be initialized and valid during the whole thread lifetime.
|
void exit(); // be initialized and valid during the whole thread lifetime.
|
||||||
|
|
||||||
MainThread* main() { return static_cast<MainThread*>(at(0)); }
|
MainThread* main() { return static_cast<MainThread*>(at(0)); }
|
||||||
void start_thinking(const Position&, StateListPtr&, const Search::LimitsType&);
|
void start_thinking(Position&, StateListPtr&, const Search::LimitsType&);
|
||||||
void read_uci_options();
|
void read_uci_options();
|
||||||
int64_t nodes_searched();
|
int64_t nodes_searched();
|
||||||
|
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ namespace {
|
|||||||
// the thinking time and other parameters from the input string, then starts
|
// the thinking time and other parameters from the input string, then starts
|
||||||
// the search.
|
// the search.
|
||||||
|
|
||||||
void go(const Position& pos, istringstream& is) {
|
void go(Position& pos, istringstream& is) {
|
||||||
|
|
||||||
Search::LimitsType limits;
|
Search::LimitsType limits;
|
||||||
string token;
|
string token;
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ void init(OptionsMap& o) {
|
|||||||
|
|
||||||
const int MaxHashMB = Is64Bit ? 1024 * 1024 : 2048;
|
const int MaxHashMB = Is64Bit ? 1024 * 1024 : 2048;
|
||||||
|
|
||||||
o["Write Debug Log"] << Option(false, on_logger);
|
o["Debug Log File"] << Option("", on_logger);
|
||||||
o["Contempt"] << Option(0, -100, 100);
|
o["Contempt"] << Option(0, -100, 100);
|
||||||
o["Threads"] << Option(1, 1, 128, on_threads);
|
o["Threads"] << Option(1, 1, 128, on_threads);
|
||||||
o["Hash"] << Option(16, 1, MaxHashMB, on_hash_size);
|
o["Hash"] << Option(16, 1, MaxHashMB, on_hash_size);
|
||||||
|
|||||||
Reference in New Issue
Block a user