--- /dev/null
+\r
+// book.c\r
+\r
+// includes\r
+\r
+#include <errno.h>\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <string.h>\r
+\r
+#include "board.h"\r
+#include "book.h"\r
+#include "move.h"\r
+#include "move_legal.h"\r
+#include "san.h"\r
+#include "util.h"\r
+#include "option.h"\r
+\r
+// types\r
+\r
+typedef struct {\r
+ uint64 key;\r
+ uint16 move;\r
+ uint16 count;\r
+ uint16 n;\r
+ uint16 sum;\r
+} entry_t;\r
+\r
+// variables\r
+\r
+static FILE * BookFile;\r
+static int BookSize;\r
+\r
+// prototypes\r
+\r
+static int find_pos (uint64 key);\r
+\r
+static void read_entry (entry_t * entry, int n);\r
+static void write_entry (const entry_t * entry, int n);\r
+\r
+static uint64 read_integer (FILE * file, int size);\r
+static void write_integer (FILE * file, int size, uint64 n);\r
+\r
+// functions\r
+\r
+// book_clear()\r
+\r
+void book_clear() {\r
+\r
+ BookFile = NULL;\r
+ BookSize = 0;\r
+}\r
+\r
+bool book_is_open(){\r
+ return BookFile!=NULL;\r
+}\r
+\r
+// book_open()\r
+\r
+void book_open(const char file_name[]) {\r
+\r
+ ASSERT(file_name!=NULL);\r
+ if(option_get_bool("BookLearn")){\r
+ BookFile = fopen(file_name,"rb+");\r
+ }else{\r
+ BookFile = fopen(file_name,"rb");\r
+ }\r
+ \r
+// if (BookFile == NULL) my_fatal("book_open(): can't open file \"%s\": %s\n",file_name,strerror(errno));\r
+ if (BookFile == NULL) return; \r
+\r
+ if (fseek(BookFile,0,SEEK_END) == -1) {\r
+ my_fatal("book_open(): fseek(): %s\n",strerror(errno));\r
+ }\r
+\r
+ BookSize = ftell(BookFile) / 16;\r
+// if (BookSize == 0) my_fatal("book_open(): empty file\n");\r
+ if (BookSize == 0) {\r
+ book_close();\r
+ book_clear(); \r
+ };\r
+}\r
+\r
+// book_close()\r
+\r
+void book_close() {\r
+\r
+ if(BookFile==NULL) return;\r
+\r
+ if (fclose(BookFile) == EOF) {\r
+ my_fatal("book_close(): fclose(): %s\n",strerror(errno));\r
+ }\r
+}\r
+\r
+// is_in_book()\r
+\r
+bool is_in_book(const board_t * board) {\r
+\r
+ int pos;\r
+ entry_t entry[1];\r
+\r
+ if(BookFile==NULL) return FALSE;\r
+\r
+ ASSERT(board!=NULL);\r
+\r
+ for (pos = find_pos(board->key); pos < BookSize; pos++) {\r
+ read_entry(entry,pos);\r
+ if (entry->key == board->key) return TRUE;\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
+// book_move()\r
+\r
+int book_move(const board_t * board, bool random) {\r
+\r
+ int best_move;\r
+ int best_score;\r
+ int pos;\r
+ entry_t entry[1];\r
+ int move;\r
+ int score;\r
+\r
+ if(BookFile==NULL) return MoveNone;\r
+\r
+ ASSERT(board!=NULL);\r
+ ASSERT(random==TRUE||random==FALSE);\r
+\r
+\r
+ best_move = MoveNone;\r
+ best_score = 0;\r
+ for (pos = find_pos(board->key); pos < BookSize; pos++) {\r
+\r
+ read_entry(entry,pos);\r
+ if (entry->key != board->key) break;\r
+\r
+ move = entry->move;\r
+ score = entry->count;\r
+\r
+ if (move != MoveNone && move_is_legal(move,board)) {\r
+\r
+ // pick this move?\r
+\r
+ ASSERT(score>0);\r
+\r
+ if (random) {\r
+ best_score += score;\r
+ if (my_random_int(best_score) < score) best_move = move;\r
+ } else {\r
+ if (score > best_score) {\r
+ best_move = move;\r
+ best_score = score;\r
+ }\r
+ }\r
+\r
+ } else {\r
+\r
+ ASSERT(FALSE);\r
+ }\r
+ }\r
+\r
+ return best_move;\r
+}\r
+\r
+// book_disp()\r
+\r
+void book_disp(const board_t * board) {\r
+\r
+ int first_pos;\r
+ int sum;\r
+ int pos;\r
+ entry_t entry[1];\r
+ int move;\r
+ int score;\r
+ char move_string[256];\r
+\r
+ ASSERT(board!=NULL);\r
+\r
+ if(BookFile==NULL) return; \r
+\r
+ first_pos = find_pos(board->key);\r
+\r
+ // sum\r
+\r
+ sum = 0;\r
+\r
+ for (pos = first_pos; pos < BookSize; pos++) {\r
+\r
+ read_entry(entry,pos);\r
+ if (entry->key != board->key) break;\r
+\r
+ sum += entry->count;\r
+ }\r
+\r
+ // disp\r
+\r
+ for (pos = first_pos; pos < BookSize; pos++) {\r
+\r
+ read_entry(entry,pos);\r
+ if (entry->key != board->key) break;\r
+\r
+ move = entry->move;\r
+ score = entry->count;\r
+\r
+ if (score > 0 && move != MoveNone && move_is_legal(move,board)) {\r
+ move_to_san(move,board,move_string,256);\r
+ printf(" %s (%.0f%%)\n",move_string,((double)score)/((double)sum)*100.0);\r
+ }\r
+ }\r
+\r
+ printf("\n");\r
+}\r
+\r
+// book_learn_move()\r
+\r
+void book_learn_move(const board_t * board, int move, int result) {\r
+\r
+ int pos;\r
+ entry_t entry[1];\r
+\r
+ if(BookFile==NULL) return;\r
+\r
+ ASSERT(board!=NULL);\r
+ ASSERT(move_is_ok(move));\r
+ ASSERT(result>=-1&&result<=+1);\r
+\r
+ ASSERT(move_is_legal(move,board));\r
+\r
+ for (pos = find_pos(board->key); pos < BookSize; pos++) {\r
+\r
+ read_entry(entry,pos);\r
+ if (entry->key != board->key) break;\r
+\r
+ if (entry->move == move) {\r
+\r
+ entry->n++;\r
+ entry->sum += result+1;\r
+\r
+ write_entry(entry,pos);\r
+\r
+ break;\r
+ }\r
+ }\r
+}\r
+\r
+// book_flush()\r
+\r
+void book_flush() {\r
+\r
+ if(BookFile==NULL) return;\r
+\r
+ if (fflush(BookFile) == EOF) {\r
+ my_fatal("book_flush(): fflush(): %s\n",strerror(errno));\r
+ }\r
+}\r
+\r
+// find_pos()\r
+\r
+static int find_pos(uint64 key) {\r
+\r
+ int left, right, mid;\r
+ entry_t entry[1];\r
+\r
+ // binary search (finds the leftmost entry)\r
+\r
+ left = 0;\r
+ right = BookSize-1;\r
+\r
+ ASSERT(left<=right);\r
+\r
+ while (left < right) {\r
+\r
+ mid = (left + right) / 2;\r
+ ASSERT(mid>=left&&mid<right);\r
+\r
+ read_entry(entry,mid);\r
+\r
+ if (key <= entry->key) {\r
+ right = mid;\r
+ } else {\r
+ left = mid+1;\r
+ }\r
+ }\r
+\r
+ ASSERT(left==right);\r
+\r
+ read_entry(entry,left);\r
+\r
+ return (entry->key == key) ? left : BookSize;\r
+}\r
+\r
+// read_entry()\r
+\r
+static void read_entry(entry_t * entry, int n) {\r
+\r
+ ASSERT(entry!=NULL);\r
+ ASSERT(n>=0&&n<BookSize);\r
+\r
+ if (fseek(BookFile,n*16,SEEK_SET) == -1) {\r
+ my_fatal("read_entry(): fseek(): %s\n",strerror(errno));\r
+ }\r
+\r
+ entry->key = read_integer(BookFile,8);\r
+ entry->move = read_integer(BookFile,2);\r
+ entry->count = read_integer(BookFile,2);\r
+ entry->n = read_integer(BookFile,2);\r
+ entry->sum = read_integer(BookFile,2);\r
+}\r
+\r
+// write_entry()\r
+\r
+static void write_entry(const entry_t * entry, int n) {\r
+\r
+ ASSERT(entry!=NULL);\r
+ ASSERT(n>=0&&n<BookSize);\r
+\r
+ if (fseek(BookFile,n*16,SEEK_SET) == -1) {\r
+ my_fatal("write_entry(): fseek(): %s\n",strerror(errno));\r
+ }\r
+\r
+ write_integer(BookFile,8,entry->key);\r
+ write_integer(BookFile,2,entry->move);\r
+ write_integer(BookFile,2,entry->count);\r
+ write_integer(BookFile,2,entry->n);\r
+ write_integer(BookFile,2,entry->sum);\r
+}\r
+\r
+// read_integer()\r
+\r
+static uint64 read_integer(FILE * file, int size) {\r
+\r
+ uint64 n;\r
+ int i;\r
+ int b;\r
+\r
+ ASSERT(file!=NULL);\r
+ ASSERT(size>0&&size<=8);\r
+\r
+ n = 0;\r
+\r
+ for (i = 0; i < size; i++) {\r
+\r
+ b = fgetc(file);\r
+\r
+ if (b == EOF) {\r
+ if (feof(file)) {\r
+ my_fatal("read_integer(): fgetc(): EOF reached\n");\r
+ } else { // error\r
+ my_fatal("read_integer(): fgetc(): %s\n",strerror(errno));\r
+ }\r
+ }\r
+\r
+ ASSERT(b>=0&&b<256);\r
+ n = (n << 8) | b;\r
+ }\r
+\r
+ return n;\r
+}\r
+\r
+// write_integer()\r
+\r
+static void write_integer(FILE * file, int size, uint64 n) {\r
+\r
+ int i;\r
+ int b;\r
+\r
+ ASSERT(file!=NULL);\r
+ ASSERT(size>0&&size<=8);\r
+ ASSERT(size==8||n>>(size*8)==0);\r
+\r
+ for (i = size-1; i >= 0; i--) {\r
+\r
+ b = (n >> (i*8)) & 0xFF;\r
+ ASSERT(b>=0&&b<256);\r
+\r
+ if (fputc(b,file) == EOF) {\r
+ my_fatal("write_integer(): fputc(): %s\n",strerror(errno));\r
+ }\r
+ }\r
+}\r
+\r
+// end of book.cpp\r
+\r