version 1.4.30b
[polyglot.git] / book.c
diff --git a/book.c b/book.c
new file mode 100644 (file)
index 0000000..73fb2d2
--- /dev/null
+++ b/book.c
@@ -0,0 +1,384 @@
+\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