20 using value_t = int8_t;
21 static constexpr size_t SIZE_BYTES_8PLY_DB = 103'545;
22 static constexpr size_t SIZE_BYTES_12PLY_DB = 6'943'780;
23 static constexpr size_t SIZE_BYTES_12PLY_DB_WITH_DIST = 21'004'495;
25 static constexpr size_t SIZE_8PLY_DB = 34'515;
26 static constexpr size_t SIZE_12PLY_DB = 1'735'945;
27 static constexpr size_t SIZE_12PLY_DB_WITH_DIST = 4'200'899;
29 std::vector<std::tuple<key_t, value_t>> m_book;
30 bool m_withDistances{};
32 std::filesystem::path m_bookPath;
35 [[nodiscard]] value_t binarySearch(
const key_t& huffmanCode)
const {
38 int r = m_book.size() - 1;
40 const auto mid = (l + r + 1) / 2;
41 auto p = m_book.at(mid);
42 if (std::get<0>(p) == huffmanCode) {
43 return std::get<1>(p);
45 if (std::get<0>(p) > huffmanCode) {
53 return std::numeric_limits<value_t>::min();
57 static constexpr auto NONE_VALUE = std::numeric_limits<value_t>::min();
59 explicit OpeningBook(
const std::filesystem::path& bookPath,
60 const bool is_8ply,
const bool with_distances) {
61 init(bookPath, is_8ply, with_distances);
64 explicit OpeningBook(
const std::filesystem::path& bookPath) {
65 if (!std::filesystem::exists(bookPath)) {
66 throw std::invalid_argument(
"Book file does not exist: " +
70 const auto fileSize = std::filesystem::file_size(bookPath);
72 const bool is8ply = (fileSize == SIZE_BYTES_8PLY_DB);
73 const bool withDistances = (fileSize == SIZE_BYTES_12PLY_DB_WITH_DIST);
75 init(bookPath, is8ply, withDistances);
78 auto getBook()
const {
return m_book; }
80 void init(
const std::filesystem::path& bookPath,
const bool is_8ply,
81 const bool with_distances) {
82 assert(!is_8ply || !with_distances);
85 if (!std::filesystem::exists(bookPath)) {
86 throw std::invalid_argument(
"Book file does not exist: " +
92 const auto fileSize = std::filesystem::file_size(bookPath);
95 assert(fileSize == SIZE_BYTES_8PLY_DB);
96 }
else if (with_distances) {
98 SIZE_BYTES_12PLY_DB_WITH_DIST);
100 assert(fileSize == SIZE_BYTES_12PLY_DB);
103 this->m_withDistances = with_distances;
104 this->m_is8ply = is_8ply;
105 this->m_book = readBook(bookPath, with_distances, is_8ply);
106 this->m_bookPath = bookPath;
107 this->m_nPly = (is_8ply ? 8 : 12);
109 assert(!with_distances || is_8ply ||
110 m_book.size() == SIZE_12PLY_DB_WITH_DIST);
112 assert(with_distances || is_8ply ||
113 m_book.size() == SIZE_12PLY_DB);
116 m_book.size() == SIZE_8PLY_DB);
119 [[nodiscard]]
auto getEntry(
const size_t entryIdx)
const {
120 return m_book.at(entryIdx);
123 [[nodiscard]]
auto getBookSize()
const {
return m_book.size(); }
125 static std::tuple<key_t, int> readline(std::ifstream& file,
126 const bool with_distances,
127 const bool is_8ply) {
128 const decltype(file.gcount()) bytes_position = is_8ply ? 3 : 4;
130 file.read(buffer, bytes_position);
132 if (file.gcount() != bytes_position) {
138 key_t huffman_position = 0;
139 for (
decltype(file.gcount()) i = 0; i < bytes_position; ++i) {
141 (huffman_position << 8) | static_cast<unsigned char>(buffer[i]);
146 if (huffman_position & (1LL << ((bytes_position * 8) - 1))) {
147 huffman_position -= (1LL << (bytes_position * 8));
152 if (with_distances) {
155 if (file.read(&score_byte, 1)) {
156 score =
static_cast<int8_t
>(score_byte);
163 score = (
static_cast<value_t
>(huffman_position) & 3) * -1;
164 huffman_position = huffman_position & ~3;
167 return {huffman_position, score};
170 int getNPly()
const {
return m_nPly; }
172 static std::vector<std::tuple<key_t, value_t>> readBook(
173 const std::filesystem::path& filename,
const bool with_distances =
true,
174 const bool is_8ply =
false) {
175 std::vector<std::tuple<key_t, value_t>> book;
176 std::ifstream file(filename, std::ios::binary);
178 std::cerr <<
"Failed to open file: " << filename.string() <<
'\n';
183 auto [position, score] = readline(file, with_distances, is_8ply);
187 book.emplace_back(position, score);
193 template <
typename T>
194 static int sign(T value) {
195 return (value > 0) - (value < 0);
198 int inline convertValue(
const int value,
const Board& b)
const {
199 if (!m_withDistances)
return value;
202 int movesLeft = std::abs(value) - 100 + b.movesLeft();
203 return sign(value) * (movesLeft / 2 + 1);
206 [[nodiscard]]
bool isInBook(
const Board& b)
const {
208 return (binarySearch(b.toHuffman()) != NONE_VALUE);
211 [[nodiscard]]
int getBoardValue(
const Board& b)
const {
212 if (!((m_is8ply && b.countTokens() == 8) || b.countTokens() == 12)) {
217 auto p = b.toHuffman();
218 int val = binarySearch(p);
219 if (val != NONE_VALUE) {
220 return convertValue(val, b);
224 p = b.mirror().toHuffman();
225 val = binarySearch(p);
226 if (!m_withDistances && val == NONE_VALUE) {
237 }
else if (val == NONE_VALUE) {
240 return (b.movesLeft() + 1) / 2;
242 assert(val != NONE_VALUE);
243 return convertValue(val, b);