14 #include "move_legal.h"
31 static FILE * BookFile;
36 static int find_pos (uint64 key);
38 static void read_entry (entry_t * entry, int n);
39 static void write_entry (const entry_t * entry, int n);
41 static uint64 read_integer (FILE * file, int size);
42 static void write_integer (FILE * file, int size, uint64 n);
55 return BookFile!=NULL;
60 void book_open(const char file_name[]) {
62 ASSERT(file_name!=NULL);
63 if(option_get_bool(Option,"BookLearn")){
64 BookFile = fopen(file_name,"rb+");
66 BookFile = fopen(file_name,"rb");
69 // if (BookFile == NULL) my_fatal("book_open(): can't open file \"%s\": %s\n",file_name,strerror(errno));
70 if (BookFile == NULL) return;
72 if (fseek(BookFile,0,SEEK_END) == -1) {
73 my_fatal("book_open(): fseek(): %s\n",strerror(errno));
76 BookSize = ftell(BookFile) / 16;
77 // if (BookSize == 0) my_fatal("book_open(): empty file\n");
88 if(BookFile==NULL) return;
90 if (fclose(BookFile) == EOF) {
91 my_fatal("book_close(): fclose(): %s\n",strerror(errno));
97 bool is_in_book(const board_t * board) {
102 if(BookFile==NULL) return FALSE;
106 for (pos = find_pos(board->key); pos < BookSize; pos++) {
107 read_entry(entry,pos);
108 if (entry->key == board->key) return TRUE;
116 int book_move(const board_t * board, bool random) {
127 if(BookFile==NULL) return MoveNone;
130 ASSERT(random==TRUE||random==FALSE);
136 book_moves(list,board);
138 best_move = MoveNone;
140 for(i=0; i<list_size(list); i++){
142 move = list->move[i];
143 score = list->value[i];
145 if (move != MoveNone &&
146 move_is_legal(move,board) &&
147 score>10*option_get_int(Option,"BookTreshold")) {
155 if (my_random_int(best_score) < score) best_move = move;
157 if (score > best_score) {
174 void book_moves(list_t * list, const board_t * board) {
182 uint32 weight[1000]; // [HGM] assumes not more than 1000 book moves per position!
183 char move_string[256];
188 if(BookFile==NULL) return;
194 first_pos = find_pos(board->key);
200 for (pos = first_pos; pos < BookSize; pos++) {
202 read_entry(entry,pos);
203 if (entry->key != board->key) break;
205 weight[pos - first_pos] = 1000 * (uint32)entry->count;
206 if(option_get_bool(Option,"BookLearn")) // [HGM] improvised use of learn info
207 weight[pos - first_pos] *= ((uint32)entry->n + 10.) /((uint32)entry->sum + 1.);
208 sum += weight[pos - first_pos];
213 for (pos = first_pos; pos < BookSize; pos++) {
215 read_entry(entry,pos);
216 if (entry->key != board->key) break;
219 score = (10000.*weight[pos-first_pos])/sum;
221 if (move != MoveNone && move_is_legal(move,board)) {
222 list_add_ex(list,move,score);
231 void book_disp(const board_t * board) {
233 char move_string[256];
236 int treshold=option_get_int(Option,"BookTreshold");
240 if(BookFile==NULL) return;
242 book_moves(list,board);
244 for(i=0; i<list_size(list); i++){
245 move_to_san(list->move[i],board,move_string,256);
246 if(list->value[i]>10*treshold){
247 printf(" %6s %5.2f%%\n",move_string,list->value[i]/100.0);
249 printf(" %6s %5.2f%% (below treshold %4.2f%%)\n",
250 move_string,list->value[i]/100.0,treshold/10.0);
253 // this is necessary by the xboard protocol
259 void book_learn_move(const board_t * board, int move, int result) {
264 if(BookFile==NULL) return;
267 ASSERT(move_is_ok(move));
268 ASSERT(result>=-1&&result<=+1);
270 ASSERT(move_is_legal(move,board));
272 for (pos = find_pos(board->key); pos < BookSize; pos++) {
274 read_entry(entry,pos);
275 if (entry->key != board->key) break;
277 if (entry->move == move) {
280 entry->sum += result+1;
282 write_entry(entry,pos);
293 if(BookFile==NULL) return;
295 if (fflush(BookFile) == EOF) {
296 my_fatal("book_flush(): fflush(): %s\n",strerror(errno));
302 static int find_pos(uint64 key) {
304 int left, right, mid;
307 // binary search (finds the leftmost entry)
314 while (left < right) {
316 mid = (left + right) / 2;
317 ASSERT(mid>=left&&mid<right);
319 read_entry(entry,mid);
321 if (key <= entry->key) {
330 read_entry(entry,left);
332 return (entry->key == key) ? left : BookSize;
337 static void read_entry(entry_t * entry, int n) {
340 ASSERT(n>=0&&n<BookSize);
342 if (fseek(BookFile,n*16,SEEK_SET) == -1) {
343 my_fatal("read_entry(): fseek(): %s\n",strerror(errno));
346 entry->key = read_integer(BookFile,8);
347 entry->move = read_integer(BookFile,2);
348 entry->count = read_integer(BookFile,2);
349 entry->n = read_integer(BookFile,2);
350 entry->sum = read_integer(BookFile,2);
355 static void write_entry(const entry_t * entry, int n) {
358 ASSERT(n>=0&&n<BookSize);
360 if (fseek(BookFile,n*16,SEEK_SET) == -1) {
361 my_fatal("write_entry(): fseek(): %s\n",strerror(errno));
364 write_integer(BookFile,8,entry->key);
365 write_integer(BookFile,2,entry->move);
366 write_integer(BookFile,2,entry->count);
367 write_integer(BookFile,2,entry->n);
368 write_integer(BookFile,2,entry->sum);
373 static uint64 read_integer(FILE * file, int size) {
380 ASSERT(size>0&&size<=8);
384 for (i = 0; i < size; i++) {
390 my_fatal("read_integer(): fgetc(): EOF reached\n");
392 my_fatal("read_integer(): fgetc(): %s\n",strerror(errno));
405 static void write_integer(FILE * file, int size, uint64 n) {
411 ASSERT(size>0&&size<=8);
412 ASSERT(size==8||n>>(size*8)==0);
414 for (i = size-1; i >= 0; i--) {
416 b = (n >> (i*8)) & 0xFF;
419 if (fputc(b,file) == EOF) {
420 my_fatal("write_integer(): fputc(): %s\n",strerror(errno));