mirror of
https://github.com/HChaZZY/Stockfish.git
synced 2025-12-06 10:53:50 +08:00
Compare commits
23 Commits
5337edfdb6
...
sf_1.6.3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
48cfdfcc46 | ||
|
|
fa7b244dc9 | ||
|
|
29ad6a73fc | ||
|
|
ac48b16708 | ||
|
|
38b1c4b6b8 | ||
|
|
162dbeaee8 | ||
|
|
85146ca0a9 | ||
|
|
02e12a69a7 | ||
|
|
6e8116e38f | ||
|
|
29f7fab2a9 | ||
|
|
2af986bf31 | ||
|
|
b67146b100 | ||
|
|
c1b1a94d81 | ||
|
|
17212e5fcc | ||
|
|
46921dff27 | ||
|
|
941016e7a2 | ||
|
|
290caf9960 | ||
|
|
43fa3a4d64 | ||
|
|
64b4836d12 | ||
|
|
5df7d62eb9 | ||
|
|
82179c70dc | ||
|
|
de17652e47 | ||
|
|
647b79b556 |
@@ -80,6 +80,7 @@ help:
|
||||
@echo "Makefile options:"
|
||||
@echo ""
|
||||
@echo "make > Default: Compiler = g++"
|
||||
@echo "make gcc-popcnt > Compiler = g++ + popcnt-support"
|
||||
@echo "make icc > Compiler = icpc"
|
||||
@echo "make icc-profile > Compiler = icpc + automatic pgo-build"
|
||||
@echo "make icc-profile-popcnt > Compiler = icpc + automatic pgo-build + popcnt-support"
|
||||
@@ -108,6 +109,13 @@ gcc:
|
||||
CXXFLAGS="$(GCCFLAGS)" \
|
||||
all
|
||||
|
||||
gcc-popcnt:
|
||||
$(MAKE) \
|
||||
CXX='g++' \
|
||||
CXXFLAGS="$(GCCFLAGS) -DUSE_POPCNT" \
|
||||
all
|
||||
|
||||
|
||||
icc:
|
||||
$(MAKE) \
|
||||
CXX='icpc' \
|
||||
|
||||
@@ -155,7 +155,7 @@ void benchmark(const string& commandLine) {
|
||||
cerr << "\nBench position: " << cnt << '/' << positions.size() << endl << endl;
|
||||
if (limitType == "perft")
|
||||
totalNodes += perft(pos, maxDepth * OnePly);
|
||||
else if (!think(pos, true, false, 0, dummy, dummy, 0, maxDepth, maxNodes, secsPerPos, moves))
|
||||
else if (!think(pos, false, false, 0, dummy, dummy, 0, maxDepth, maxNodes, secsPerPos, moves))
|
||||
break;
|
||||
totalNodes += nodes_searched();
|
||||
}
|
||||
|
||||
@@ -53,6 +53,30 @@ inline bool cpu_has_popcnt() {
|
||||
|
||||
#define POPCNT_INTRINSIC(x) __popcnt64(x)
|
||||
|
||||
#elif defined(__GNUC__) && defined(USE_POPCNT) // Gcc compiler
|
||||
|
||||
inline void __cpuid(unsigned int op,
|
||||
unsigned int *eax, unsigned int *ebx,
|
||||
unsigned int *ecx, unsigned int *edx)
|
||||
{
|
||||
*eax = op;
|
||||
*ecx = 0;
|
||||
__asm__("cpuid" : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx)
|
||||
: "0" (*eax), "2" (*ecx));
|
||||
}
|
||||
|
||||
inline bool cpu_has_popcnt() {
|
||||
|
||||
unsigned int eax, ebx, ecx, edx;
|
||||
__cpuid(1, &eax, &ebx, &ecx, &edx);
|
||||
return (ecx >> 23) & 1;
|
||||
}
|
||||
|
||||
#define POPCNT_INTRINSIC(x) ({ \
|
||||
unsigned long __ret; \
|
||||
__asm__("popcnt %1, %0" : "=r" (__ret) : "r" (x)); \
|
||||
__ret; })
|
||||
|
||||
#else // Safe fallback for unsupported compilers or when USE_POPCNT is disabled
|
||||
|
||||
inline bool cpu_has_popcnt() { return false; }
|
||||
|
||||
@@ -374,7 +374,6 @@ EndgameFunctions::EndgameFunctions() {
|
||||
add<ScalingFunction<KBPPKB> >("KBPPKB");
|
||||
add<ScalingFunction<KBPKN> >("KBPKN");
|
||||
add<ScalingFunction<KRPPKRP> >("KRPPKRP");
|
||||
add<ScalingFunction<KRPPKRP> >("KRPPKRP");
|
||||
}
|
||||
|
||||
EndgameFunctions::~EndgameFunctions() {
|
||||
|
||||
@@ -50,7 +50,7 @@ using namespace std;
|
||||
/// Version number. If this is left empty, the current date (in the format
|
||||
/// YYMMDD) is used as a version number.
|
||||
|
||||
static const string EngineVersion = "1.6.2";
|
||||
static const string EngineVersion = "1.6.3";
|
||||
static const string AppName = "Stockfish";
|
||||
static const string AppTag = "";
|
||||
|
||||
|
||||
169
src/position.cpp
169
src/position.cpp
@@ -143,72 +143,77 @@ void Position::from_fen(const string& fen) {
|
||||
}
|
||||
|
||||
i++;
|
||||
while(strchr("KQkqabcdefghABCDEFGH-", fen[i])) {
|
||||
if (fen[i] == '-')
|
||||
{
|
||||
while (strchr("KQkqabcdefghABCDEFGH-", fen[i])) {
|
||||
if (fen[i] == '-')
|
||||
{
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
else if (fen[i] == 'K') allow_oo(WHITE);
|
||||
else if (fen[i] == 'Q') allow_ooo(WHITE);
|
||||
else if (fen[i] == 'k') allow_oo(BLACK);
|
||||
else if (fen[i] == 'q') allow_ooo(BLACK);
|
||||
else if (fen[i] >= 'A' && fen[i] <= 'H') {
|
||||
File rookFile, kingFile = FILE_NONE;
|
||||
for (Square square = SQ_B1; square <= SQ_G1; square++)
|
||||
if (piece_on(square) == WK)
|
||||
kingFile = square_file(square);
|
||||
if (kingFile == FILE_NONE) {
|
||||
std::cout << "Error in FEN at character " << i << std::endl;
|
||||
return;
|
||||
}
|
||||
initialKFile = kingFile;
|
||||
rookFile = File(fen[i] - 'A') + FILE_A;
|
||||
if (rookFile < initialKFile) {
|
||||
allow_ooo(WHITE);
|
||||
initialQRFile = rookFile;
|
||||
}
|
||||
else {
|
||||
allow_oo(WHITE);
|
||||
initialKRFile = rookFile;
|
||||
}
|
||||
}
|
||||
else if (fen[i] >= 'a' && fen[i] <= 'h') {
|
||||
File rookFile, kingFile = FILE_NONE;
|
||||
for (Square square = SQ_B8; square <= SQ_G8; square++)
|
||||
if (piece_on(square) == BK)
|
||||
kingFile = square_file(square);
|
||||
if (kingFile == FILE_NONE) {
|
||||
std::cout << "Error in FEN at character " << i << std::endl;
|
||||
return;
|
||||
}
|
||||
initialKFile = kingFile;
|
||||
rookFile = File(fen[i] - 'a') + FILE_A;
|
||||
if (rookFile < initialKFile) {
|
||||
allow_ooo(BLACK);
|
||||
initialQRFile = rookFile;
|
||||
}
|
||||
else {
|
||||
allow_oo(BLACK);
|
||||
initialKRFile = rookFile;
|
||||
}
|
||||
}
|
||||
else {
|
||||
std::cout << "Error in FEN at character " << i << std::endl;
|
||||
return;
|
||||
}
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
else if(fen[i] == 'K') allow_oo(WHITE);
|
||||
else if(fen[i] == 'Q') allow_ooo(WHITE);
|
||||
else if(fen[i] == 'k') allow_oo(BLACK);
|
||||
else if(fen[i] == 'q') allow_ooo(BLACK);
|
||||
else if(fen[i] >= 'A' && fen[i] <= 'H') {
|
||||
File rookFile, kingFile = FILE_NONE;
|
||||
for(Square square = SQ_B1; square <= SQ_G1; square++)
|
||||
if(piece_on(square) == WK)
|
||||
kingFile = square_file(square);
|
||||
if(kingFile == FILE_NONE) {
|
||||
std::cout << "Error in FEN at character " << i << std::endl;
|
||||
return;
|
||||
}
|
||||
initialKFile = kingFile;
|
||||
rookFile = File(fen[i] - 'A') + FILE_A;
|
||||
if(rookFile < initialKFile) {
|
||||
allow_ooo(WHITE);
|
||||
initialQRFile = rookFile;
|
||||
}
|
||||
else {
|
||||
allow_oo(WHITE);
|
||||
initialKRFile = rookFile;
|
||||
}
|
||||
}
|
||||
else if(fen[i] >= 'a' && fen[i] <= 'h') {
|
||||
File rookFile, kingFile = FILE_NONE;
|
||||
for(Square square = SQ_B8; square <= SQ_G8; square++)
|
||||
if(piece_on(square) == BK)
|
||||
kingFile = square_file(square);
|
||||
if(kingFile == FILE_NONE) {
|
||||
std::cout << "Error in FEN at character " << i << std::endl;
|
||||
return;
|
||||
}
|
||||
initialKFile = kingFile;
|
||||
rookFile = File(fen[i] - 'a') + FILE_A;
|
||||
if(rookFile < initialKFile) {
|
||||
allow_ooo(BLACK);
|
||||
initialQRFile = rookFile;
|
||||
}
|
||||
else {
|
||||
allow_oo(BLACK);
|
||||
initialKRFile = rookFile;
|
||||
}
|
||||
}
|
||||
else {
|
||||
std::cout << "Error in FEN at character " << i << std::endl;
|
||||
return;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
// Skip blanks
|
||||
while (fen[i] == ' ')
|
||||
i++;
|
||||
|
||||
// En passant square
|
||||
// En passant square -- ignore if no capture is possible
|
||||
if ( i <= fen.length() - 2
|
||||
&& (fen[i] >= 'a' && fen[i] <= 'h')
|
||||
&& (fen[i+1] == '3' || fen[i+1] == '6'))
|
||||
st->epSquare = square_from_string(fen.substr(i, 2));
|
||||
{
|
||||
Square fenEpSquare = square_from_string(fen.substr(i, 2));
|
||||
Color them = opposite_color(sideToMove);
|
||||
if (attacks_from<PAWN>(fenEpSquare, them) & this->pieces(PAWN, sideToMove))
|
||||
st->epSquare = square_from_string(fen.substr(i, 2));
|
||||
}
|
||||
|
||||
// Various initialisation
|
||||
for (Square sq = SQ_A1; sq <= SQ_H8; sq++)
|
||||
@@ -266,10 +271,24 @@ const string Position::to_fen() const {
|
||||
fen += (sideToMove == WHITE ? "w " : "b ");
|
||||
if (st->castleRights != NO_CASTLES)
|
||||
{
|
||||
if (can_castle_kingside(WHITE)) fen += 'K';
|
||||
if (can_castle_queenside(WHITE)) fen += 'Q';
|
||||
if (can_castle_kingside(BLACK)) fen += 'k';
|
||||
if (can_castle_queenside(BLACK)) fen += 'q';
|
||||
if (initialKFile == FILE_E && initialQRFile == FILE_A && initialKRFile == FILE_H)
|
||||
{
|
||||
if (can_castle_kingside(WHITE)) fen += 'K';
|
||||
if (can_castle_queenside(WHITE)) fen += 'Q';
|
||||
if (can_castle_kingside(BLACK)) fen += 'k';
|
||||
if (can_castle_queenside(BLACK)) fen += 'q';
|
||||
}
|
||||
else
|
||||
{
|
||||
if (can_castle_kingside(WHITE))
|
||||
fen += char(toupper(file_to_char(initialKRFile)));
|
||||
if (can_castle_queenside(WHITE))
|
||||
fen += char(toupper(file_to_char(initialQRFile)));
|
||||
if (can_castle_kingside(BLACK))
|
||||
fen += file_to_char(initialKRFile);
|
||||
if (can_castle_queenside(BLACK))
|
||||
fen += file_to_char(initialQRFile);
|
||||
}
|
||||
} else
|
||||
fen += '-';
|
||||
|
||||
@@ -1553,7 +1572,7 @@ Key Position::compute_pawn_key() const {
|
||||
for (Color c = WHITE; c <= BLACK; c++)
|
||||
{
|
||||
b = pieces(PAWN, c);
|
||||
while(b)
|
||||
while (b)
|
||||
{
|
||||
s = pop_1st_bit(&b);
|
||||
result ^= zobrist[c][PAWN][s];
|
||||
@@ -1597,7 +1616,7 @@ Score Position::compute_value() const {
|
||||
for (PieceType pt = PAWN; pt <= KING; pt++)
|
||||
{
|
||||
b = pieces(pt, c);
|
||||
while(b)
|
||||
while (b)
|
||||
{
|
||||
s = pop_1st_bit(&b);
|
||||
assert(piece_on(s) == piece_of_color_and_type(c, pt));
|
||||
@@ -1843,6 +1862,7 @@ bool Position::is_ok(int* failedStep) const {
|
||||
static const bool debugNonPawnMaterial = false;
|
||||
static const bool debugPieceCounts = false;
|
||||
static const bool debugPieceList = false;
|
||||
static const bool debugCastleSquares = false;
|
||||
|
||||
if (failedStep) *failedStep = 1;
|
||||
|
||||
@@ -1968,9 +1988,9 @@ bool Position::is_ok(int* failedStep) const {
|
||||
if (failedStep) (*failedStep)++;
|
||||
if (debugPieceList)
|
||||
{
|
||||
for(Color c = WHITE; c <= BLACK; c++)
|
||||
for(PieceType pt = PAWN; pt <= KING; pt++)
|
||||
for(int i = 0; i < pieceCount[c][pt]; i++)
|
||||
for (Color c = WHITE; c <= BLACK; c++)
|
||||
for (PieceType pt = PAWN; pt <= KING; pt++)
|
||||
for (int i = 0; i < pieceCount[c][pt]; i++)
|
||||
{
|
||||
if (piece_on(piece_list(c, pt, i)) != piece_of_color_and_type(c, pt))
|
||||
return false;
|
||||
@@ -1979,6 +1999,25 @@ bool Position::is_ok(int* failedStep) const {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (failedStep) (*failedStep)++;
|
||||
if (debugCastleSquares) {
|
||||
for (Color c = WHITE; c <= BLACK; c++) {
|
||||
if (can_castle_kingside(c) && piece_on(initial_kr_square(c)) != piece_of_color_and_type(c, ROOK))
|
||||
return false;
|
||||
if (can_castle_queenside(c) && piece_on(initial_qr_square(c)) != piece_of_color_and_type(c, ROOK))
|
||||
return false;
|
||||
}
|
||||
if (castleRightsMask[initial_kr_square(WHITE)] != (ALL_CASTLES ^ WHITE_OO))
|
||||
return false;
|
||||
if (castleRightsMask[initial_qr_square(WHITE)] != (ALL_CASTLES ^ WHITE_OOO))
|
||||
return false;
|
||||
if (castleRightsMask[initial_kr_square(BLACK)] != (ALL_CASTLES ^ BLACK_OO))
|
||||
return false;
|
||||
if (castleRightsMask[initial_qr_square(BLACK)] != (ALL_CASTLES ^ BLACK_OOO))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (failedStep) *failedStep = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
216
src/search.cpp
216
src/search.cpp
@@ -227,14 +227,9 @@ namespace {
|
||||
int MaxNodes, MaxDepth;
|
||||
int MaxSearchTime, AbsoluteMaxSearchTime, ExtraSearchTime, ExactMaxTime;
|
||||
int RootMoveNumber;
|
||||
bool InfiniteSearch;
|
||||
bool PonderSearch;
|
||||
bool StopOnPonderhit;
|
||||
bool AbortSearch; // heavy SMP read access
|
||||
bool Quit;
|
||||
bool FailHigh;
|
||||
bool FailLow;
|
||||
bool Problem;
|
||||
bool UseTimeManagement, InfiniteSearch, PonderSearch, StopOnPonderhit;
|
||||
bool AbortSearch, Quit;
|
||||
bool FailHigh, FailLow, Problem;
|
||||
|
||||
// Show current line?
|
||||
bool ShowCurrentLine;
|
||||
@@ -368,8 +363,20 @@ bool think(const Position& pos, bool infinite, bool ponder, int side_to_move,
|
||||
int time[], int increment[], int movesToGo, int maxDepth,
|
||||
int maxNodes, int maxTime, Move searchMoves[]) {
|
||||
|
||||
// Look for a book move
|
||||
if (!infinite && !ponder && get_option_value_bool("OwnBook"))
|
||||
// Initialize global search variables
|
||||
Idle = StopOnPonderhit = AbortSearch = Quit = false;
|
||||
FailHigh = FailLow = Problem = false;
|
||||
NodesSincePoll = 0;
|
||||
SearchStartTime = get_system_time();
|
||||
ExactMaxTime = maxTime;
|
||||
MaxDepth = maxDepth;
|
||||
MaxNodes = maxNodes;
|
||||
InfiniteSearch = infinite;
|
||||
PonderSearch = ponder;
|
||||
UseTimeManagement = !ExactMaxTime && !MaxDepth && !MaxNodes && !InfiniteSearch;
|
||||
|
||||
// Look for a book move, only during games, not tests
|
||||
if (UseTimeManagement && !ponder && get_option_value_bool("OwnBook"))
|
||||
{
|
||||
Move bookMove;
|
||||
if (get_option_value_string("Book File") != OpeningBook.file_name())
|
||||
@@ -384,8 +391,6 @@ bool think(const Position& pos, bool infinite, bool ponder, int side_to_move,
|
||||
}
|
||||
|
||||
// Initialize global search variables
|
||||
Idle = false;
|
||||
SearchStartTime = get_system_time();
|
||||
for (int i = 0; i < THREAD_MAX; i++)
|
||||
{
|
||||
Threads[i].nodes = 0ULL;
|
||||
@@ -452,6 +457,10 @@ bool think(const Position& pos, bool infinite, bool ponder, int side_to_move,
|
||||
{
|
||||
ActiveThreads = newActiveThreads;
|
||||
init_eval(ActiveThreads);
|
||||
// HACK: init_eval() destroys the static castleRightsMask[] array in the
|
||||
// Position class. The below line repairs the damage.
|
||||
Position p(pos.to_fen());
|
||||
assert(pos.is_ok());
|
||||
}
|
||||
|
||||
// Wake up sleeping threads
|
||||
@@ -463,48 +472,45 @@ bool think(const Position& pos, bool infinite, bool ponder, int side_to_move,
|
||||
// Set thinking time
|
||||
int myTime = time[side_to_move];
|
||||
int myIncrement = increment[side_to_move];
|
||||
|
||||
if (!movesToGo) // Sudden death time control
|
||||
if (UseTimeManagement)
|
||||
{
|
||||
if (myIncrement)
|
||||
if (!movesToGo) // Sudden death time control
|
||||
{
|
||||
MaxSearchTime = myTime / 30 + myIncrement;
|
||||
AbsoluteMaxSearchTime = Max(myTime / 4, myIncrement - 100);
|
||||
} else { // Blitz game without increment
|
||||
MaxSearchTime = myTime / 30;
|
||||
AbsoluteMaxSearchTime = myTime / 8;
|
||||
if (myIncrement)
|
||||
{
|
||||
MaxSearchTime = myTime / 30 + myIncrement;
|
||||
AbsoluteMaxSearchTime = Max(myTime / 4, myIncrement - 100);
|
||||
}
|
||||
else // Blitz game without increment
|
||||
{
|
||||
MaxSearchTime = myTime / 30;
|
||||
AbsoluteMaxSearchTime = myTime / 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
else // (x moves) / (y minutes)
|
||||
{
|
||||
if (movesToGo == 1)
|
||||
else // (x moves) / (y minutes)
|
||||
{
|
||||
MaxSearchTime = myTime / 2;
|
||||
AbsoluteMaxSearchTime =
|
||||
(myTime > 3000)? (myTime - 500) : ((myTime * 3) / 4);
|
||||
} else {
|
||||
MaxSearchTime = myTime / Min(movesToGo, 20);
|
||||
AbsoluteMaxSearchTime = Min((4 * myTime) / movesToGo, myTime / 3);
|
||||
if (movesToGo == 1)
|
||||
{
|
||||
MaxSearchTime = myTime / 2;
|
||||
AbsoluteMaxSearchTime = (myTime > 3000)? (myTime - 500) : ((myTime * 3) / 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
MaxSearchTime = myTime / Min(movesToGo, 20);
|
||||
AbsoluteMaxSearchTime = Min((4 * myTime) / movesToGo, myTime / 3);
|
||||
}
|
||||
}
|
||||
|
||||
if (PonderingEnabled)
|
||||
{
|
||||
MaxSearchTime += MaxSearchTime / 4;
|
||||
MaxSearchTime = Min(MaxSearchTime, AbsoluteMaxSearchTime);
|
||||
}
|
||||
}
|
||||
|
||||
if (PonderingEnabled)
|
||||
{
|
||||
MaxSearchTime += MaxSearchTime / 4;
|
||||
MaxSearchTime = Min(MaxSearchTime, AbsoluteMaxSearchTime);
|
||||
}
|
||||
|
||||
// Fixed depth or fixed number of nodes?
|
||||
MaxDepth = maxDepth;
|
||||
if (MaxDepth)
|
||||
InfiniteSearch = true; // HACK
|
||||
|
||||
MaxNodes = maxNodes;
|
||||
// Set best NodesBetweenPolls interval
|
||||
if (MaxNodes)
|
||||
{
|
||||
NodesBetweenPolls = Min(MaxNodes, 30000);
|
||||
InfiniteSearch = true; // HACK
|
||||
}
|
||||
else if (myTime && myTime < 1000)
|
||||
NodesBetweenPolls = 1000;
|
||||
else if (myTime && myTime < 5000)
|
||||
@@ -569,6 +575,7 @@ bool think(const Position& pos, bool infinite, bool ponder, int side_to_move,
|
||||
void init_threads() {
|
||||
|
||||
volatile int i;
|
||||
bool ok;
|
||||
|
||||
#if !defined(_MSC_VER)
|
||||
pthread_t pthread[1];
|
||||
@@ -604,12 +611,18 @@ void init_threads() {
|
||||
for(i = 1; i < THREAD_MAX; i++)
|
||||
{
|
||||
#if !defined(_MSC_VER)
|
||||
pthread_create(pthread, NULL, init_thread, (void*)(&i));
|
||||
ok = (pthread_create(pthread, NULL, init_thread, (void*)(&i)) == 0);
|
||||
#else
|
||||
DWORD iID[1];
|
||||
CreateThread(NULL, 0, init_thread, (LPVOID)(&i), 0, iID);
|
||||
ok = (CreateThread(NULL, 0, init_thread, (LPVOID)(&i), 0, iID) != NULL);
|
||||
#endif
|
||||
|
||||
if (!ok)
|
||||
{
|
||||
std::cout << "Failed to create thread number " << i << std::endl;
|
||||
Application::exit_with_failure();
|
||||
}
|
||||
|
||||
// Wait until the thread has finished launching
|
||||
while (!Threads[i].running);
|
||||
}
|
||||
@@ -782,7 +795,7 @@ namespace {
|
||||
|
||||
Problem = false;
|
||||
|
||||
if (!InfiniteSearch)
|
||||
if (UseTimeManagement)
|
||||
{
|
||||
// Time to stop?
|
||||
bool stopSearch = false;
|
||||
@@ -835,9 +848,9 @@ namespace {
|
||||
|
||||
rml.sort();
|
||||
|
||||
// If we are pondering, we shouldn't print the best move before we
|
||||
// are told to do so
|
||||
if (PonderSearch)
|
||||
// If we are pondering or in infinite search, we shouldn't print the
|
||||
// best move before we are told to do so.
|
||||
if (!AbortSearch && (PonderSearch || InfiniteSearch))
|
||||
wait_for_stop_or_ponderhit();
|
||||
else
|
||||
// Print final search statistics
|
||||
@@ -2006,7 +2019,14 @@ namespace {
|
||||
if (sp->ply == 1 && RootMoveNumber == 1)
|
||||
Threads[threadID].failHighPly1 = true;
|
||||
|
||||
value = -search_pv(pos, ss, -sp->beta, -sp->alpha, newDepth, sp->ply+1, threadID);
|
||||
// If another thread has failed high then sp->alpha has been increased
|
||||
// to be higher or equal then beta, if so, avoid to start a PV search.
|
||||
Value localAlpha = sp->alpha;
|
||||
if (localAlpha < sp->beta)
|
||||
value = -search_pv(pos, ss, -sp->beta, -localAlpha, newDepth, sp->ply+1, threadID);
|
||||
else
|
||||
assert(thread_should_stop(threadID));
|
||||
|
||||
Threads[threadID].failHighPly1 = false;
|
||||
}
|
||||
}
|
||||
@@ -2024,11 +2044,7 @@ namespace {
|
||||
sp->bestValue = value;
|
||||
if (value > sp->alpha)
|
||||
{
|
||||
sp->alpha = value;
|
||||
sp_update_pv(sp->parentSstack, ss, sp->ply);
|
||||
if (value == value_mate_in(sp->ply + 1))
|
||||
ss[sp->ply].mateKiller = move;
|
||||
|
||||
// Ask threads to stop before to modify sp->alpha
|
||||
if (value >= sp->beta)
|
||||
{
|
||||
for (int i = 0; i < ActiveThreads; i++)
|
||||
@@ -2037,6 +2053,12 @@ namespace {
|
||||
|
||||
sp->finished = true;
|
||||
}
|
||||
|
||||
sp->alpha = value;
|
||||
|
||||
sp_update_pv(sp->parentSstack, ss, sp->ply);
|
||||
if (value == value_mate_in(sp->ply + 1))
|
||||
ss[sp->ply].mateKiller = move;
|
||||
}
|
||||
// If we are at ply 1, and we are searching the first root move at
|
||||
// ply 0, set the 'Problem' variable if the score has dropped a lot
|
||||
@@ -2642,16 +2664,26 @@ namespace {
|
||||
if (ShowCurrentLine)
|
||||
Threads[0].printCurrentLine = true;
|
||||
}
|
||||
|
||||
// Should we stop the search?
|
||||
if (PonderSearch)
|
||||
return;
|
||||
|
||||
bool overTime = t > AbsoluteMaxSearchTime
|
||||
|| (RootMoveNumber == 1 && t > MaxSearchTime + ExtraSearchTime && !FailLow) //FIXME: We are not checking any problem flags, BUG?
|
||||
|| ( !FailHigh && !FailLow && !fail_high_ply_1() && !Problem
|
||||
&& t > 6*(MaxSearchTime + ExtraSearchTime));
|
||||
bool stillAtFirstMove = RootMoveNumber == 1
|
||||
&& !FailLow
|
||||
&& t > MaxSearchTime + ExtraSearchTime;
|
||||
|
||||
if ( (Iteration >= 3 && (!InfiniteSearch && overTime))
|
||||
bool noProblemFound = !FailHigh
|
||||
&& !FailLow
|
||||
&& !fail_high_ply_1()
|
||||
&& !Problem
|
||||
&& t > 6 * (MaxSearchTime + ExtraSearchTime);
|
||||
|
||||
bool noMoreTime = t > AbsoluteMaxSearchTime
|
||||
|| stillAtFirstMove //FIXME: We are not checking any problem flags, BUG?
|
||||
|| noProblemFound;
|
||||
|
||||
if ( (Iteration >= 3 && UseTimeManagement && noMoreTime)
|
||||
|| (ExactMaxTime && t >= ExactMaxTime)
|
||||
|| (Iteration >= 3 && MaxNodes && nodes_searched() >= MaxNodes))
|
||||
AbortSearch = true;
|
||||
@@ -2666,14 +2698,23 @@ namespace {
|
||||
|
||||
int t = current_search_time();
|
||||
PonderSearch = false;
|
||||
if (Iteration >= 3 &&
|
||||
(!InfiniteSearch && (StopOnPonderhit ||
|
||||
t > AbsoluteMaxSearchTime ||
|
||||
(RootMoveNumber == 1 &&
|
||||
t > MaxSearchTime + ExtraSearchTime && !FailLow) ||
|
||||
(!FailHigh && !FailLow && !fail_high_ply_1() && !Problem &&
|
||||
t > 6*(MaxSearchTime + ExtraSearchTime)))))
|
||||
AbortSearch = true;
|
||||
|
||||
bool stillAtFirstMove = RootMoveNumber == 1
|
||||
&& !FailLow
|
||||
&& t > MaxSearchTime + ExtraSearchTime;
|
||||
|
||||
bool noProblemFound = !FailHigh
|
||||
&& !FailLow
|
||||
&& !fail_high_ply_1()
|
||||
&& !Problem
|
||||
&& t > 6 * (MaxSearchTime + ExtraSearchTime);
|
||||
|
||||
bool noMoreTime = t > AbsoluteMaxSearchTime
|
||||
|| stillAtFirstMove
|
||||
|| noProblemFound;
|
||||
|
||||
if (Iteration >= 3 && UseTimeManagement && (noMoreTime || StopOnPonderhit))
|
||||
AbortSearch = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -2767,13 +2808,15 @@ namespace {
|
||||
}
|
||||
|
||||
// If this thread has been assigned work, launch a search
|
||||
if(Threads[threadID].workIsWaiting) {
|
||||
Threads[threadID].workIsWaiting = false;
|
||||
if(Threads[threadID].splitPoint->pvNode)
|
||||
sp_search_pv(Threads[threadID].splitPoint, threadID);
|
||||
else
|
||||
sp_search(Threads[threadID].splitPoint, threadID);
|
||||
Threads[threadID].idle = true;
|
||||
if (Threads[threadID].workIsWaiting)
|
||||
{
|
||||
Threads[threadID].workIsWaiting = false;
|
||||
if (Threads[threadID].splitPoint->pvNode)
|
||||
sp_search_pv(Threads[threadID].splitPoint, threadID);
|
||||
else
|
||||
sp_search(Threads[threadID].splitPoint, threadID);
|
||||
|
||||
Threads[threadID].idle = true;
|
||||
}
|
||||
|
||||
// If this thread is the master of a split point and all threads have
|
||||
@@ -2847,17 +2890,22 @@ namespace {
|
||||
if(!Threads[slave].idle || slave == master)
|
||||
return false;
|
||||
|
||||
if(Threads[slave].activeSplitPoints == 0)
|
||||
// No active split points means that the thread is available as a slave
|
||||
// for any other thread.
|
||||
return true;
|
||||
// Make a local copy to be sure doesn't change under our feet
|
||||
int localActiveSplitPoints = Threads[slave].activeSplitPoints;
|
||||
|
||||
if (localActiveSplitPoints == 0)
|
||||
// No active split points means that the thread is available as
|
||||
// a slave for any other thread.
|
||||
return true;
|
||||
|
||||
if(ActiveThreads == 2)
|
||||
return true;
|
||||
|
||||
// Apply the "helpful master" concept if possible.
|
||||
if(SplitPointStack[slave][Threads[slave].activeSplitPoints-1].slaves[master])
|
||||
return true;
|
||||
// Apply the "helpful master" concept if possible. Use localActiveSplitPoints
|
||||
// that is known to be > 0, instead of Threads[slave].activeSplitPoints that
|
||||
// could have been set to 0 by another thread leading to an out of bound access.
|
||||
if (SplitPointStack[slave][localActiveSplitPoints - 1].slaves[master])
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ struct SplitPoint {
|
||||
|
||||
struct Thread {
|
||||
SplitPoint *splitPoint;
|
||||
int activeSplitPoints;
|
||||
volatile int activeSplitPoints;
|
||||
uint64_t nodes;
|
||||
uint64_t betaCutOffs[2];
|
||||
bool failHighPly1;
|
||||
|
||||
@@ -53,11 +53,11 @@ TranspositionTable::~TranspositionTable() {
|
||||
/// TranspositionTable::set_size sets the size of the transposition table,
|
||||
/// measured in megabytes.
|
||||
|
||||
void TranspositionTable::set_size(unsigned mbSize) {
|
||||
void TranspositionTable::set_size(size_t mbSize) {
|
||||
|
||||
assert(mbSize >= 4 && mbSize <= 2048);
|
||||
assert(mbSize >= 4 && mbSize <= 8192);
|
||||
|
||||
unsigned newSize = 1024;
|
||||
size_t newSize = 1024;
|
||||
|
||||
// We store a cluster of ClusterSize number of TTEntry for each position
|
||||
// and newSize is the maximum number of storable positions.
|
||||
|
||||
4
src/tt.h
4
src/tt.h
@@ -95,7 +95,7 @@ class TranspositionTable {
|
||||
public:
|
||||
TranspositionTable();
|
||||
~TranspositionTable();
|
||||
void set_size(unsigned mbSize);
|
||||
void set_size(size_t mbSize);
|
||||
void clear();
|
||||
void store(const Key posKey, Value v, ValueType type, Depth d, Move m);
|
||||
TTEntry* retrieve(const Key posKey) const;
|
||||
@@ -114,7 +114,7 @@ private:
|
||||
unsigned writes; // heavy SMP read/write access here
|
||||
unsigned char pad_after[64];
|
||||
|
||||
unsigned size;
|
||||
size_t size;
|
||||
TTCluster* entries;
|
||||
uint8_t generation;
|
||||
};
|
||||
|
||||
68
src/uci.cpp
68
src/uci.cpp
@@ -107,7 +107,8 @@ namespace {
|
||||
UCIInputParser uip(command);
|
||||
string token;
|
||||
|
||||
uip >> token; // operator>>() skips any whitespace
|
||||
if (!(uip >> token)) // operator>>() skips any whitespace
|
||||
return true;
|
||||
|
||||
if (token == "quit")
|
||||
return false;
|
||||
@@ -159,14 +160,8 @@ namespace {
|
||||
else if (token == "perft")
|
||||
perft(uip);
|
||||
else
|
||||
{
|
||||
cout << "Unknown command: " << command << endl;
|
||||
while (!uip.eof())
|
||||
{
|
||||
uip >> token;
|
||||
cout << token << endl;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -181,33 +176,33 @@ namespace {
|
||||
|
||||
string token;
|
||||
|
||||
uip >> token; // operator>>() skips any whitespace
|
||||
if (!(uip >> token)) // operator>>() skips any whitespace
|
||||
return;
|
||||
|
||||
if (token == "startpos")
|
||||
RootPosition.from_fen(StartPosition);
|
||||
else if (token == "fen")
|
||||
{
|
||||
string fen;
|
||||
while (token != "moves" && !uip.eof())
|
||||
while (uip >> token && token != "moves")
|
||||
{
|
||||
uip >> token;
|
||||
fen += token;
|
||||
fen += ' ';
|
||||
}
|
||||
RootPosition.from_fen(fen);
|
||||
}
|
||||
|
||||
if (!uip.eof())
|
||||
if (uip.good())
|
||||
{
|
||||
if (token != "moves")
|
||||
uip >> token;
|
||||
|
||||
if (token == "moves")
|
||||
{
|
||||
Move move;
|
||||
StateInfo st;
|
||||
while (!uip.eof())
|
||||
while (uip >> token)
|
||||
{
|
||||
uip >> token;
|
||||
move = move_from_string(RootPosition, token);
|
||||
RootPosition.do_move(move, st);
|
||||
if (RootPosition.rule_50_counter() == 0)
|
||||
@@ -229,27 +224,22 @@ namespace {
|
||||
|
||||
void set_option(UCIInputParser& uip) {
|
||||
|
||||
string token, name;
|
||||
string token, name, value;
|
||||
|
||||
uip >> token;
|
||||
if (token == "name")
|
||||
if (!(uip >> token)) // operator>>() skips any whitespace
|
||||
return;
|
||||
|
||||
if (token == "name" && uip >> name)
|
||||
{
|
||||
uip >> name;
|
||||
while (!uip.eof())
|
||||
{
|
||||
uip >> token;
|
||||
if (token == "value")
|
||||
break;
|
||||
|
||||
while (uip >> token && token != "value")
|
||||
name += (" " + token);
|
||||
}
|
||||
if (token == "value")
|
||||
{
|
||||
// Reads until end of line and left trim white space
|
||||
getline(uip, token);
|
||||
token.erase(0, token.find_first_not_of(" \n\r\t"));
|
||||
|
||||
set_option_value(name, token);
|
||||
if (token == "value" && uip >> value)
|
||||
{
|
||||
while (uip >> token)
|
||||
value += (" " + token);
|
||||
|
||||
set_option_value(name, value);
|
||||
} else
|
||||
push_button(name);
|
||||
}
|
||||
@@ -276,10 +266,8 @@ namespace {
|
||||
|
||||
searchMoves[0] = MOVE_NONE;
|
||||
|
||||
while (!uip.eof())
|
||||
while (uip >> token)
|
||||
{
|
||||
uip >> token;
|
||||
|
||||
if (token == "infinite")
|
||||
infinite = true;
|
||||
else if (token == "ponder")
|
||||
@@ -303,18 +291,13 @@ namespace {
|
||||
else if (token == "searchmoves")
|
||||
{
|
||||
int numOfMoves = 0;
|
||||
while (!uip.eof())
|
||||
{
|
||||
uip >> token;
|
||||
while (uip >> token)
|
||||
searchMoves[numOfMoves++] = move_from_string(RootPosition, token);
|
||||
}
|
||||
|
||||
searchMoves[numOfMoves] = MOVE_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
if (moveTime)
|
||||
infinite = true; // HACK
|
||||
|
||||
assert(RootPosition.is_ok());
|
||||
|
||||
return think(RootPosition, infinite, ponder, RootPosition.side_to_move(),
|
||||
@@ -327,10 +310,9 @@ namespace {
|
||||
int depth, tm, n;
|
||||
Position pos = RootPosition;
|
||||
|
||||
if (uip.eof())
|
||||
if (!(uip >> depth))
|
||||
return;
|
||||
|
||||
uip >> depth;
|
||||
tm = get_system_time();
|
||||
|
||||
n = perft(pos, depth * OnePly);
|
||||
|
||||
@@ -123,7 +123,7 @@ namespace {
|
||||
o["Minimum Split Depth"] = Option(4, 4, 7);
|
||||
o["Maximum Number of Threads per Split Point"] = Option(5, 4, 8);
|
||||
o["Threads"] = Option(1, 1, THREAD_MAX);
|
||||
o["Hash"] = Option(32, 4, 2048);
|
||||
o["Hash"] = Option(32, 4, 8192);
|
||||
o["Clear Hash"] = Option(false, BUTTON);
|
||||
o["New Game"] = Option(false, BUTTON);
|
||||
o["Ponder"] = Option(true);
|
||||
@@ -196,15 +196,18 @@ void init_uci_options() {
|
||||
|
||||
load_defaults(options);
|
||||
|
||||
// Limit the default value of "Threads" to 7 even if we have 8 CPU cores.
|
||||
// According to Ken Dail's tests, Glaurung plays much better with 7 than
|
||||
// with 8 threads. This is weird, but it is probably difficult to find out
|
||||
// why before I have a 8-core computer to experiment with myself.
|
||||
// Set optimal value for parameter "Minimum Split Depth"
|
||||
// according to number of available cores.
|
||||
assert(options.find("Threads") != options.end());
|
||||
assert(options.find("Minimum Split Depth") != options.end());
|
||||
|
||||
options["Threads"].defaultValue = stringify(Min(cpu_count(), 7));
|
||||
options["Threads"].currentValue = stringify(Min(cpu_count(), 7));
|
||||
Option& thr = options["Threads"];
|
||||
Option& msd = options["Minimum Split Depth"];
|
||||
|
||||
thr.defaultValue = thr.currentValue = stringify(cpu_count());
|
||||
|
||||
if (cpu_count() >= 8)
|
||||
msd.defaultValue = msd.currentValue = stringify(7);
|
||||
}
|
||||
|
||||
|
||||
@@ -292,10 +295,28 @@ void set_option_value(const string& name, const string& value) {
|
||||
else if (v == "false")
|
||||
v = "0";
|
||||
|
||||
if (options.find(name) != options.end())
|
||||
options[name].currentValue = v;
|
||||
else
|
||||
if (options.find(name) == options.end())
|
||||
{
|
||||
std::cout << "No such option: " << name << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
// Normally it's up to the GUI to check for option's limits,
|
||||
// but we could receive the new value directly from the user
|
||||
// by teminal window. So let's check the bounds anyway.
|
||||
Option& opt = options[name];
|
||||
|
||||
if (opt.type == CHECK && v != "0" && v != "1")
|
||||
return;
|
||||
|
||||
else if (opt.type == SPIN)
|
||||
{
|
||||
int val = atoi(v.c_str());
|
||||
if (val < opt.minValue || val > opt.maxValue)
|
||||
return;
|
||||
}
|
||||
|
||||
opt.currentValue = v;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -48,7 +48,8 @@ enum Value {
|
||||
VALUE_KNOWN_WIN = 15000,
|
||||
VALUE_MATE = 30000,
|
||||
VALUE_INFINITE = 30001,
|
||||
VALUE_NONE = 30002
|
||||
VALUE_NONE = 30002,
|
||||
VALUE_ENSURE_SIGNED = -1
|
||||
};
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user