BitBully 0.0.39
Loading...
Searching...
No Matches
OpeningBook.hpp
1/*
2 * This file is part of Connect4 Game Solver <http://connect4.gamesolver.org>
3 * Copyright (C) 2017-2019 Pascal Pons <contact@gamesolver.org>
4 *
5 * Connect4 Game Solver is free software: you can redistribute it and/or
6 * modify it under the terms of the GNU Affero General Public License as
7 * published by the Free Software Foundation, either version 3 of the
8 * License, or (at your option) any later version.
9 *
10 * Connect4 Game Solver is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Affero General Public License for more details.
14 *
15 * You should have received a copy of the GNU Affero General Public License
16 * along with Connect4 Game Solver. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#ifndef OPENING_BOOK_HPP
20#define OPENING_BOOK_HPP
21
22#include <iostream>
23#include <fstream>
24#include "Position.hpp"
25#include "TranspositionTable.hpp"
26
27namespace GameSolver {
28namespace Connect4 {
29
30class OpeningBook {
32 const int width;
33 const int height;
34 int depth;
35
36 template<class partial_key_t>
37 TableGetter<Position::position_t, uint8_t>* initTranspositionTable(int log_size) {
38 switch(log_size) {
39 case 21:
41 case 22:
43 case 23:
45 case 24:
47 case 25:
49 case 26:
51 case 27:
53 default:
54 std::cerr << "Unimplemented OpeningBook size: " << log_size << std::endl;
55 return 0;
56 }
57 }
58
59 TableGetter<Position::position_t, uint8_t>* initTranspositionTable(int partial_key_bytes, int log_size) {
60 switch(partial_key_bytes) {
61 case 1:
62 return initTranspositionTable<uint8_t>(log_size);
63 case 2:
64 return initTranspositionTable<uint16_t>(log_size);
65 case 4:
66 return initTranspositionTable<uint32_t>(log_size);
67 default:
68 std::cerr << "Invalid internal key size: " << partial_key_bytes << " bytes" << std::endl;
69 return 0;
70 }
71 }
72
73 public:
74 OpeningBook(int width, int height) : T{0}, width{width}, height{height}, depth{ -1} {} // Empty opening book
75
76 OpeningBook(int width, int height, int depth, TableGetter<Position::position_t, uint8_t>* T) : T{T}, width{width}, height{height}, depth{depth} {} // Empty opening book
88 void load(std::string filename) {
89 depth = -1;
90 delete T;
91 std::ifstream ifs(filename, std::ios::binary); // open file
92
93 if(ifs.fail()) {
94 std::cerr << "Unable to load opening book: " << filename << std::endl;
95 return;
96 } else std::cerr << "Loading opening book from file: " << filename << ". ";
97
98 char _width, _height, _depth, value_bytes, partial_key_bytes, log_size;
99
100 ifs.read(&_width, 1);
101 if(ifs.fail() || _width != width) {
102 std::cerr << "Unable to load opening book: invalid width (found: " << int(_width) << ", expected: " << width << ")" << std::endl;
103 return;
104 }
105
106 ifs.read(&_height, 1);
107 if(ifs.fail() || _height != height) {
108 std::cerr << "Unable to load opening book: invalid height(found: " << int(_height) << ", expected: " << height << ")" << std::endl;
109 return;
110 }
111
112 ifs.read(&_depth, 1);
113 if(ifs.fail() || _depth > width * height) {
114 std::cerr << "Unable to load opening book: invalid depth (found: " << int(_depth) << ")" << std::endl;
115 return;
116 }
117
118 ifs.read(&partial_key_bytes, 1);
119 if(ifs.fail() || partial_key_bytes > 8) {
120 std::cerr << "Unable to load opening book: invalid internal key size(found: " << int(partial_key_bytes) << ")" << std::endl;
121 return;
122 }
123
124 ifs.read(&value_bytes, 1);
125 if(ifs.fail() || value_bytes != 1) {
126 std::cerr << "Unable to load opening book: invalid value size (found: " << int(value_bytes) << ", expected: 1)" << std::endl;
127 return;
128 }
129
130 ifs.read(&log_size, 1);
131 if(ifs.fail() || log_size > 40) {
132 std::cerr << "Unable to load opening book: invalid log2(size)(found: " << int(log_size) << ")" << std::endl;
133 return;
134 }
135
136 if((T = initTranspositionTable(partial_key_bytes, log_size))) {
137 ifs.read(reinterpret_cast<char *>(T->getKeys()), T->getSize() * partial_key_bytes);
138 ifs.read(reinterpret_cast<char *>(T->getValues()), T->getSize() * value_bytes);
139 if(ifs.fail()) {
140 std::cerr << "Unable to load data from opening book" << std::endl;
141 return;
142 }
143 depth = _depth; // set it in case of success only, keep -1 in case of failure
144 std::cerr << "done" << std::endl;
145 }
146 else std::cerr << "Unable to initialize opening book" << std::endl;
147 ifs.close();
148 }
149
150 void save(const std::string output_file) const {
151 std::ofstream ofs(output_file, std::ios::binary);
152 char tmp;
153 tmp = width;
154 ofs.write(&tmp, 1);
155 tmp = height;
156 ofs.write(&tmp, 1);
157 tmp = depth;
158 ofs.write(&tmp, 1);
159 tmp = T->getKeySize();
160 ofs.write(&tmp, 1);
161 tmp = T->getValueSize();
162 ofs.write(&tmp, 1);
163 tmp = log2(T->getSize());
164 ofs.write(&tmp, 1);
165
166 ofs.write(reinterpret_cast<const char *>(T->getKeys()), T->getSize() * T->getKeySize());
167 ofs.write(reinterpret_cast<const char *>(T->getValues()), T->getSize() * T->getValueSize());
168 ofs.close();
169 }
170
171 int get(const Position &P) const {
172 if(P.nbMoves() > depth) return 0;
173 else return T->get(P.key3());
174 }
175
176 ~OpeningBook() {
177 delete T;
178 }
179};
180
181} // namespace Connect4
182} // namespace GameSolver
183#endif
void load(std::string filename)