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