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