Add forgotten files 1.4.70b
[polyglot.git] / book.cpp
1 \r
2 // book.cpp\r
3 \r
4 // includes\r
5 \r
6 #include <cerrno>\r
7 #include <cstdio>\r
8 #include <cstdlib>\r
9 #include <cstring>\r
10 \r
11 #include "board.h"\r
12 #include "book.h"\r
13 #include "move.h"\r
14 #include "move_legal.h"\r
15 #include "san.h"\r
16 #include "util.h"\r
17 #include "option.h"\r
18 \r
19 // types\r
20 \r
21 struct entry_t {\r
22    uint64 key;\r
23    uint16 move;\r
24    uint16 count;\r
25    uint16 n;\r
26    uint16 sum;\r
27 };\r
28 \r
29 // variables\r
30 \r
31 static FILE * BookFile;\r
32 static int BookSize;\r
33 \r
34 // prototypes\r
35 \r
36 static int    find_pos      (uint64 key);\r
37 \r
38 static void   read_entry    (entry_t * entry, int n);\r
39 static void   write_entry   (const entry_t * entry, int n);\r
40 \r
41 static uint64 read_integer  (FILE * file, int size);\r
42 static void   write_integer (FILE * file, int size, uint64 n);\r
43 \r
44 // functions\r
45 \r
46 // book_clear()\r
47 \r
48 void book_clear() {\r
49 \r
50    BookFile = NULL;\r
51    BookSize = 0;\r
52 }\r
53 \r
54 bool book_is_open(){\r
55     return BookFile!=NULL;\r
56 }\r
57 \r
58 // book_open()\r
59 \r
60 void book_open(const char file_name[]) {\r
61 \r
62    ASSERT(file_name!=NULL);\r
63    if(option_get_bool("BookLearn")){\r
64        BookFile = fopen(file_name,"rb+");\r
65    }else{\r
66        BookFile = fopen(file_name,"rb");\r
67    }\r
68       \r
69 //   if (BookFile == NULL) my_fatal("book_open(): can't open file \"%s\": %s\n",file_name,strerror(errno));\r
70    if (BookFile == NULL)  return; \r
71 \r
72    if (fseek(BookFile,0,SEEK_END) == -1) {\r
73       my_fatal("book_open(): fseek(): %s\n",strerror(errno));\r
74    }\r
75 \r
76    BookSize = ftell(BookFile) / 16;\r
77 //   if (BookSize == 0) my_fatal("book_open(): empty file\n");\r
78    if (BookSize == 0) {\r
79       book_close();\r
80       book_clear(); \r
81    };\r
82 }\r
83 \r
84 // book_close()\r
85 \r
86 void book_close() {\r
87 \r
88    if(BookFile==NULL) return;\r
89 \r
90    if (fclose(BookFile) == EOF) {\r
91       my_fatal("book_close(): fclose(): %s\n",strerror(errno));\r
92    }\r
93 }\r
94 \r
95 // is_in_book()\r
96 \r
97 bool is_in_book(const board_t * board) {\r
98 \r
99    int pos;\r
100    entry_t entry[1];\r
101 \r
102    if(BookFile==NULL) return false;\r
103 \r
104    ASSERT(board!=NULL);\r
105 \r
106    for (pos = find_pos(board->key); pos < BookSize; pos++) {\r
107       read_entry(entry,pos);\r
108       if (entry->key == board->key) return true;\r
109    }\r
110 \r
111    return false;\r
112 }\r
113 \r
114 // book_move()\r
115 \r
116 int book_move(const board_t * board, bool random) {\r
117 \r
118    int best_move;\r
119    int best_score;\r
120    int pos;\r
121    entry_t entry[1];\r
122    int move;\r
123    int score;\r
124 \r
125    if(BookFile==NULL) return MoveNone;\r
126 \r
127    ASSERT(board!=NULL);\r
128    ASSERT(random==true||random==false);\r
129 \r
130 \r
131    best_move = MoveNone;\r
132    best_score = 0;\r
133    for (pos = find_pos(board->key); pos < BookSize; pos++) {\r
134 \r
135       read_entry(entry,pos);\r
136       if (entry->key != board->key) break;\r
137 \r
138       move = entry->move;\r
139       score = entry->count;\r
140 \r
141       if (move != MoveNone && move_is_legal(move,board)) {\r
142 \r
143          // pick this move?\r
144 \r
145          ASSERT(score>0);\r
146 \r
147          if (random) {\r
148             best_score += score;\r
149             if (my_random_int(best_score) < score) best_move = move;\r
150          } else {\r
151             if (score > best_score) {\r
152                best_move = move;\r
153                best_score = score;\r
154             }\r
155          }\r
156 \r
157       } else {\r
158 \r
159          ASSERT(false);\r
160       }\r
161    }\r
162 \r
163    return best_move;\r
164 }\r
165 \r
166 // book_disp()\r
167 \r
168 void book_disp(const board_t * board) {\r
169 \r
170    int first_pos;\r
171    int sum;\r
172    int pos;\r
173    entry_t entry[1];\r
174    int move;\r
175    int score;\r
176    char move_string[256];\r
177 \r
178    ASSERT(board!=NULL);\r
179 \r
180    if(BookFile==NULL) return; \r
181 \r
182    first_pos = find_pos(board->key);\r
183 \r
184    // sum\r
185 \r
186    sum = 0;\r
187 \r
188    for (pos = first_pos; pos < BookSize; pos++) {\r
189 \r
190       read_entry(entry,pos);\r
191       if (entry->key != board->key) break;\r
192 \r
193       sum += entry->count;\r
194    }\r
195 \r
196    // disp\r
197 \r
198    for (pos = first_pos; pos < BookSize; pos++) {\r
199 \r
200       read_entry(entry,pos);\r
201       if (entry->key != board->key) break;\r
202 \r
203       move = entry->move;\r
204       score = entry->count;\r
205 \r
206       if (score > 0 && move != MoveNone && move_is_legal(move,board)) {\r
207          move_to_san(move,board,move_string,256);\r
208          printf(" %s (%.0f%%)\n",move_string,(double(score)/double(sum))*100.0);\r
209       }\r
210    }\r
211 \r
212    printf("\n");\r
213 }\r
214 \r
215 // book_learn_move()\r
216 \r
217 void book_learn_move(const board_t * board, int move, int result) {\r
218 \r
219    int pos;\r
220    entry_t entry[1];\r
221 \r
222    if(BookFile==NULL) return;\r
223 \r
224    ASSERT(board!=NULL);\r
225    ASSERT(move_is_ok(move));\r
226    ASSERT(result>=-1&&result<=+1);\r
227 \r
228    ASSERT(move_is_legal(move,board));\r
229 \r
230    for (pos = find_pos(board->key); pos < BookSize; pos++) {\r
231 \r
232       read_entry(entry,pos);\r
233       if (entry->key != board->key) break;\r
234 \r
235       if (entry->move == move) {\r
236 \r
237          entry->n++;\r
238          entry->sum += result+1;\r
239 \r
240          write_entry(entry,pos);\r
241 \r
242          break;\r
243       }\r
244    }\r
245 }\r
246 \r
247 // book_flush()\r
248 \r
249 void book_flush() {\r
250 \r
251    if(BookFile==NULL) return;\r
252 \r
253    if (fflush(BookFile) == EOF) {\r
254       my_fatal("book_flush(): fflush(): %s\n",strerror(errno));\r
255    }\r
256 }\r
257 \r
258 // find_pos()\r
259 \r
260 static int find_pos(uint64 key) {\r
261 \r
262    int left, right, mid;\r
263    entry_t entry[1];\r
264 \r
265    // binary search (finds the leftmost entry)\r
266 \r
267    left = 0;\r
268    right = BookSize-1;\r
269 \r
270    ASSERT(left<=right);\r
271 \r
272    while (left < right) {\r
273 \r
274       mid = (left + right) / 2;\r
275       ASSERT(mid>=left&&mid<right);\r
276 \r
277       read_entry(entry,mid);\r
278 \r
279       if (key <= entry->key) {\r
280          right = mid;\r
281       } else {\r
282          left = mid+1;\r
283       }\r
284    }\r
285 \r
286    ASSERT(left==right);\r
287 \r
288    read_entry(entry,left);\r
289 \r
290    return (entry->key == key) ? left : BookSize;\r
291 }\r
292 \r
293 // read_entry()\r
294 \r
295 static void read_entry(entry_t * entry, int n) {\r
296 \r
297    ASSERT(entry!=NULL);\r
298    ASSERT(n>=0&&n<BookSize);\r
299 \r
300    if (fseek(BookFile,n*16,SEEK_SET) == -1) {\r
301       my_fatal("read_entry(): fseek(): %s\n",strerror(errno));\r
302    }\r
303 \r
304    entry->key   = read_integer(BookFile,8);\r
305    entry->move  = read_integer(BookFile,2);\r
306    entry->count = read_integer(BookFile,2);\r
307    entry->n     = read_integer(BookFile,2);\r
308    entry->sum   = read_integer(BookFile,2);\r
309 }\r
310 \r
311 // write_entry()\r
312 \r
313 static void write_entry(const entry_t * entry, int n) {\r
314 \r
315    ASSERT(entry!=NULL);\r
316    ASSERT(n>=0&&n<BookSize);\r
317 \r
318    if (fseek(BookFile,n*16,SEEK_SET) == -1) {\r
319       my_fatal("write_entry(): fseek(): %s\n",strerror(errno));\r
320    }\r
321 \r
322    write_integer(BookFile,8,entry->key);\r
323    write_integer(BookFile,2,entry->move);\r
324    write_integer(BookFile,2,entry->count);\r
325    write_integer(BookFile,2,entry->n);\r
326    write_integer(BookFile,2,entry->sum);\r
327 }\r
328 \r
329 // read_integer()\r
330 \r
331 static uint64 read_integer(FILE * file, int size) {\r
332 \r
333    uint64 n;\r
334    int i;\r
335    int b;\r
336 \r
337    ASSERT(file!=NULL);\r
338    ASSERT(size>0&&size<=8);\r
339 \r
340    n = 0;\r
341 \r
342    for (i = 0; i < size; i++) {\r
343 \r
344       b = fgetc(file);\r
345 \r
346       if (b == EOF) {\r
347          if (feof(file)) {\r
348             my_fatal("read_integer(): fgetc(): EOF reached\n");\r
349          } else { // error\r
350             my_fatal("read_integer(): fgetc(): %s\n",strerror(errno));\r
351          }\r
352       }\r
353 \r
354       ASSERT(b>=0&&b<256);\r
355       n = (n << 8) | b;\r
356    }\r
357 \r
358    return n;\r
359 }\r
360 \r
361 // write_integer()\r
362 \r
363 static void write_integer(FILE * file, int size, uint64 n) {\r
364 \r
365    int i;\r
366    int b;\r
367 \r
368    ASSERT(file!=NULL);\r
369    ASSERT(size>0&&size<=8);\r
370    ASSERT(size==8||n>>(size*8)==0);\r
371 \r
372    for (i = size-1; i >= 0; i--) {\r
373 \r
374       b = (n >> (i*8)) & 0xFF;\r
375       ASSERT(b>=0&&b<256);\r
376 \r
377       if (fputc(b,file) == EOF) {\r
378          my_fatal("write_integer(): fputc(): %s\n",strerror(errno));\r
379       }\r
380    }\r
381 }\r
382 \r
383 // end of book.cpp\r
384 \r