refactor: 清理无用代码
This commit is contained in:
parent
7594c6e31d
commit
3726ad9635
|
@ -456,7 +456,6 @@
|
|||
<ClInclude Include="src\movegen.h" />
|
||||
<ClInclude Include="src\movepick.h" />
|
||||
<ClInclude Include="src\search.h" />
|
||||
<ClInclude Include="src\timeman.h" />
|
||||
<ClInclude Include="src\trainer.h" />
|
||||
<ClInclude Include="src\tt.h" />
|
||||
<ClInclude Include="src\debug.h" />
|
||||
|
@ -720,7 +719,6 @@
|
|||
<ClCompile Include="src\movegen.cpp" />
|
||||
<ClCompile Include="src\movepick.cpp" />
|
||||
<ClCompile Include="src\search.cpp" />
|
||||
<ClCompile Include="src\timeman.cpp" />
|
||||
<ClCompile Include="src\trainer.cpp" />
|
||||
<ClCompile Include="src\tt.cpp" />
|
||||
<ClCompile Include="src\misc.cpp" />
|
||||
|
|
|
@ -120,9 +120,6 @@
|
|||
<ClInclude Include="src\uci.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\timeman.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\thread_win32_osx.h">
|
||||
<Filter>Qt Files</Filter>
|
||||
</ClInclude>
|
||||
|
@ -356,9 +353,6 @@
|
|||
<ClCompile Include="src\ucioption.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\timeman.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\benchmark.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
|
|
|
@ -35,11 +35,6 @@ enum Tracing
|
|||
NO_TRACE, TRACE
|
||||
};
|
||||
|
||||
double to_cp(Value v)
|
||||
{
|
||||
return double(v) / StoneValue;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
using namespace Trace;
|
||||
|
@ -176,37 +171,15 @@ Value Eval::evaluate(Position &pos)
|
|||
/// a string (suitable for outputting to stdout) that contains the detailed
|
||||
/// descriptions and values of each evaluation term. Useful for debugging.
|
||||
|
||||
std::string Eval::trace(const Position &pos)
|
||||
std::string Eval::trace(Position &pos)
|
||||
{
|
||||
#if 0
|
||||
std::memset(scores, 0, sizeof(scores));
|
||||
Value v = Evaluation<TRACE>(pos).value();
|
||||
|
||||
// TODO
|
||||
//pos.this_thread()->contempt = 0 // TODO: SCORE_ZERO; // Reset any dynamic contempt
|
||||
|
||||
Value v = Evaluation<TRACE>(pos)->value();
|
||||
|
||||
v = pos.side_to_move() == WHITE ? v : -v; // Trace scores are from white's point of view
|
||||
v = pos.side_to_move() == BLACK ? v : -v; // Trace scores are from black's point of view
|
||||
|
||||
std::stringstream ss;
|
||||
ss << std::showpoint << std::noshowpos << std::fixed << std::setprecision(2)
|
||||
<< " Term | White | Black | Total \n"
|
||||
<< " | MG EG | MG EG | MG EG \n"
|
||||
<< " ------------+-------------+-------------+------------\n"
|
||||
<< " Material | " << Term(MATERIAL)
|
||||
<< " Imbalance | " << Term(IMBALANCE)
|
||||
<< " Mobility | " << Term(MOBILITY)
|
||||
<< " Threats | " << Term(THREAT)
|
||||
<< " Passed | " << Term(PASSED)
|
||||
<< " Space | " << Term(SPACE)
|
||||
<< " Initiative | " << Term(INITIATIVE)
|
||||
<< " ------------+-------------+-------------+------------\n"
|
||||
<< " Total | " << Term(TOTAL);
|
||||
|
||||
ss << "\nTotal evaluation: " << to_cp(v) << " (white side)\n";
|
||||
ss << "\nTotal evaluation: " << v << " (black side)\n";
|
||||
|
||||
return ss.str();
|
||||
#endif
|
||||
//pos = pos;
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ class Position;
|
|||
|
||||
namespace Eval {
|
||||
|
||||
std::string trace(const Position &pos);
|
||||
std::string trace(Position &pos);
|
||||
|
||||
Value evaluate(Position &pos);
|
||||
};
|
||||
|
|
|
@ -133,7 +133,6 @@ template<>
|
|||
void MoveList<LEGAL>::create()
|
||||
{
|
||||
// Note: Not follow order of MoveDirection array
|
||||
#if 1
|
||||
const int moveTable_obliqueLine[SQUARE_NB][MD_NB] = {
|
||||
/* 0 */ {0, 0, 0, 0},
|
||||
/* 1 */ {0, 0, 0, 0},
|
||||
|
@ -227,101 +226,6 @@ void MoveList<LEGAL>::create()
|
|||
/* 38 */ {0, 0, 0, 0},
|
||||
/* 39 */ {0, 0, 0, 0},
|
||||
};
|
||||
#else
|
||||
const int moveTable_obliqueLine[Position::N_LOCATIONS][MD_NB] = {
|
||||
{0, 0, 0, 0},
|
||||
{0, 0, 0, 0},
|
||||
{0, 0, 0, 0},
|
||||
{0, 0, 0, 0},
|
||||
{0, 0, 0, 0},
|
||||
{0, 0, 0, 0},
|
||||
{0, 0, 0, 0},
|
||||
{0, 0, 0, 0},
|
||||
|
||||
{9, 15, 0, 16},
|
||||
{10, 8, 0, 17},
|
||||
{11, 9, 0, 18},
|
||||
{12, 10, 0, 19},
|
||||
{13, 11, 0, 20},
|
||||
{14, 12, 0, 21},
|
||||
{15, 13, 0, 22},
|
||||
{8, 14, 0, 23},
|
||||
|
||||
{17, 23, 8, 24},
|
||||
{18, 16, 9, 25},
|
||||
{19, 17, 10, 26},
|
||||
{20, 18, 11, 27},
|
||||
{21, 19, 12, 28},
|
||||
{22, 20, 13, 29},
|
||||
{23, 21, 14, 30},
|
||||
{16, 22, 15, 31},
|
||||
|
||||
{25, 31, 16, 0},
|
||||
{26, 24, 17, 0},
|
||||
{27, 25, 18, 0},
|
||||
{28, 26, 19, 0},
|
||||
{29, 27, 20, 0},
|
||||
{30, 28, 21, 0},
|
||||
{31, 29, 22, 0},
|
||||
{24, 30, 23, 0},
|
||||
|
||||
{0, 0, 0, 0},
|
||||
{0, 0, 0, 0},
|
||||
{0, 0, 0, 0},
|
||||
{0, 0, 0, 0},
|
||||
{0, 0, 0, 0},
|
||||
{0, 0, 0, 0},
|
||||
{0, 0, 0, 0},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
const int moveTable_noObliqueLine[Position::N_LOCATIONS][MD_NB] = {
|
||||
/* 0 */ {0, 0, 0, 0},
|
||||
/* 1 */ {0, 0, 0, 0},
|
||||
/* 2 */ {0, 0, 0, 0},
|
||||
/* 3 */ {0, 0, 0, 0},
|
||||
/* 4 */ {0, 0, 0, 0},
|
||||
/* 5 */ {0, 0, 0, 0},
|
||||
/* 6 */ {0, 0, 0, 0},
|
||||
/* 7 */ {0, 0, 0, 0},
|
||||
|
||||
/* 8 */ {9, 15, 0, 16},
|
||||
/* 9 */ {10, 8, 0, 0},
|
||||
/* 10 */ {11, 9, 0, 18},
|
||||
/* 11 */ {12, 10, 0, 0},
|
||||
/* 12 */ {13, 11, 0, 20},
|
||||
/* 13 */ {14, 12, 0, 0},
|
||||
/* 14 */ {15, 13, 0, 22},
|
||||
/* 15 */ {8, 14, 0, 0},
|
||||
|
||||
/* 16 */ {17, 23, 8, 24},
|
||||
/* 17 */ {18, 16, 0, 0},
|
||||
/* 18 */ {19, 17, 10, 26},
|
||||
/* 19 */ {20, 18, 0, 0},
|
||||
/* 20 */ {21, 19, 12, 28},
|
||||
/* 21 */ {22, 20, 0, 0},
|
||||
/* 22 */ {23, 21, 14, 30},
|
||||
/* 23 */ {16, 22, 0, 0},
|
||||
|
||||
/* 24 */ {25, 31, 16, 0},
|
||||
/* 25 */ {26, 24, 0, 0},
|
||||
/* 26 */ {27, 25, 18, 0},
|
||||
/* 27 */ {28, 26, 0, 0},
|
||||
/* 28 */ {29, 27, 20, 0},
|
||||
/* 29 */ {30, 28, 0, 0},
|
||||
/* 30 */ {31, 29, 22, 0},
|
||||
/* 31 */ {24, 30, 0, 0},
|
||||
|
||||
/* 32 */ {0, 0, 0, 0},
|
||||
/* 33 */ {0, 0, 0, 0},
|
||||
/* 34 */ {0, 0, 0, 0},
|
||||
/* 35 */ {0, 0, 0, 0},
|
||||
/* 36 */ {0, 0, 0, 0},
|
||||
/* 37 */ {0, 0, 0, 0},
|
||||
/* 38 */ {0, 0, 0, 0},
|
||||
/* 39 */ {0, 0, 0, 0},
|
||||
};
|
||||
#endif
|
||||
|
||||
if (rule->hasObliqueLines) {
|
||||
memcpy(moveTable, moveTable_obliqueLine, sizeof(moveTable));
|
||||
|
|
|
@ -21,9 +21,6 @@
|
|||
|
||||
#include "movepick.h"
|
||||
|
||||
// namespace
|
||||
// {
|
||||
|
||||
// partial_insertion_sort() sorts moves in descending order up to and including
|
||||
// a given limit. The order of moves smaller than the limit is left unspecified.
|
||||
void partial_insertion_sort(ExtMove *begin, ExtMove *end, int limit)
|
||||
|
@ -38,9 +35,6 @@ void partial_insertion_sort(ExtMove *begin, ExtMove *end, int limit)
|
|||
}
|
||||
}
|
||||
|
||||
//}
|
||||
|
||||
|
||||
/// Constructors of the MovePicker class. As arguments we pass information
|
||||
/// to help it to return the (presumably) good moves first, to decide which
|
||||
/// moves to return (in the quiescence search, for instance, we only want to
|
||||
|
@ -180,7 +174,7 @@ Move MovePicker::select(Pred filter)
|
|||
Move MovePicker::next_move()
|
||||
{
|
||||
endMoves = generate<LEGAL>(pos, moves);
|
||||
moveCount = endMoves - moves;
|
||||
moveCount = int(endMoves - moves);
|
||||
|
||||
score<LEGAL>();
|
||||
partial_insertion_sort(moves, endMoves, -100); // TODO: limit = -3000 * depth
|
||||
|
|
|
@ -107,34 +107,6 @@ enum StatsType
|
|||
NoCaptures, Captures
|
||||
};
|
||||
|
||||
/// ButterflyHistory records how often quiet moves have been successful or
|
||||
/// unsuccessful during the current search, and is used for reduction and move
|
||||
/// ordering decisions. It uses 2 tables (one for each color) indexed by
|
||||
/// 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
|
||||
constexpr int MAX_LPH = 4;
|
||||
typedef Stats<int16_t, 10692, MAX_LPH, int(SQUARE_NB) *int(SQUARE_NB)> LowPlyHistory;
|
||||
|
||||
/// CounterMoveHistory stores counter moves indexed by [piece][to] of the previous
|
||||
/// move, see www.chessprogramming.org/Countermove_Heuristic
|
||||
typedef Stats<Move, NOT_USED, PIECE_NB, SQUARE_NB> CounterMoveHistory;
|
||||
|
||||
/// CapturePieceToHistory is addressed by a move's [piece][to][captured piece type]
|
||||
typedef Stats<int16_t, 10692, PIECE_NB, SQUARE_NB, PIECE_TYPE_NB> CapturePieceToHistory;
|
||||
|
||||
/// PieceToHistory is like ButterflyHistory but is addressed by a move's [piece][to]
|
||||
typedef Stats<int16_t, 29952, PIECE_NB, SQUARE_NB> PieceToHistory;
|
||||
|
||||
/// ContinuationHistory is the combined history of a given pair of moves, usually
|
||||
/// the current one given a previous one. The nested history table is based on
|
||||
/// PieceToHistory instead of ButterflyBoards.
|
||||
typedef Stats<PieceToHistory, NOT_USED, PIECE_NB, SQUARE_NB> ContinuationHistory;
|
||||
|
||||
|
||||
/// MovePicker class is used to pick one pseudo legal move at a time from the
|
||||
/// current position. The most important method is next_move(), which returns a
|
||||
/// new pseudo legal move each time it is called, until there are no moves left,
|
||||
|
@ -155,7 +127,6 @@ public:
|
|||
|
||||
Move next_move();
|
||||
|
||||
//private:
|
||||
template<PickType T, typename Pred> Move select(Pred);
|
||||
template<GenType> void score();
|
||||
ExtMove *begin()
|
||||
|
|
|
@ -112,4 +112,3 @@ bool GameOptions::getOpeningBook()
|
|||
{
|
||||
return openingBook;
|
||||
}
|
||||
|
||||
|
|
|
@ -125,25 +125,6 @@ std::ostream &operator<<(std::ostream &os, const Position &pos)
|
|||
}
|
||||
|
||||
|
||||
// Marcel van Kervinck's cuckoo algorithm for fast detection of "upcoming repetition"
|
||||
// situations. Description of the algorithm in the following paper:
|
||||
// https://marcelk.net/2013-04-06/paper/upcoming-rep-v2.pdf
|
||||
|
||||
// First and second hash functions for indexing the cuckoo tables
|
||||
inline int H1(Key h)
|
||||
{
|
||||
return h & 0x1fff;
|
||||
}
|
||||
inline int H2(Key h)
|
||||
{
|
||||
return (h >> 16) & 0x1fff;
|
||||
}
|
||||
|
||||
// Cuckoo tables with Zobrist hashes of valid reversible moves, and the moves themselves
|
||||
Key cuckoo[8192];
|
||||
Move cuckooMove[8192];
|
||||
|
||||
|
||||
/// Position::init() initializes at startup the various arrays used to compute
|
||||
/// hash keys.
|
||||
|
||||
|
@ -157,18 +138,11 @@ void Position::init()
|
|||
|
||||
Zobrist::side = rng.rand<Key>() << Zobrist::KEY_MISC_BIT >> Zobrist::KEY_MISC_BIT;
|
||||
|
||||
// Prepare the cuckoo tables
|
||||
std::memset(cuckoo, 0, sizeof(cuckoo));
|
||||
std::memset(cuckooMove, 0, sizeof(cuckooMove));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Position::Position()
|
||||
{
|
||||
// TODO
|
||||
//st = &tmpSt;
|
||||
|
||||
construct_key();
|
||||
|
||||
if (rule == nullptr) {
|
||||
|
@ -187,7 +161,7 @@ Position::Position()
|
|||
/// This function is not very robust - make sure that input FENs are correct,
|
||||
/// this is assumed to be the responsibility of the GUI.
|
||||
|
||||
Position &Position::set(const string &fenStr, StateInfo *si, Thread *th)
|
||||
Position &Position::set(const string &fenStr, Thread *th)
|
||||
{
|
||||
/*
|
||||
A FEN string defines a particular position using only the ASCII character set.
|
||||
|
@ -220,7 +194,6 @@ Position &Position::set(const string &fenStr, StateInfo *si, Thread *th)
|
|||
*/
|
||||
|
||||
unsigned char token;
|
||||
size_t idx;
|
||||
Square sq = SQ_A1;
|
||||
std::istringstream ss(fenStr);
|
||||
|
||||
|
@ -229,9 +202,6 @@ Position &Position::set(const string &fenStr, StateInfo *si, Thread *th)
|
|||
}
|
||||
|
||||
std::memset(this, 0, sizeof(Position));
|
||||
//std::memset(si, 0, sizeof(StateInfo));
|
||||
//std::fill_n(&pieceList[0][0], sizeof(pieceList) / sizeof(Square), SQ_NONE);
|
||||
//st = si;
|
||||
|
||||
ss >> std::noskipws;
|
||||
|
||||
|
@ -302,7 +272,6 @@ Position &Position::set(const string &fenStr, StateInfo *si, Thread *th)
|
|||
gamePly = std::max(2 * (gamePly - 1), 0) + (sideToMove == WHITE);
|
||||
|
||||
thisThread = th;
|
||||
//set_state(st);
|
||||
|
||||
assert(pos_is_ok());
|
||||
out:
|
||||
|
@ -310,55 +279,6 @@ out:
|
|||
}
|
||||
|
||||
|
||||
/// Position::set_state() computes the hash keys of the position, and other
|
||||
/// data that once computed is updated incrementally as moves are made.
|
||||
/// The function is only used when a new position is set up, and to verify
|
||||
/// the correctness of the StateInfo data when running in debug mode.
|
||||
|
||||
void Position::set_state(StateInfo *si) const
|
||||
{
|
||||
// TODO
|
||||
#if 0
|
||||
si->key = 0;
|
||||
|
||||
for (Bitboard b = pieces(); b; ) {
|
||||
Square s = pop_lsb(&b);
|
||||
Piece pc = piece_on(s);
|
||||
si->key ^= Zobrist::psq[pc][s];
|
||||
}
|
||||
|
||||
if (sideToMove == BLACK)
|
||||
si->key ^= Zobrist::side;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// TODO
|
||||
#if 0
|
||||
/// Position::set() is an overload to initialize the position object with
|
||||
/// the given endgame code string like "KBPKN". It is mainly a helper to
|
||||
/// get the material key out of an endgame code.
|
||||
|
||||
Position &Position::set(const string &code, Color c, StateInfo *si)
|
||||
{
|
||||
assert(code[0] == 'K');
|
||||
|
||||
string sides[] = { code.substr(code.find('K', 1)), // Weak
|
||||
code.substr(0, std::min(code.find('v'), code.find('K', 1))) }; // Strong
|
||||
|
||||
assert(sides[0].length() > 0 && sides[0].length() < 8);
|
||||
assert(sides[1].length() > 0 && sides[1].length() < 8);
|
||||
|
||||
std::transform(sides[c].begin(), sides[c].end(), sides[c].begin(), tolower);
|
||||
|
||||
string fenStr = "8/" + sides[0] + char(8 - sides[0].length() + '0') + "/8/8/8/8/"
|
||||
+ sides[1] + char(8 - sides[1].length() + '0') + "/8 w - - 0 10";
|
||||
|
||||
return set(fenStr, si, nullptr);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/// Position::fen() returns a FEN representation of the position. In case of
|
||||
/// Chess960 the Shredder-FEN notation is used. This is mainly a debugging function.
|
||||
|
||||
|
@ -477,7 +397,7 @@ bool Position::pseudo_legal(const Move m) const
|
|||
/// to a StateInfo object. The move is assumed to be legal. Pseudo-legal
|
||||
/// moves should be filtered out before this function is called.
|
||||
|
||||
void Position::do_move(Move m, StateInfo &newSt)
|
||||
void Position::do_move(Move m)
|
||||
{
|
||||
#if 0
|
||||
assert(is_ok(m));
|
||||
|
@ -1204,27 +1124,24 @@ inline void Position::set_gameover(Color w, GameOverReason reason)
|
|||
winner = w;
|
||||
}
|
||||
|
||||
int Position::update()
|
||||
void Position::update()
|
||||
{
|
||||
int ret = -1;
|
||||
int timePoint = -1;
|
||||
time_t *ourSeconds = &elapsedSeconds[sideToMove];
|
||||
time_t theirSeconds = elapsedSeconds[them];
|
||||
|
||||
if (!(phase & PHASE_PLAYING)) {
|
||||
return -1;
|
||||
return;
|
||||
}
|
||||
|
||||
currentTime = time(NULL);
|
||||
|
||||
if (timePoint >= *ourSeconds) {
|
||||
*ourSeconds = ret = timePoint;
|
||||
*ourSeconds = timePoint;
|
||||
startTime = currentTime - (elapsedSeconds[BLACK] + elapsedSeconds[WHITE]);
|
||||
} else {
|
||||
*ourSeconds = ret = currentTime - startTime - theirSeconds;
|
||||
*ourSeconds = currentTime - startTime - theirSeconds;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void Position::update_score()
|
||||
|
|
|
@ -42,17 +42,8 @@ struct StateInfo
|
|||
|
||||
// Not copied when making a move (will be recomputed anyhow)
|
||||
Key key;
|
||||
Piece capturedPiece;
|
||||
StateInfo *previous;
|
||||
int repetition;
|
||||
};
|
||||
|
||||
/// A list to keep track of the position states along the setup moves (from the
|
||||
/// start position to the position just before the search starts). Needed by
|
||||
/// 'draw by repetition' detection. Use a std::deque because pointers to
|
||||
/// elements are not invalidated upon list resizing.
|
||||
typedef std::unique_ptr<std::deque<StateInfo>> StateListPtr;
|
||||
|
||||
|
||||
/// Position class stores information regarding the board representation as
|
||||
/// pieces, side to move, hash keys, castling info, etc. Important methods are
|
||||
|
@ -71,8 +62,7 @@ public:
|
|||
Position &operator=(const Position &) = delete;
|
||||
|
||||
// FEN string input/output
|
||||
Position &set(const std::string &fenStr, StateInfo *si, Thread *th);
|
||||
Position &set(const std::string &code, Color c, StateInfo *si);
|
||||
Position &set(const std::string &fenStr, Thread *th);
|
||||
const std::string fen() const;
|
||||
|
||||
// Position representation
|
||||
|
@ -87,7 +77,7 @@ public:
|
|||
Piece moved_piece(Move m) const;
|
||||
|
||||
// Doing and undoing moves
|
||||
void do_move(Move m, StateInfo &newSt);
|
||||
void do_move(Move m);
|
||||
void undo_move(Move m);
|
||||
void undo_move(Sanmill::Stack<Position> &ss);
|
||||
void do_null_move();
|
||||
|
@ -124,7 +114,6 @@ public:
|
|||
|
||||
Piece *get_board() const;
|
||||
Square current_square() const;
|
||||
int get_step() const;
|
||||
enum Phase get_phase() const;
|
||||
enum Action get_action() const;
|
||||
const char *cmd_line() const;
|
||||
|
@ -135,7 +124,7 @@ public:
|
|||
bool start();
|
||||
bool resign(Color loser);
|
||||
bool command(const char *cmd);
|
||||
int update();
|
||||
void update();
|
||||
void update_score();
|
||||
bool check_gameover_condition();
|
||||
void remove_ban_stones();
|
||||
|
@ -181,11 +170,9 @@ public:
|
|||
void put_piece(Piece pc, Square s);
|
||||
bool put_piece(File file, Rank rank);
|
||||
bool put_piece(Square s, bool updateCmdlist = false);
|
||||
bool undo_put_piece(Square s);
|
||||
|
||||
bool remove_piece(File file, Rank rank);
|
||||
bool remove_piece(Square s, bool updateCmdlist = false);
|
||||
bool undo_remove_piece(Square s);
|
||||
|
||||
bool move_piece(File f1, Rank r1, File f2, Rank r2);
|
||||
bool move_piece(Square from, Square to);
|
||||
|
@ -323,10 +310,11 @@ inline bool Position::select_piece(File f, Rank r)
|
|||
return select_piece(make_square(f, r));
|
||||
}
|
||||
|
||||
#if 0
|
||||
inline void Position::put_piece(Piece pc, Square s)
|
||||
{
|
||||
// TODO: put_piece
|
||||
#if 0
|
||||
|
||||
board[s] = pc;
|
||||
byTypeBB[ALL_PIECES] |= s;
|
||||
byTypeBB[type_of(pc)] |= s;
|
||||
|
@ -334,8 +322,8 @@ inline void Position::put_piece(Piece pc, Square s)
|
|||
index[s] = pieceCount[pc]++;
|
||||
pieceList[pc][index[s]] = s;
|
||||
pieceCount[make_piece(color_of(pc), ALL_PIECES)]++;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
inline bool Position::put_piece(File f, Rank r)
|
||||
{
|
||||
|
|
|
@ -44,4 +44,3 @@ extern const struct Rule RULES[N_RULES];
|
|||
extern const struct Rule *rule;
|
||||
|
||||
#endif /* RULE_H */
|
||||
|
||||
|
|
354
src/search.cpp
354
src/search.cpp
|
@ -31,7 +31,6 @@
|
|||
#include "position.h"
|
||||
#include "search.h"
|
||||
#include "thread.h"
|
||||
#include "timeman.h"
|
||||
#include "tt.h"
|
||||
#include "uci.h"
|
||||
|
||||
|
@ -39,21 +38,6 @@
|
|||
#include "types.h"
|
||||
#include "option.h"
|
||||
|
||||
namespace Search
|
||||
{
|
||||
LimitsType Limits;
|
||||
}
|
||||
|
||||
namespace Tablebases
|
||||
{
|
||||
int Cardinality;
|
||||
bool RootInTB;
|
||||
bool UseRule50;
|
||||
Depth ProbeDepth;
|
||||
}
|
||||
|
||||
namespace TB = Tablebases;
|
||||
|
||||
using std::string;
|
||||
using Eval::evaluate;
|
||||
using namespace Search;
|
||||
|
@ -69,100 +53,6 @@ enum NodeType
|
|||
NonPV, PV
|
||||
};
|
||||
|
||||
// Skill structure is used to implement strength limit
|
||||
struct Skill
|
||||
{
|
||||
explicit Skill(int l) : level(l)
|
||||
{
|
||||
}
|
||||
bool enabled() const
|
||||
{
|
||||
return level < 20;
|
||||
}
|
||||
bool time_to_pick(Depth depth) const
|
||||
{
|
||||
return depth == 1 + level;
|
||||
}
|
||||
Move pick_best(size_t multiPV);
|
||||
|
||||
int level;
|
||||
Move best = MOVE_NONE;
|
||||
};
|
||||
|
||||
// Breadcrumbs are used to mark nodes as being searched by a given thread
|
||||
struct Breadcrumb
|
||||
{
|
||||
std::atomic<Thread *> thread;
|
||||
std::atomic<Key> key;
|
||||
};
|
||||
std::array<Breadcrumb, 1024> breadcrumbs;
|
||||
|
||||
// ThreadHolding structure keeps track of which thread left breadcrumbs at the given
|
||||
// node for potential reductions. A free node will be marked upon entering the moves
|
||||
// loop by the constructor, and unmarked upon leaving that loop by the destructor.
|
||||
struct ThreadHolding
|
||||
{
|
||||
explicit ThreadHolding(Thread *thisThread, Key posKey, int ply)
|
||||
{
|
||||
location = ply < 8 ? &breadcrumbs[posKey & (breadcrumbs.size() - 1)] : nullptr;
|
||||
otherThread = false;
|
||||
owning = false;
|
||||
if (location) {
|
||||
// See if another already marked this location, if not, mark it ourselves
|
||||
Thread *tmp = (*location).thread.load(std::memory_order_relaxed);
|
||||
if (tmp == nullptr) {
|
||||
(*location).thread.store(thisThread, std::memory_order_relaxed);
|
||||
(*location).key.store(posKey, std::memory_order_relaxed);
|
||||
owning = true;
|
||||
} else if (tmp != thisThread
|
||||
&& (*location).key.load(std::memory_order_relaxed) == posKey)
|
||||
otherThread = true;
|
||||
}
|
||||
}
|
||||
|
||||
~ThreadHolding()
|
||||
{
|
||||
if (owning) // Free the marked location
|
||||
(*location).thread.store(nullptr, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
bool marked()
|
||||
{
|
||||
return otherThread;
|
||||
}
|
||||
|
||||
private:
|
||||
Breadcrumb *location;
|
||||
bool otherThread, owning;
|
||||
};
|
||||
|
||||
template <NodeType NT>
|
||||
Value search(Position &pos, Stack *ss, Value alpha, Value beta, Depth depth, bool cutNode);
|
||||
|
||||
// perft() is our utility to verify move generation. All the leaf nodes up
|
||||
// to the given depth are generated and counted, and the sum is returned.
|
||||
template<bool Root>
|
||||
uint64_t perft(Position &pos, Depth depth)
|
||||
{
|
||||
StateInfo st;
|
||||
uint64_t cnt, nodes = 0;
|
||||
const bool leaf = (depth == 2);
|
||||
|
||||
for (const auto &m : MoveList<LEGAL>(pos)) {
|
||||
if (Root && depth <= 1)
|
||||
cnt = 1, nodes++;
|
||||
else {
|
||||
pos.do_move(m, st);
|
||||
cnt = leaf ? MoveList<LEGAL>(pos).size() : perft<false>(pos, depth - 1);
|
||||
nodes += cnt;
|
||||
pos.undo_move(m);
|
||||
}
|
||||
if (Root)
|
||||
sync_cout << UCI::move(m) << ": " << cnt << sync_endl;
|
||||
}
|
||||
return nodes;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
|
@ -180,7 +70,6 @@ void Search::clear()
|
|||
{
|
||||
Threads.main()->wait_for_search_finished();
|
||||
|
||||
Time.availableNodes = 0;
|
||||
#ifdef TRANSPOSITION_TABLE_ENABLE
|
||||
TT.clear();
|
||||
#endif
|
||||
|
@ -188,106 +77,6 @@ void Search::clear()
|
|||
}
|
||||
|
||||
|
||||
/// MainThread::search() is started when the program receives the UCI 'go'
|
||||
/// command. It searches from the root position and outputs the "bestmove".
|
||||
|
||||
int MainThread::search()
|
||||
{
|
||||
if (Limits.perft) {
|
||||
nodes = perft<true>(*rootPos, Limits.perft);
|
||||
sync_cout << "\nNodes searched: " << nodes << "\n" << sync_endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
Color us = rootPos->side_to_move();
|
||||
Time.init(Limits, us, rootPos->game_ply());
|
||||
//TT.new_search();
|
||||
|
||||
if (rootMoves.empty()) {
|
||||
rootMoves.emplace_back(MOVE_NONE);
|
||||
sync_cout << "info depth 0 score "
|
||||
<< UCI::value(rootPos->get_phase() == PHASE_GAMEOVER ? -VALUE_MATE : VALUE_DRAW) // TODO
|
||||
<< sync_endl;
|
||||
} else {
|
||||
for (Thread *th : Threads) {
|
||||
th->bestMoveChanges = 0;
|
||||
if (th != this)
|
||||
th->start_searching();
|
||||
}
|
||||
|
||||
Thread::search(); // Let's start searching!
|
||||
}
|
||||
|
||||
// When we reach the maximum depth, we can arrive here without a raise of
|
||||
// Threads.stop. However, if we are pondering or in an infinite search,
|
||||
// the UCI protocol states that we shouldn't print the best move before the
|
||||
// GUI sends a "stop" or "ponderhit" command. We therefore simply wait here
|
||||
// until the GUI sends one of those commands.
|
||||
|
||||
while (!Threads.stop && (ponder || Limits.infinite)) {
|
||||
} // Busy wait for a stop or a ponder reset
|
||||
|
||||
// Stop the threads if not already stopped (also raise the stop if
|
||||
// "ponderhit" just reset Threads.ponder).
|
||||
Threads.stop = true;
|
||||
|
||||
// Wait until all threads have finished
|
||||
for (Thread *th : Threads)
|
||||
if (th != this)
|
||||
th->wait_for_search_finished();
|
||||
|
||||
// When playing in 'nodes as time' mode, subtract the searched nodes from
|
||||
// the available ones before exiting.
|
||||
if (Limits.npmsec)
|
||||
Time.availableNodes += Limits.inc[us] - Threads.nodes_searched();
|
||||
|
||||
Thread *bestThread = this;
|
||||
|
||||
// Check if there are threads with a better score than main thread
|
||||
if (Options["MultiPV"] == 1
|
||||
&& !Limits.depth
|
||||
&& !(Skill((int)Options["Skill Level"]).enabled() || 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;
|
||||
}
|
||||
}
|
||||
|
||||
bestPreviousScore = bestThread->rootMoves[0].score;
|
||||
|
||||
// Send again PV info if we have a new best thread
|
||||
if (bestThread != this)
|
||||
sync_cout << UCI::pv(bestThread->rootPos, bestThread->completedDepth, -VALUE_INFINITE, VALUE_INFINITE) << sync_endl;
|
||||
|
||||
sync_cout << "bestmove " << UCI::move(bestThread->rootMoves[0].pv[0]);
|
||||
|
||||
if (bestThread->rootMoves[0].pv.size() > 1 /* || bestThread->rootMoves[0].extract_ponder_from_tt(rootPos) */)
|
||||
std::cout << " ponder " << UCI::move(bestThread->rootMoves[0].pv[1]);
|
||||
|
||||
std::cout << sync_endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/// Thread::search() is the main iterative deepening loop. It calls search()
|
||||
/// repeatedly with increasing depth until the allocated thinking time has been
|
||||
/// consumed, the user stops the search, or the maximum search depth is reached.
|
||||
|
@ -405,158 +194,17 @@ int Thread::search()
|
|||
}
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
// search<>() is the main search function for both PV and non-PV nodes
|
||||
|
||||
template <NodeType NT>
|
||||
Value search(Position &pos, Stack *ss, Value alpha, Value beta, Depth depth, bool cutNode)
|
||||
{
|
||||
//return MTDF(rootPos, ss, value, i, adjustedDepth, bestMove); // TODO;
|
||||
return VALUE_DRAW;
|
||||
}
|
||||
|
||||
|
||||
// When playing with strength handicap, choose best move among a set of RootMoves
|
||||
// using a statistical rule dependent on 'level'. Idea by Heinz van Saanen.
|
||||
|
||||
Move Skill::pick_best(size_t multiPV)
|
||||
{
|
||||
|
||||
const RootMoves &rootMoves = Threads.main()->rootMoves;
|
||||
static PRNG rng(now()); // PRNG sequence should be non-deterministic
|
||||
|
||||
// RootMoves are already sorted by score in descending order
|
||||
Value topScore = rootMoves[0].score;
|
||||
//int delta = std::min(topScore - rootMoves[multiPV - 1].score, PawnValueMg);
|
||||
int delta = std::min(topScore - rootMoves[multiPV - 1].score, StoneValue);
|
||||
int weakness = 120 - 2 * level;
|
||||
int maxScore = -VALUE_INFINITE;
|
||||
|
||||
// Choose best move. For each move score we add two terms, both dependent on
|
||||
// weakness. One is deterministic and bigger for weaker levels, and one is
|
||||
// random. Then we choose the move with the resulting highest score.
|
||||
for (size_t i = 0; i < multiPV; ++i) {
|
||||
// This is our magic formula
|
||||
int push = (weakness * int(topScore - rootMoves[i].score)
|
||||
+ delta * (rng.rand<unsigned>() % weakness)) / 128;
|
||||
|
||||
if (rootMoves[i].score + push >= maxScore) {
|
||||
maxScore = rootMoves[i].score + push;
|
||||
best = rootMoves[i].pv[0];
|
||||
}
|
||||
}
|
||||
|
||||
return best;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
/// MainThread::check_time() is used to print debug info and, more importantly,
|
||||
/// to detect when we are out of available time and thus stop the search.
|
||||
|
||||
void MainThread::check_time()
|
||||
{
|
||||
if (--callsCnt > 0)
|
||||
return;
|
||||
|
||||
// When using nodes, ensure checking rate is not lower than 0.1% of nodes
|
||||
callsCnt = Limits.nodes ? std::min(1024, int(Limits.nodes / 1024)) : 1024;
|
||||
|
||||
static TimePoint lastInfoTime = now();
|
||||
|
||||
TimePoint elapsed = Time.elapsed();
|
||||
TimePoint tick = Limits.startTime + elapsed;
|
||||
|
||||
if (tick - lastInfoTime >= 1000) {
|
||||
lastInfoTime = tick;
|
||||
dbg_print();
|
||||
}
|
||||
|
||||
// We should not stop pondering until told so by the GUI
|
||||
if (ponder)
|
||||
return;
|
||||
|
||||
if ((Limits.use_time_management() && (elapsed > Time.maximum() - 10 || stopOnPonderhit))
|
||||
|| (Limits.movetime && elapsed >= Limits.movetime)
|
||||
|| (Limits.nodes && Threads.nodes_searched() >= (uint64_t)Limits.nodes))
|
||||
Threads.stop = true;
|
||||
}
|
||||
|
||||
|
||||
/// UCI::pv() formats PV information according to the UCI protocol. UCI requires
|
||||
/// that all (if any) unsearched PV lines are sent using a previous search score.
|
||||
|
||||
string UCI::pv(const Position *pos, Depth depth, Value alpha, Value beta)
|
||||
{
|
||||
|
||||
std::stringstream ss;
|
||||
TimePoint elapsed = Time.elapsed() + 1;
|
||||
const RootMoves &rootMoves = pos->this_thread()->rootMoves;
|
||||
size_t pvIdx = pos->this_thread()->pvIdx;
|
||||
size_t multiPV = std::min((size_t)Options["MultiPV"], rootMoves.size());
|
||||
uint64_t nodesSearched = Threads.nodes_searched();
|
||||
uint64_t tbHits = Threads.tb_hits() + (TB::RootInTB ? rootMoves.size() : 0);
|
||||
|
||||
for (size_t i = 0; i < multiPV; ++i) {
|
||||
bool updated = rootMoves[i].score != -VALUE_INFINITE;
|
||||
|
||||
if (depth == 1 && !updated)
|
||||
continue;
|
||||
|
||||
Depth d = updated ? depth : depth - 1;
|
||||
Value v = updated ? rootMoves[i].score : rootMoves[i].previousScore;
|
||||
|
||||
bool tb = TB::RootInTB && abs(v) < VALUE_MATE_IN_MAX_PLY;
|
||||
v = tb ? rootMoves[i].tbScore : v;
|
||||
|
||||
if (ss.rdbuf()->in_avail()) // Not at first line
|
||||
ss << "\n";
|
||||
|
||||
ss << "info"
|
||||
<< " depth " << d
|
||||
<< " seldepth " << rootMoves[i].selDepth
|
||||
<< " multipv " << i + 1
|
||||
<< " score " << UCI::value(v);
|
||||
|
||||
if (!tb && i == pvIdx)
|
||||
ss << (v >= beta ? " lowerbound" : v <= alpha ? " upperbound" : "");
|
||||
|
||||
ss << " nodes " << nodesSearched
|
||||
<< " nps " << nodesSearched * 1000 / elapsed;
|
||||
|
||||
#if 0
|
||||
if (elapsed > 1000) // Earlier makes little sense
|
||||
ss << " hashfull " << TT.hashfull();
|
||||
#endif
|
||||
|
||||
ss << " tbhits " << tbHits
|
||||
<< " time " << elapsed
|
||||
<< " pv";
|
||||
|
||||
for (Move m : rootMoves[i].pv)
|
||||
ss << " " << UCI::move(m);
|
||||
}
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
extern ThreadPool Threads;
|
||||
|
||||
vector<Key> moveHistory;
|
||||
|
||||
|
||||
Value search(Position *pos, Sanmill::Stack<Position> &ss, Depth depth, Depth originDepth, Value alpha, Value beta, Move &bestMove)
|
||||
{
|
||||
Value value;
|
||||
Value bestValue = -VALUE_INFINITE;
|
||||
|
||||
StateInfo st; // TODO
|
||||
|
||||
Depth epsilon;
|
||||
|
||||
#ifdef TT_MOVE_ENABLE
|
||||
|
@ -690,7 +338,7 @@ Value search(Position *pos, Sanmill::Stack<Position> &ss, Depth depth, Depth ori
|
|||
ss.push(*(pos));
|
||||
Color before = pos->sideToMove;
|
||||
Move move = mp.moves[i].move;
|
||||
pos->do_move(move, st);
|
||||
pos->do_move(move);
|
||||
Color after = pos->sideToMove;
|
||||
|
||||
if (gameOptions.getDepthExtension() == true && moveCount == 1) {
|
||||
|
|
84
src/search.h
84
src/search.h
|
@ -32,94 +32,10 @@
|
|||
#include "stopwatch.h"
|
||||
#endif
|
||||
|
||||
class AIAlgorithm;
|
||||
class Node;
|
||||
class Position;
|
||||
class MovePicker;
|
||||
|
||||
using namespace std;
|
||||
using namespace CTSL;
|
||||
|
||||
namespace Search
|
||||
{
|
||||
/// Threshold used for countermoves based pruning
|
||||
constexpr int CounterMovePruneThreshold = 0;
|
||||
|
||||
|
||||
/// Stack struct keeps track of the information we need to remember from nodes
|
||||
/// shallower and deeper in the tree during the search. Each search thread has
|
||||
/// its own array of Stack objects, indexed by the current ply.
|
||||
|
||||
struct Stack
|
||||
{
|
||||
Move *pv;
|
||||
PieceToHistory *continuationHistory;
|
||||
int ply;
|
||||
Move currentMove;
|
||||
Move excludedMove;
|
||||
Move killers[2];
|
||||
Value staticEval;
|
||||
int statScore;
|
||||
int moveCount;
|
||||
};
|
||||
|
||||
|
||||
/// RootMove struct is used for moves at the root of the tree. For each root move
|
||||
/// we store a score and a PV (really a refutation in the case of moves which
|
||||
/// fail low). Score is normally set at -VALUE_INFINITE for all non-pv moves.
|
||||
|
||||
struct RootMove
|
||||
{
|
||||
explicit RootMove(Move m) : pv(1, m)
|
||||
{
|
||||
}
|
||||
bool operator==(const Move &m) const
|
||||
{
|
||||
return pv[0] == m;
|
||||
}
|
||||
bool operator<(const RootMove &m) const
|
||||
{ // Sort in descending order
|
||||
return m.score != score ? m.score < score
|
||||
: m.previousScore < previousScore;
|
||||
}
|
||||
|
||||
Value score = -VALUE_INFINITE;
|
||||
Value previousScore = -VALUE_INFINITE;
|
||||
int selDepth = 0;
|
||||
int tbRank = 0;
|
||||
int bestMoveCount = 0;
|
||||
Value tbScore;
|
||||
std::vector<Move> pv;
|
||||
};
|
||||
|
||||
typedef std::vector<RootMove> RootMoves;
|
||||
|
||||
|
||||
/// LimitsType struct stores information sent by GUI about available time to
|
||||
/// search the current move, maximum depth/time, or if we are in analysis mode.
|
||||
|
||||
struct LimitsType
|
||||
{
|
||||
LimitsType()
|
||||
{
|
||||
// Init explicitly due to broken value-initialization of non POD in MSVC
|
||||
time[WHITE] = time[BLACK] = inc[WHITE] = inc[BLACK] = npmsec = movetime = TimePoint(0);
|
||||
movestogo = depth = mate = perft = infinite = 0;
|
||||
nodes = 0;
|
||||
}
|
||||
|
||||
bool use_time_management() const
|
||||
{
|
||||
return !(mate | movetime | depth | nodes | perft | infinite);
|
||||
}
|
||||
|
||||
std::vector<Move> searchmoves;
|
||||
TimePoint time[COLOR_NB], inc[COLOR_NB], npmsec, movetime, startTime;
|
||||
int movestogo, depth, mate, perft, infinite;
|
||||
int64_t nodes;
|
||||
};
|
||||
|
||||
extern LimitsType Limits;
|
||||
|
||||
void init();
|
||||
void clear();
|
||||
|
|
|
@ -53,8 +53,6 @@ Thread::Thread(size_t n
|
|||
#endif
|
||||
timeLimit(3600)
|
||||
{
|
||||
//this->us = color;
|
||||
|
||||
wait_for_search_finished();
|
||||
}
|
||||
|
||||
|
@ -63,27 +61,17 @@ Thread::Thread(size_t n
|
|||
/// for its termination. Thread should be already waiting.
|
||||
|
||||
Thread::~Thread()
|
||||
{
|
||||
//delete server;
|
||||
//delete client
|
||||
|
||||
{
|
||||
assert(!searching);
|
||||
|
||||
exit = true;
|
||||
#ifdef HOSTORY_HEURISTIC
|
||||
clearHistoryScore();
|
||||
#endif // HOSTORY_HEURISTIC
|
||||
start_searching();
|
||||
stdThread.join();
|
||||
}
|
||||
|
||||
/// Thread::bestMoveCount(Move move) return best move counter for the given root move
|
||||
|
||||
int Thread::best_move_count(Move move) const
|
||||
{
|
||||
// TODO
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// Thread::clear() reset histories, usually before a new game
|
||||
|
||||
void Thread::clear()
|
||||
|
@ -125,24 +113,8 @@ void Thread::wait_for_search_finished()
|
|||
|
||||
void Thread::idle_loop()
|
||||
{
|
||||
#ifdef DEBUG_MODE
|
||||
int iTemp = 0;
|
||||
#endif
|
||||
|
||||
loggerDebug("Thread %d start\n", us);
|
||||
|
||||
bestvalue = lastvalue = VALUE_ZERO;
|
||||
|
||||
#if 0
|
||||
// If OS already scheduled us on a different group than 0 then don't overwrite
|
||||
// the choice, eventually we are one of many one-threaded processes running on
|
||||
// some Windows NUMA hardware, for instance in fishtest. To make it simple,
|
||||
// just check if running threads are below a threshold, in this case all this
|
||||
// NUMA machinery is not needed.
|
||||
if (Options["Threads"] > 8)
|
||||
WinProcGroup::bindThisThread(idx);
|
||||
#endif
|
||||
|
||||
while (true) {
|
||||
std::unique_lock<std::mutex> lk(mutex);
|
||||
searching = false;
|
||||
|
@ -183,20 +155,16 @@ void Thread::idle_loop()
|
|||
strCommand = nextMove();
|
||||
if (strCommand != "" && strCommand != "error!") {
|
||||
emitCommand();
|
||||
} else {
|
||||
int err = 1;
|
||||
}
|
||||
}
|
||||
#ifdef OPENING_BOOK
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
loggerDebug("Thread %d quit\n", us);
|
||||
}
|
||||
|
||||
|
||||
///////////////
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Thread::setAi(Position *p)
|
||||
{
|
||||
|
@ -517,9 +485,6 @@ void Thread::clearTT()
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
string Thread::nextMove()
|
||||
{
|
||||
#if 0
|
||||
|
@ -676,42 +641,18 @@ void ThreadPool::clear()
|
|||
{
|
||||
for (Thread *th : *this)
|
||||
th->clear();
|
||||
|
||||
main()->callsCnt = 0;
|
||||
main()->bestPreviousScore = VALUE_INFINITE;
|
||||
main()->previousTimeReduction = 1.0;
|
||||
}
|
||||
|
||||
/// ThreadPool::start_thinking() wakes up main thread waiting in idle_loop() and
|
||||
/// returns immediately. Main thread will wake up other threads and start the search.
|
||||
|
||||
void ThreadPool::start_thinking(Position *pos, StateListPtr &states,
|
||||
const Search::LimitsType &limits, bool ponderMode)
|
||||
void ThreadPool::start_thinking(Position *pos, bool ponderMode)
|
||||
{
|
||||
main()->wait_for_search_finished();
|
||||
|
||||
// main()->stopOnPonderhit = stop = false;
|
||||
// increaseDepth = true;
|
||||
// main()->ponder = ponderMode;
|
||||
// Search::Limits = limits;
|
||||
// Search::RootMoves rootMoves;
|
||||
|
||||
// for (const auto &m : MoveList<LEGAL>(*pos))
|
||||
// if (limits.searchmoves.empty()
|
||||
// || std::count(limits.searchmoves.begin(), limits.searchmoves.end(), m))
|
||||
// rootMoves.emplace_back(m);
|
||||
|
||||
#ifdef TBPROBE
|
||||
if (!rootMoves.empty())
|
||||
Tablebases::rank_root_moves(pos, rootMoves);
|
||||
#endif
|
||||
|
||||
// After ownership transfer 'states' becomes empty, so if we stop the search
|
||||
// and call 'go' again without setting a new position states.get() == NULL.
|
||||
//assert(states.get() || setupStates.get());
|
||||
|
||||
//if (states.get())
|
||||
// setupStates = std::move(states); // Ownership transfer, states is now empty
|
||||
main()->stopOnPonderhit = stop = false;
|
||||
increaseDepth = true;
|
||||
main()->ponder = ponderMode;
|
||||
|
||||
// We use Position::set() to set root position across threads. But there are
|
||||
// some StateInfo fields (previous, pliesFromNull, capturedPiece) that cannot
|
||||
|
@ -721,14 +662,10 @@ void ThreadPool::start_thinking(Position *pos, StateListPtr &states,
|
|||
//StateInfo tmp = setupStates->back();
|
||||
|
||||
for (Thread *th : *this) {
|
||||
//th->nodes = th->tbHits = th->nmpMinPly = 0;
|
||||
//th->rootDepth = th->completedDepth = 0;
|
||||
//th->rootMoves = rootMoves;
|
||||
// TODO
|
||||
//th->rootPos->set(pos->fen(), &setupStates->back(), th);
|
||||
th->rootPos = pos;
|
||||
}
|
||||
|
||||
//setupStates->back() = tmp;
|
||||
|
||||
main()->start_searching();
|
||||
}
|
||||
|
|
27
src/thread.h
27
src/thread.h
|
@ -64,17 +64,8 @@ public:
|
|||
void idle_loop();
|
||||
void start_searching();
|
||||
void wait_for_search_finished();
|
||||
int best_move_count(Move move) const;
|
||||
|
||||
size_t pvIdx, pvLast;
|
||||
uint64_t ttHitAverage;
|
||||
int selDepth, nmpMinPly;
|
||||
Color nmpColor;
|
||||
std::atomic<uint64_t> nodes, tbHits, bestMoveChanges;
|
||||
|
||||
Position *rootPos { nullptr };
|
||||
Search::RootMoves rootMoves;
|
||||
Depth rootDepth, completedDepth;
|
||||
|
||||
// Mill Game
|
||||
|
||||
|
@ -167,12 +158,6 @@ struct MainThread : public Thread
|
|||
{
|
||||
using Thread::Thread;
|
||||
|
||||
int search() /* override */;
|
||||
void check_time();
|
||||
|
||||
double previousTimeReduction;
|
||||
Value bestPreviousScore;
|
||||
Value iterValue[4];
|
||||
int callsCnt;
|
||||
bool stopOnPonderhit;
|
||||
std::atomic_bool ponder;
|
||||
|
@ -185,7 +170,7 @@ struct MainThread : public Thread
|
|||
|
||||
struct ThreadPool : public std::vector<Thread *>
|
||||
{
|
||||
void start_thinking(Position *, StateListPtr &, const Search::LimitsType &, bool = false);
|
||||
void start_thinking(Position *, bool = false);
|
||||
void clear();
|
||||
void set(size_t);
|
||||
|
||||
|
@ -193,20 +178,10 @@ struct ThreadPool : public std::vector<Thread *>
|
|||
{
|
||||
return static_cast<MainThread *>(front());
|
||||
}
|
||||
uint64_t nodes_searched() const
|
||||
{
|
||||
return accumulate(&Thread::nodes);
|
||||
}
|
||||
uint64_t tb_hits() const
|
||||
{
|
||||
return accumulate(&Thread::tbHits);
|
||||
}
|
||||
|
||||
std::atomic_bool stop, increaseDepth;
|
||||
|
||||
private:
|
||||
StateListPtr setupStates;
|
||||
|
||||
uint64_t accumulate(std::atomic<uint64_t> Thread:: *member) const
|
||||
{
|
||||
uint64_t sum = 0;
|
||||
|
|
136
src/timeman.cpp
136
src/timeman.cpp
|
@ -1,136 +0,0 @@
|
|||
/*
|
||||
Fishmill, a UCI Mill Game playing engine derived from Stockfish
|
||||
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
||||
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad (Stockfish author)
|
||||
Copyright (C) 2015-2020 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad (Stockfish author)
|
||||
Copyright (C) 2020 Calcitem <calcitem@outlook.com>
|
||||
|
||||
Fishmill is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Fishmill is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <cfloat>
|
||||
#include <cmath>
|
||||
|
||||
#include "search.h"
|
||||
#include "timeman.h"
|
||||
#include "uci.h"
|
||||
|
||||
TimeManagement Time; // Our global time management object
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
enum TimeType
|
||||
{
|
||||
OptimumTime, MaxTime
|
||||
};
|
||||
|
||||
constexpr int MoveHorizon = 50; // Plan time management at most this many moves ahead
|
||||
constexpr double MaxRatio = 7.3; // When in trouble, we can step over reserved time with this ratio
|
||||
constexpr double StealRatio = 0.34; // However we must not steal time from remaining moves over this ratio
|
||||
|
||||
|
||||
// move_importance() is a skew-logistic function based on naive statistical
|
||||
// analysis of "how many games are still undecided after n half-moves". Game
|
||||
// is considered "undecided" as long as neither side has >275cp advantage.
|
||||
// Data was extracted from the CCRL game database with some simple filtering criteria.
|
||||
|
||||
double move_importance(int ply)
|
||||
{
|
||||
constexpr double XScale = 6.85;
|
||||
constexpr double XShift = 64.5;
|
||||
constexpr double Skew = 0.171;
|
||||
|
||||
return pow((1 + exp((ply - XShift) / XScale)), -Skew) + DBL_MIN; // Ensure non-zero
|
||||
}
|
||||
|
||||
template<TimeType T>
|
||||
TimePoint remaining(TimePoint myTime, int movesToGo, int ply, TimePoint slowMover)
|
||||
{
|
||||
constexpr double TMaxRatio = (T == OptimumTime ? 1.0 : MaxRatio);
|
||||
constexpr double TStealRatio = (T == OptimumTime ? 0.0 : StealRatio);
|
||||
|
||||
double moveImportance = (move_importance(ply) * slowMover) / 100.0;
|
||||
double otherMovesImportance = 0.0;
|
||||
|
||||
for (int i = 1; i < movesToGo; ++i)
|
||||
otherMovesImportance += move_importance(ply + 2 * i);
|
||||
|
||||
double ratio1 = (TMaxRatio * moveImportance) / (TMaxRatio * moveImportance + otherMovesImportance);
|
||||
double ratio2 = (moveImportance + TStealRatio * otherMovesImportance) / (moveImportance + otherMovesImportance);
|
||||
|
||||
return TimePoint(myTime * std::min(ratio1, ratio2)); // Intel C++ asks for an explicit cast
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
/// init() is called at the beginning of the search and calculates the allowed
|
||||
/// thinking time out of the time control and current game ply. We support four
|
||||
/// different kinds of time controls, passed in 'limits':
|
||||
///
|
||||
/// inc == 0 && movestogo == 0 means: x basetime [sudden death!]
|
||||
/// inc == 0 && movestogo != 0 means: x moves in y minutes
|
||||
/// inc > 0 && movestogo == 0 means: x basetime + z increment
|
||||
/// inc > 0 && movestogo != 0 means: x moves in y minutes + z increment
|
||||
|
||||
void TimeManagement::init(Search::LimitsType &limits, Color us, int ply)
|
||||
{
|
||||
TimePoint minThinkingTime = (TimePoint)Options["Minimum Thinking Time"];
|
||||
TimePoint moveOverhead = (TimePoint)Options["Move Overhead"];
|
||||
TimePoint slowMover = (TimePoint)Options["Slow Mover"];
|
||||
TimePoint npmsec = (TimePoint)Options["nodestime"];
|
||||
TimePoint hypMyTime;
|
||||
|
||||
// If we have to play in 'nodes as time' mode, then convert from time
|
||||
// to nodes, and use resulting values in time management formulas.
|
||||
// WARNING: to avoid time losses, the given npmsec (nodes per millisecond)
|
||||
// must be much lower than the real engine speed.
|
||||
if (npmsec) {
|
||||
if (!availableNodes) // Only once at game start
|
||||
availableNodes = npmsec * limits.time[us]; // Time is in msec
|
||||
|
||||
// Convert from milliseconds to nodes
|
||||
limits.time[us] = TimePoint(availableNodes);
|
||||
limits.inc[us] *= npmsec;
|
||||
limits.npmsec = npmsec;
|
||||
}
|
||||
|
||||
startTime = limits.startTime;
|
||||
optimumTime = maximumTime = std::max(limits.time[us], minThinkingTime);
|
||||
|
||||
const int maxMTG = limits.movestogo ? std::min(limits.movestogo, MoveHorizon) : MoveHorizon;
|
||||
|
||||
// We calculate optimum time usage for different hypothetical "moves to go" values
|
||||
// and choose the minimum of calculated search time values. Usually the greatest
|
||||
// hypMTG gives the minimum values.
|
||||
for (int hypMTG = 1; hypMTG <= maxMTG; ++hypMTG) {
|
||||
// Calculate thinking time for hypothetical "moves to go"-value
|
||||
hypMyTime = limits.time[us]
|
||||
+ limits.inc[us] * (hypMTG - 1)
|
||||
- moveOverhead * (2 + std::min(hypMTG, 40));
|
||||
|
||||
hypMyTime = std::max(hypMyTime, TimePoint(0));
|
||||
|
||||
TimePoint t1 = minThinkingTime + remaining<OptimumTime>(hypMyTime, hypMTG, ply, slowMover);
|
||||
TimePoint t2 = minThinkingTime + remaining<MaxTime >(hypMyTime, hypMTG, ply, slowMover);
|
||||
|
||||
optimumTime = std::min(t1, optimumTime);
|
||||
maximumTime = std::min(t2, maximumTime);
|
||||
}
|
||||
|
||||
if (Options["Ponder"])
|
||||
optimumTime += optimumTime / 4;
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
/*
|
||||
Fishmill, a UCI Mill Game playing engine derived from Stockfish
|
||||
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
||||
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad (Stockfish author)
|
||||
Copyright (C) 2015-2020 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad (Stockfish author)
|
||||
Copyright (C) 2020 Calcitem <calcitem@outlook.com>
|
||||
|
||||
Fishmill is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Fishmill is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef TIMEMAN_H_INCLUDED
|
||||
#define TIMEMAN_H_INCLUDED
|
||||
|
||||
#include "misc.h"
|
||||
#include "search.h"
|
||||
#include "thread.h"
|
||||
|
||||
/// The TimeManagement class computes the optimal time to think depending on
|
||||
/// the maximum available time, the game move number and other parameters.
|
||||
|
||||
class TimeManagement {
|
||||
public:
|
||||
void init(Search::LimitsType& limits, Color us, int ply);
|
||||
TimePoint optimum() const { return optimumTime; }
|
||||
TimePoint maximum() const { return maximumTime; }
|
||||
TimePoint elapsed() const { return Search::Limits.npmsec ?
|
||||
TimePoint(Threads.nodes_searched()) : now() - startTime; }
|
||||
|
||||
int64_t availableNodes; // When in 'nodes as time' mode
|
||||
|
||||
private:
|
||||
TimePoint startTime;
|
||||
TimePoint optimumTime;
|
||||
TimePoint maximumTime;
|
||||
};
|
||||
|
||||
extern TimeManagement Time;
|
||||
|
||||
#endif // #ifndef TIMEMAN_H_INCLUDED
|
|
@ -67,7 +67,7 @@ Value TranspositionTable::probe(const Key &key,
|
|||
break;
|
||||
case BOUND_UPPER:
|
||||
if (tte.value8 <= alpha) {
|
||||
return alpha; // TODO: https://github.com/calcitem/NineChess/issues/25
|
||||
return alpha; // TODO: https://github.com/calcitem/Sanmill/issues/25
|
||||
}
|
||||
break;
|
||||
case BOUND_LOWER:
|
||||
|
|
62
src/uci.cpp
62
src/uci.cpp
|
@ -29,7 +29,6 @@
|
|||
#include "position.h"
|
||||
#include "search.h"
|
||||
#include "thread.h"
|
||||
#include "timeman.h"
|
||||
#include "tt.h"
|
||||
#include "uci.h"
|
||||
|
||||
|
@ -41,7 +40,7 @@ namespace
|
|||
{
|
||||
|
||||
// FEN string of the initial position, normal mill game
|
||||
const char *StartFEN = "********/********/******** b p p 0 12 0 12 0 0 1"; // Chess: "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
|
||||
const char *StartFEN = "********/********/******** b p p 0 12 0 12 0 0 1";
|
||||
|
||||
|
||||
// position() is called when engine receives the "position" UCI command.
|
||||
|
@ -49,7 +48,7 @@ const char *StartFEN = "********/********/******** b p p 0 12 0 12 0 0 1"; // Ch
|
|||
// or the starting position ("startpos") and then makes the moves given in the
|
||||
// following move list ("moves").
|
||||
|
||||
void position(Position *pos, istringstream &is, StateListPtr &states)
|
||||
void position(Position *pos, istringstream &is)
|
||||
{
|
||||
Move m;
|
||||
string token, fen;
|
||||
|
@ -65,13 +64,11 @@ void position(Position *pos, istringstream &is, StateListPtr &states)
|
|||
else
|
||||
return;
|
||||
|
||||
states = StateListPtr(new std::deque<StateInfo>(1)); // Drop old and create a new one
|
||||
pos->set(fen, &states->back(), Threads.main());
|
||||
pos->set(fen, Threads.main());
|
||||
|
||||
// Parse move list (if any)
|
||||
while (is >> token && (m = UCI::to_move(pos, token)) != MOVE_NONE) {
|
||||
states->emplace_back();
|
||||
pos->do_move(m, states->back());
|
||||
pos->do_move(m);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -104,34 +101,10 @@ void setoption(istringstream &is)
|
|||
// the thinking time and other parameters from the input string, then starts
|
||||
// the search.
|
||||
|
||||
void go(Position *pos, istringstream &is, StateListPtr &states)
|
||||
void go(Position *pos)
|
||||
{
|
||||
begin:
|
||||
Search::LimitsType limits;
|
||||
string token;
|
||||
bool ponderMode = false;
|
||||
|
||||
limits.startTime = now(); // As early as possible!
|
||||
|
||||
while (is >> token)
|
||||
if (token == "searchmoves") // Needs to be the last command on the line
|
||||
while (is >> token)
|
||||
limits.searchmoves.push_back(UCI::to_move(pos, token));
|
||||
|
||||
else if (token == "wtime") is >> limits.time[WHITE];
|
||||
else if (token == "btime") is >> limits.time[BLACK];
|
||||
else if (token == "winc") is >> limits.inc[WHITE];
|
||||
else if (token == "binc") is >> limits.inc[BLACK];
|
||||
else if (token == "movestogo") is >> limits.movestogo;
|
||||
else if (token == "depth") is >> limits.depth;
|
||||
else if (token == "nodes") is >> limits.nodes;
|
||||
else if (token == "movetime") is >> limits.movetime;
|
||||
else if (token == "mate") is >> limits.mate;
|
||||
else if (token == "perft") is >> limits.perft;
|
||||
else if (token == "infinite") limits.infinite = 1;
|
||||
else if (token == "ponder") ponderMode = true;
|
||||
|
||||
Threads.start_thinking(pos, states, limits, ponderMode);
|
||||
Threads.start_thinking(pos);
|
||||
|
||||
if (pos->get_phase() == PHASE_GAMEOVER)
|
||||
{
|
||||
|
@ -140,7 +113,7 @@ begin:
|
|||
{
|
||||
}
|
||||
|
||||
pos->set(StartFEN, &states->back(), Threads.main());
|
||||
pos->set(StartFEN, Threads.main());
|
||||
}
|
||||
|
||||
goto begin;
|
||||
|
@ -151,10 +124,10 @@ begin:
|
|||
// a list of UCI commands is setup according to bench parameters, then
|
||||
// it is run one by one printing a summary at the end.
|
||||
|
||||
void bench(Position *pos, istream &args, StateListPtr &states)
|
||||
void bench(Position *pos, istream &args)
|
||||
{
|
||||
string token;
|
||||
uint64_t num, nodes = 0, cnt = 1;
|
||||
uint64_t num, cnt = 1;
|
||||
|
||||
vector<string> list = setup_bench(pos, args);
|
||||
num = count_if(list.begin(), list.end(), [](string s) { return s.find("go ") == 0 || s.find("eval") == 0; });
|
||||
|
@ -168,13 +141,12 @@ void bench(Position *pos, istream &args, StateListPtr &states)
|
|||
if (token == "go" || token == "eval") {
|
||||
cerr << "\nPosition: " << cnt++ << '/' << num << endl;
|
||||
if (token == "go") {
|
||||
go(pos, is, states);
|
||||
go(pos);
|
||||
Threads.main()->wait_for_search_finished();
|
||||
nodes += Threads.nodes_searched();
|
||||
} else
|
||||
sync_cout << "\n" << Eval::trace(*pos) << sync_endl;
|
||||
} else if (token == "setoption") setoption(is);
|
||||
else if (token == "position") position(pos, is, states);
|
||||
else if (token == "position") position(pos, is);
|
||||
else if (token == "ucinewgame") {
|
||||
Search::clear(); elapsed = now();
|
||||
} // Search::clear() may take some while
|
||||
|
@ -186,8 +158,7 @@ void bench(Position *pos, istream &args, StateListPtr &states)
|
|||
|
||||
cerr << "\n==========================="
|
||||
<< "\nTotal time (ms) : " << elapsed
|
||||
<< "\nNodes searched : " << nodes
|
||||
<< "\nNodes/second : " << 1000 * nodes / elapsed << endl;
|
||||
<< endl;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
@ -204,9 +175,8 @@ void UCI::loop(int argc, char *argv[])
|
|||
|
||||
Position *pos = new Position;
|
||||
string token, cmd;
|
||||
StateListPtr states(new std::deque<StateInfo>(1));
|
||||
|
||||
pos->set(StartFEN, &states->back(), Threads.main());
|
||||
pos->set(StartFEN, Threads.main());
|
||||
|
||||
for (int i = 1; i < argc; ++i)
|
||||
cmd += std::string(argv[i]) + " ";
|
||||
|
@ -237,15 +207,15 @@ void UCI::loop(int argc, char *argv[])
|
|||
<< "\nuciok" << sync_endl;
|
||||
|
||||
else if (token == "setoption") setoption(is);
|
||||
else if (token == "go") go(pos, is, states);
|
||||
else if (token == "position") position(pos, is, states);
|
||||
else if (token == "go") go(pos);
|
||||
else if (token == "position") position(pos, is);
|
||||
else if (token == "ucinewgame") Search::clear();
|
||||
else if (token == "isready") sync_cout << "readyok" << sync_endl;
|
||||
|
||||
// Additional custom non-UCI commands, mainly for debugging.
|
||||
// Do not use these commands during a search!
|
||||
else if (token == "flip") pos->flip();
|
||||
else if (token == "bench") bench(pos, is, states);
|
||||
else if (token == "bench") bench(pos, is);
|
||||
else if (token == "d") sync_cout << &pos << sync_endl;
|
||||
else if (token == "eval") sync_cout << Eval::trace(*pos) << sync_endl;
|
||||
else if (token == "compiler") sync_cout << compiler_info() << sync_endl;
|
||||
|
|
|
@ -73,7 +73,6 @@ void loop(int argc, char* argv[]);
|
|||
std::string value(Value v);
|
||||
std::string square(Square s);
|
||||
std::string move(Move m);
|
||||
std::string pv(const Position* pos, Depth depth, Value alpha, Value beta);
|
||||
Move to_move(Position* pos, std::string& str);
|
||||
|
||||
} // namespace UCI
|
||||
|
|
|
@ -29,7 +29,6 @@
|
|||
#include "thread.h"
|
||||
#include "tt.h"
|
||||
#include "uci.h"
|
||||
//#include "syzygy/tbprobe.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
|
@ -57,12 +56,6 @@ void on_threads(const Option &o)
|
|||
{
|
||||
Threads.set((size_t)o);
|
||||
}
|
||||
#ifdef TBPROBE
|
||||
void on_tb_path(const Option &o)
|
||||
{
|
||||
Tablebases::init(o);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/// Our case insensitive less() function as required by UCI protocol
|
||||
|
@ -97,12 +90,6 @@ void init(OptionsMap &o)
|
|||
o["UCI_AnalyseMode"] << Option(false);
|
||||
o["UCI_LimitStrength"] << Option(false);
|
||||
o["UCI_Elo"] << Option(1350, 1350, 2850);
|
||||
#ifdef TBPROBE
|
||||
o["SyzygyPath"] << Option("<empty>", on_tb_path);
|
||||
o["SyzygyProbeDepth"] << Option(1, 1, 100);
|
||||
o["Syzygy50MoveRule"] << Option(true);
|
||||
o["SyzygyProbeLimit"] << Option(7, 0, 7);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1048,7 +1048,7 @@ bool GameController::command(const string &cmd, bool update /* = true */)
|
|||
loggerDebug("Game Duration Time: %lldms\n", gameDurationTime);
|
||||
|
||||
#ifdef TIME_STAT
|
||||
loggerDebug("Sort Time: %ld + %ld = %ldms\n",
|
||||
loggerDebug("Sort Time: %I64d + %I64d = %I64dms\n",
|
||||
aiThread[BLACK]->sortTime, aiThread[WHITE]->sortTime,
|
||||
(aiThread[BLACK]->sortTime + aiThread[WHITE]->sortTime));
|
||||
aiThread[BLACK]->sortTime = aiThread[WHITE]->sortTime = 0;
|
||||
|
|
Loading…
Reference in New Issue