-
Notifications
You must be signed in to change notification settings - Fork 2.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
My study have shown that it does no harm to use an opening book instead of a search, while the latter being largely deterministic. This is a primitive version, using a PolyGlot-like book format but with our own Zobrist hash keys, so the probing might be cheap enough to be used elsewhere in search. The burden is on the creation of the book to provide more diversity to the openings and cover some corner cases, which is another area of research. No functional changes without a book.
- Loading branch information
1 parent
0f2df4e
commit 2b34be8
Showing
8 changed files
with
305 additions
and
34 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,188 @@ | ||
/* | ||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 | ||
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) | ||
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad | ||
Copyright (C) 2015-2019 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad | ||
Stockfish 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. | ||
Stockfish 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 "misc.h" | ||
#include "book.h" | ||
#include "movegen.h" | ||
#include <algorithm> | ||
#include <iostream> | ||
|
||
Book Books; | ||
|
||
Book::Book() | ||
{ | ||
max_book_ply = 400; | ||
NumBookEntries = 0; | ||
BookEntries = nullptr; | ||
} | ||
|
||
Book::~Book() | ||
{ | ||
if (BookEntries != nullptr) | ||
delete[] BookEntries; | ||
} | ||
|
||
void Book::init(const std::string& filename) | ||
{ | ||
if (filename.length() == 0) return; | ||
const char *fnam = filename.c_str(); | ||
|
||
if (strcmp(fnam, "<empty>") == 0) | ||
{ | ||
return; | ||
} | ||
|
||
FILE *fpt = fopen(fnam, "rb"); | ||
if (fpt == NULL) | ||
{ | ||
sync_cout << "info string Could not open " << filename << sync_endl; | ||
return; | ||
} | ||
|
||
if (BookEntries != nullptr) | ||
{ | ||
free(BookEntries); | ||
BookEntries = nullptr; | ||
} | ||
|
||
fseek(fpt, 0L, SEEK_END); | ||
int filesize = ftell(fpt); | ||
fseek(fpt, 0L, SEEK_SET); | ||
|
||
NumBookEntries = filesize / sizeof(BookEntry); | ||
BookEntries = new BookEntry[NumBookEntries]; | ||
|
||
size_t nRead = fread(BookEntries, 1, filesize, fpt); | ||
fclose(fpt); | ||
|
||
if (nRead != 1) | ||
{ | ||
free(BookEntries); | ||
BookEntries = nullptr; | ||
sync_cout << "info string Could not read " << filename << sync_endl; | ||
return; | ||
} | ||
for (size_t i = 0; i < NumBookEntries; i++) | ||
byteswap_bookentry(&BookEntries[i]); | ||
|
||
sync_cout << "info string Book loaded: " << filename << " (" << NumBookEntries << " entries)" << sync_endl; | ||
} | ||
|
||
void Book::set_max_ply(int new_max_ply) | ||
{ | ||
max_book_ply = new_max_ply; | ||
} | ||
|
||
Move Book::probe_root(Position& pos) | ||
{ | ||
if (BookEntries != nullptr && pos.game_ply() < max_book_ply) | ||
{ | ||
int count = 0; | ||
size_t index = find_first_entry(pos.key(), count); | ||
if (count > 0) | ||
{ | ||
PRNG rng(now()); | ||
Move move = reconstruct_move(BookEntries[index + rng.rand<unsigned>() % count].move); | ||
|
||
// Add 'special move' flags and verify it is legal | ||
for (const auto& m : MoveList<LEGAL>(pos)) | ||
{ | ||
if (move == (m.move & (~(3 << 14)))) // compare with MoveType (bit 14-15) masked out | ||
return m; | ||
} | ||
} | ||
} | ||
return MOVE_NONE; | ||
} | ||
|
||
void Book::probe(Position& pos, std::vector<Move>& bookmoves) | ||
{ | ||
if (BookEntries != nullptr && pos.game_ply() < max_book_ply) | ||
{ | ||
int count = 0; | ||
size_t index = find_first_entry(pos.key(), count); | ||
if (count > 0) | ||
{ | ||
for (int i = 0; i < count; i++) | ||
bookmoves.push_back(Move(BookEntries[index + i].move)); | ||
} | ||
} | ||
} | ||
|
||
Move Book::reconstruct_move(uint16_t book_move) | ||
{ | ||
Move move = Move(book_move); | ||
|
||
int pt = (move >> 12) & 7; | ||
if (pt) | ||
return make<PROMOTION>(from_sq(move), to_sq(move), PieceType(pt + 1)); | ||
|
||
return move; | ||
} | ||
|
||
size_t Book::find_first_entry(uint64_t key, int& index_count) | ||
{ | ||
size_t start = 0; | ||
size_t end = NumBookEntries; | ||
|
||
for (;;) | ||
{ | ||
size_t mid = (end + start) / 2; | ||
|
||
if (BookEntries[mid].key < key) | ||
start = mid; | ||
else | ||
{ | ||
if (BookEntries[mid].key > key) | ||
end = mid; | ||
else | ||
{ | ||
start = std::max(mid - 4, (size_t)0); | ||
end = std::min(mid + 4, NumBookEntries); | ||
} | ||
} | ||
|
||
if (end - start < 9) | ||
break; | ||
} | ||
|
||
for (size_t i = start; i < end; i++) | ||
{ | ||
if (key == BookEntries[i].key) | ||
{ | ||
while ((i > 0) && (key == BookEntries[i - 1].key)) | ||
i--; | ||
index_count = 1; | ||
end = i; | ||
while ((++end < NumBookEntries) && (key == BookEntries[end].key)) | ||
index_count++; | ||
return i; | ||
} | ||
} | ||
return 0; | ||
} | ||
|
||
void Book::byteswap_bookentry(BookEntry *be) | ||
{ | ||
be->key = number<uint64_t, BigEndian>(&be->key); | ||
be->move = number<uint16_t, BigEndian>(&be->move); | ||
be->weight = number<uint16_t, BigEndian>(&be->weight); | ||
be->score = number<uint32_t, BigEndian>(&be->score); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
/* | ||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 | ||
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) | ||
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad | ||
Copyright (C) 2015-2019 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad | ||
Stockfish 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. | ||
Stockfish 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 BOOK_H_INCLUDED | ||
#define BOOK_H_INCLUDED | ||
|
||
#include "position.h" | ||
#include <vector> | ||
|
||
class Book | ||
{ | ||
typedef struct { | ||
uint64_t key; | ||
uint16_t move; | ||
uint16_t weight; | ||
uint32_t score; | ||
} BookEntry; | ||
public: | ||
Book(); | ||
~Book(); | ||
void init(const std::string& filename); | ||
void set_max_ply(int new_max_ply); | ||
Move probe_root(Position& pos); | ||
void probe(Position& pos, std::vector<Move>& bookmoves); | ||
private: | ||
size_t find_first_entry(uint64_t key, int& index_count); | ||
Move reconstruct_move(uint16_t book_move); | ||
size_t NumBookEntries; | ||
BookEntry *BookEntries; | ||
void byteswap_bookentry(BookEntry *be); | ||
int max_book_ply; | ||
}; | ||
|
||
extern Book Books; | ||
|
||
#endif // #ifndef BOOK_H_INCLUDED |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.