version 1.4w10UCIb18
[polyglot.git] / book_make.cpp
index ffffc9b..ba02f51 100644 (file)
@@ -1,4 +1,3 @@
-\r
 // book_make.cpp\r
 \r
 // includes\r
@@ -13,6 +12,7 @@
 #include "book_make.h"\r
 #include "move.h"\r
 #include "move_do.h"\r
+#include "move_gen.h"\r
 #include "move_legal.h"\r
 #include "pgn.h"\r
 #include "san.h"\r
 // constants\r
 \r
 static const int COUNT_MAX = 16384;\r
+static const int StringSize = 4096;\r
 \r
 static const int NIL = -1;\r
 \r
+// defines\r
+\r
+#define opp_search(s) ((s)==BOOK?ALL:BOOK)\r
+\r
 // types\r
 \r
 struct entry_t {\r
-   uint64 key;\r
-   uint16 move;\r
-   uint16 n;\r
-   uint16 sum;\r
-   uint16 colour;\r
+    uint64 key;\r
+    uint16 move;\r
+    uint16 count;\r
+    union{   // unfortunately minggw32 seems to have a bug with anon unions.\r
+        struct { \r
+            uint16 n;\r
+            uint16 sum;\r
+        };\r
+        struct{\r
+            uint8 height;\r
+            int line;\r
+        };\r
+    };\r
+    uint8 colour;\r
 };\r
 \r
 struct book_t {\r
@@ -42,6 +56,24 @@ struct book_t {
    sint32 * hash;\r
 };\r
 \r
+enum search_t {\r
+    BOOK,\r
+    ALL\r
+};\r
+\r
+struct info_t {\r
+    int height;\r
+    int line;\r
+    int initial_color;\r
+    bool book_trans_only;\r
+    bool extended_search;\r
+    uint16 moves[1024];\r
+    double probs[1024];\r
+    uint64 keys[1024];\r
+    FILE *output;\r
+};\r
+\r
+\r
 // variables\r
 \r
 static int MaxPly;\r
@@ -49,6 +81,7 @@ static int MinGame;
 static double MinScore;\r
 static bool RemoveWhite, RemoveBlack;\r
 static bool Uniform;\r
+static bool Quiet=false;\r
 \r
 static book_t Book[1];\r
 \r
@@ -71,6 +104,10 @@ static int    entry_score    (const entry_t * entry);
 static int    key_compare   (const void * p1, const void * p2);\r
 \r
 static void   write_integer (FILE * file, int size, uint64 n);\r
+static uint64 read_integer(FILE * file, int size);\r
+\r
+static void read_entry_file(FILE *f, entry_t *entry);\r
+static void write_entry_file(FILE * f, const entry_t * entry);\r
 \r
 // functions\r
 \r
@@ -332,9 +369,9 @@ static int find_entry(const board_t * board, int move) {
    int pos;\r
 \r
    ASSERT(board!=NULL);\r
-   ASSERT(move_is_ok(move));\r
+   ASSERT(move==MoveNone || move_is_ok(move));\r
 \r
-   ASSERT(move_is_legal(move,board));\r
+   ASSERT(move==MoveNone || move_is_legal(move,board));\r
 \r
    // init\r
 \r
@@ -342,7 +379,7 @@ static int find_entry(const board_t * board, int move) {
 \r
    // search\r
 \r
-   for (index = key & Book->mask; (pos=Book->hash[index]) != NIL; index = (index+1) & Book->mask) {\r
+   for (index = key & (uint64) Book->mask; (pos=Book->hash[index]) != NIL; index = (index+1) & Book->mask) {\r
 \r
       ASSERT(pos>=0&&pos<Book->size);\r
 \r
@@ -361,7 +398,7 @@ static int find_entry(const board_t * board, int move) {
 \r
       resize();\r
 \r
-      for (index = key & Book->mask; Book->hash[index] != NIL; index = (index+1) & Book->mask)\r
+      for (index = key & (uint64) Book->mask; Book->hash[index] != NIL; index = (index+1) & Book->mask)\r
          ;\r
    }\r
 \r
@@ -387,13 +424,24 @@ static int find_entry(const board_t * board, int move) {
    return pos;\r
 }\r
 \r
-// resize()\r
+// rebuild_hash_table\r
+\r
+static void rebuild_hash_table(){\r
+    int index,pos;\r
+    for (index = 0; index < Book->alloc*2; index++) {\r
+        Book->hash[index] = NIL;\r
+    }\r
+    for (pos = 0; pos < Book->size; pos++) {\r
+        for (index = Book->entry[pos].key & (uint64) Book->mask; Book->hash[index] != NIL; index = (index+1) & Book->mask)\r
+         ;\r
+        ASSERT(index>=0&&index<Book->alloc*2);\r
+        Book->hash[index] = pos;\r
+    }\r
+}\r
 \r
 static void resize() {\r
 \r
    int size;\r
-   int pos;\r
-   int index;\r
 \r
    ASSERT(Book->size==Book->alloc);\r
 \r
@@ -403,7 +451,9 @@ static void resize() {
    size = 0;\r
    size += Book->alloc * sizeof(entry_t);\r
    size += (Book->alloc*2) * sizeof(sint32);\r
-   if (size >= 1048576) printf("allocating %gMB ...\n",double(size)/1048576.0);\r
+\r
+   if (size >= 1048576) if(!Quiet){printf("allocating %gMB ...\n",double(size)/1048576.0);}\r
+\r
    // resize arrays\r
 \r
    Book->entry = (entry_t *) my_realloc(Book->entry,Book->alloc*sizeof(entry_t));\r
@@ -411,20 +461,10 @@ static void resize() {
 \r
    // rebuild hash table\r
 \r
-   for (index = 0; index < Book->alloc*2; index++) {\r
-      Book->hash[index] = NIL;\r
-   }\r
-\r
-   for (pos = 0; pos < Book->size; pos++) {\r
-\r
-      for (index = Book->entry[pos].key & Book->mask; Book->hash[index] != NIL; index = (index+1) & Book->mask)\r
-         ;\r
-\r
-      ASSERT(index>=0&&index<Book->alloc*2);\r
-      Book->hash[index] = pos;\r
-   }\r
+   rebuild_hash_table();\r
 }\r
 \r
+\r
 // halve_stats()\r
 \r
 static void halve_stats(uint64 key) {\r
@@ -434,7 +474,7 @@ static void halve_stats(uint64 key) {
 \r
    // search\r
 \r
-   for (index = key & Book->mask; (pos=Book->hash[index]) != NIL; index = (index+1) & Book->mask) {\r
+   for (index = key & (uint64) Book->mask; (pos=Book->hash[index]) != NIL; index = (index+1) & Book->mask) {\r
 \r
       ASSERT(pos>=0&&pos<Book->size);\r
 \r
@@ -536,5 +576,501 @@ static void write_integer(FILE * file, int size, uint64 n) {
    }\r
 }\r
 \r
+// read_integer()\r
+\r
+static uint64 read_integer(FILE * file, int size) {\r
+   uint64 n;\r
+   int i;\r
+   int b;\r
+   ASSERT(file!=NULL);\r
+   ASSERT(size>0&&size<=8);\r
+   n = 0;\r
+   for (i = 0; i < size; i++) {\r
+      b = fgetc(file);\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
+      ASSERT(b>=0&&b<256);\r
+      n = (n << 8) | b;\r
+   }\r
+   return n;\r
+}\r
+\r
+// read_entry_file\r
+\r
+static void read_entry_file(FILE *f, entry_t *entry){\r
+    uint64 n;\r
+    ASSERT(entry!=NULL);\r
+    n = entry->key   = read_integer(f,8);\r
+    entry->move  = read_integer(f,2);\r
+    entry->count = read_integer(f,2);\r
+    entry->n     = read_integer(f,2);\r
+    entry->sum   = read_integer(f,2);\r
+    ASSERT(n==entry->key); // test for mingw compiler bug with anon structs\r
+}\r
+\r
+// write_entry_file\r
+\r
+static void write_entry_file(FILE * f, const entry_t * entry) {\r
+   ASSERT(entry!=NULL);\r
+   write_integer(f,8,entry->key);\r
+   write_integer(f,2,entry->move);\r
+   write_integer(f,2,entry->count);\r
+   write_integer(f,2,entry->n);\r
+   write_integer(f,2,entry->sum);\r
+}\r
+\r
+static void print_list(const board_t *board, list_t *list){\r
+    int i;\r
+    uint16 move;\r
+    char move_string[256];\r
+    for (i = 0; i < list_size(list); i++) {\r
+        move = list_move(list,i);\r
+        move_to_san(move,board,move_string,256);\r
+        printf("%s",move_string);\r
+    }\r
+    printf("\n");\r
+}\r
+\r
+// book_load()\r
+// loads a polyglot book\r
+\r
+static void book_load(const char filename[]){\r
+    FILE* f;\r
+    entry_t entry[1];\r
+    int size;\r
+    int i;\r
+    int pos;\r
+    int index;\r
+    ASSERT(filename!=NULL);\r
+    if(!(f=fopen(filename,"rb"))){\r
+        my_fatal("book_load() : can't open file \"%s\" for reading: %s\n",filename,strerror(errno));\r
+    }\r
+    fseek(f,0L,SEEK_END);   // superportable way to get size of book!\r
+    size=ftell(f)/16;\r
+    fseek(f,0,SEEK_SET);\r
+    for(i=0L;i<size;i++){\r
+        read_entry_file(f,entry);\r
+        ASSERT(Book->size<=Book->alloc);\r
+        if (Book->size == Book->alloc) {\r
+                // allocate more memoryx\r
+            resize();\r
+        }\r
+            // insert into the book\r
+        pos = Book->size++;\r
+        Book->entry[pos].key = entry->key;\r
+        ASSERT(entry->move!=MoveNone);\r
+        Book->entry[pos].move = entry->move;\r
+        Book->entry[pos].count = entry->count;\r
+        Book->entry[pos].n = entry->n;\r
+        Book->entry[pos].sum = entry->sum;\r
+        Book->entry[pos].colour = ColourNone;\r
+            // find free hash table spot\r
+        for (index = entry->key & (uint64) Book->mask;\r
+             Book->hash[index] != NIL;\r
+             index = (index+1) & Book->mask);\r
+            // insert into the hash table\r
+        ASSERT(index>=0&&index<Book->alloc*2);\r
+        ASSERT(Book->hash[index]==NIL);\r
+        Book->hash[index] = pos;\r
+        ASSERT(pos>=0&&pos<Book->size);\r
+    }\r
+    fclose(f);\r
+}\r
+\r
+// gen_book_moves()\r
+// similar signature as gen_legal_moves\r
+static int gen_book_moves(list_t * list, const board_t * board){\r
+    int first_pos, pos, index;\r
+    entry_t entry[1];\r
+    list_clear(list);\r
+    bool found;\r
+    found=FALSE;\r
+    for (index = board->key & (uint64) Book->mask; (first_pos=Book->hash[index]) != NIL; index = (index+1) & Book->mask) {\r
+        ASSERT(first_pos>=0&&first_pos<Book->size);\r
+        if (Book->entry[first_pos].key == board->key) {\r
+            found=TRUE;\r
+            break; // found\r
+        }\r
+    }\r
+    if(!found) return -1;\r
+    if(Book->entry[first_pos].move==MoveNone) return -1;\r
+    for (pos = first_pos; pos < Book->size; pos++) {\r
+        *entry=Book->entry[pos];\r
+        if (entry->key != board->key) break;\r
+        if (entry->count > 0 &&\r
+            entry->move != MoveNone &&\r
+            move_is_legal(entry->move,board)) {\r
+            list_add(list,entry->move,entry->count);\r
+        }\r
+    }\r
+    return first_pos;\r
+}\r
+\r
+// gen_opp_book_moves()\r
+// moves to which opponent has a reply in book\r
+// similar signature as gen_legal_moves\r
+static void gen_opp_book_moves(list_t * list, const board_t * board){\r
+    int move;\r
+    list_t new_list[1], legal_moves[1];\r
+    board_t new_board[1];\r
+    int i;\r
+    list_clear(list);\r
+    gen_legal_moves(legal_moves,board);\r
+    for (i = 0; i < list_size(legal_moves); i++) {\r
+        move = list_move(legal_moves,i);\r
+            // scratch_board\r
+        memcpy(new_board, board, sizeof(board_t));\r
+        move_do(new_board,move);\r
+        gen_book_moves(new_list,new_board); // wasteful in time but tested!\r
+        if(list_size(new_list)!=0){\r
+            list_add(list,move);\r
+        }\r
+    }\r
+}\r
+\r
+static void print_moves(info_t *info){\r
+    board_t board[1];\r
+    char move_string[256];\r
+    int i;\r
+    int color=White;\r
+    if(!info->output){\r
+        return;\r
+    }\r
+    board_start(board);\r
+    for(i=0;i<info->height;i++){\r
+        if(color==White){\r
+            fprintf(info->output,"%d. ",i/2+1);\r
+            color=Black;\r
+        }else{\r
+            color=White;\r
+        }\r
+        move_to_san(info->moves[i],board,move_string,256);\r
+        fprintf(info->output,"%s", move_string);\r
+        if(color==colour_opp(info->initial_color)){\r
+            fprintf(info->output,"{%.0f%%} ",100*info->probs[i]);\r
+        }else{\r
+            fprintf(info->output," ");\r
+        }\r
+        move_do(board,info->moves[i]);\r
+    }\r
+}\r
+\r
+static int search_book(board_t *board, info_t *info, search_t search){\r
+    list_t list[1];\r
+    board_t new_board[1];\r
+    uint16 move;\r
+    int count;\r
+    int ret;\r
+    int i;\r
+    int offset;\r
+    int pos;\r
+    int size;\r
+    int prob_sum;\r
+    double probs[256];\r
+    for(i=0;i<256;i++){\r
+        probs[i]=0.0;  // kill compiler warnings\r
+    }\r
+    for(i=0;i<info->height;i++){\r
+        if(board->key==info->keys[i]){\r
+            if(info->output){\r
+                fprintf(info->output,"%d: ",info->line);\r
+                print_moves(info);\r
+                fprintf(info->output,"{cycle: ply=%d}\n",i);\r
+            }\r
+            info->line++;\r
+            return 1; // end of line because of cycle\r
+        }\r
+    }\r
+    if(!info->book_trans_only || (info->book_trans_only && search==BOOK)){\r
+        info->keys[info->height]=board->key;\r
+        size=Book->size;  // hack\r
+        pos=find_entry(board,MoveNone);\r
+        if(size==Book->size){\r
+            if(info->output){\r
+                fprintf(info->output,"%d: ",info->line);\r
+                print_moves(info);\r
+                fprintf(info->output,"{trans: line=%d, ply=%d}\n",\r
+                        Book->entry[pos].line,\r
+                        Book->entry[pos].height);\r
+            }\r
+            info->line++;\r
+            return 1; // end of line because of transposition\r
+        }else{\r
+            Book->entry[pos].height=info->height;\r
+            Book->entry[pos].line=info->line;\r
+        }\r
+    }\r
+    count=0;\r
+    if(search==BOOK){\r
+        offset=gen_book_moves(list,board);\r
+        if(info->extended_search){\r
+            gen_legal_moves(list,board);\r
+        }\r
+//        ASSERT(offset!=-1);\r
+        if(offset!=-1){ // only false in starting position for black book\r
+            Book->entry[offset].colour=board->turn;\r
+            prob_sum=0;\r
+            if(!info->extended_search){\r
+                for(i=0;i<list_size(list);i++){\r
+                    prob_sum+=uint16(list_value(list,i));\r
+                }\r
+                for(i=0;i<list_size(list);i++){\r
+                    probs[i]=double(uint16(list_value(list,i)))/double(prob_sum);\r
+                }\r
+            }\r
+        }\r
+    }else{\r
+        gen_opp_book_moves(list,board);\r
+    }\r
+    for (i = 0; i < list_size(list); i++) {\r
+        move = list_move(list,i);\r
+        memcpy(new_board, board, sizeof(board_t));\r
+        ASSERT(move_is_legal(move,new_board));\r
+        move_do(new_board,move);\r
+        ASSERT(search!=opp_search(search));\r
+        info->moves[info->height++]=move;\r
+        if(search==BOOK){\r
+            info->probs[info->height-1]=probs[i];\r
+        }\r
+        ret=search_book(new_board, info, opp_search(search));\r
+        if(ret==0 && search==BOOK){\r
+            if(info->output){\r
+                fprintf(info->output,"%d: ",info->line);\r
+                print_moves(info);\r
+                fprintf(info->output,"\n");\r
+            }\r
+            info->line++;\r
+            ret=1; // end of line book move counts for 1\r
+        }\r
+        info->height--;\r
+        ASSERT(info->height>=0);\r
+        count+=ret;\r
+    }\r
+    return count;\r
+}\r
+\r
+void init_info(info_t *info){\r
+    info->line=1;\r
+    info->height=0;\r
+    info->output=NULL;\r
+    info->initial_color=White;\r
+    info->book_trans_only=FALSE;\r
+}\r
+\r
+// book_clean()\r
+// remove MoveNone entries from book and rebuild hash table\r
+void book_clean(){\r
+    int read_ptr,write_ptr;\r
+    write_ptr=0;\r
+    for(read_ptr=0;read_ptr<Book->size;read_ptr++){\r
+        if(Book->entry[read_ptr].move!=MoveNone){\r
+            Book->entry[write_ptr++]=Book->entry[read_ptr];\r
+        }\r
+    }\r
+    Book->size=write_ptr;\r
+    rebuild_hash_table();\r
+}\r
+\r
+// book_dump()\r
+\r
+void book_dump(int argc, char * argv[]) {\r
+    const char * bin_file=NULL;\r
+    const char * txt_file=NULL;\r
+    char string[StringSize];\r
+    int color=ColourNone;\r
+    board_t board[1];\r
+    info_t info[1];\r
+    int i;\r
+    FILE *f;\r
+    my_string_set(&bin_file,"book.bin");\r
+    for (i = 1; i < argc; i++) {\r
+        if (false) {\r
+        } else if (my_string_equal(argv[i],"dump-book")) {\r
+                // skip\r
+        } else if (my_string_equal(argv[i],"-bin")) {\r
+            i++;\r
+            if (i==argc) my_fatal("book_dump(): missing argument\n");\r
+            my_string_set(&bin_file,argv[i]);\r
+        } else if (my_string_equal(argv[i],"-out")) {\r
+            i++;\r
+            if (i==argc) my_fatal("book_dump(): missing argument\n");\r
+            my_string_set(&txt_file,argv[i]);\r
+        } else if (my_string_equal(argv[i],"-color") || my_string_equal(argv[i],"-colour")) {\r
+            i++;\r
+            if (i == argc) my_fatal("book_dump(): missing argument\n");\r
+            if(my_string_equal(argv[i],"white")){\r
+                color=White;\r
+            }else if (my_string_equal(argv[i],"black")){\r
+                color=Black;\r
+            }else{\r
+                my_fatal("book_dump(): unknown color \"%s\"\n",argv[i]);\r
+            }\r
+        } else {\r
+            my_fatal("book_dump(): unknown option \"%s\"\n",argv[i]);\r
+        }\r
+    }\r
+    if(color==ColourNone){\r
+        my_fatal("book_dump(): you must specify a color\n");\r
+    }\r
+    if(txt_file==NULL){\r
+        snprintf(string,StringSize,"book_%s.txt",color?"white":"black");\r
+        my_string_set(&txt_file,string);\r
+    }\r
+\r
+    book_clear();\r
+    if(!Quiet){printf("loading book ...\n");}\r
+    book_load(bin_file);\r
+    board_start(board);\r
+    init_info(info);\r
+    info->initial_color=color;\r
+    if(!(f=fopen(txt_file,"w"))){\r
+        my_fatal("book_dump(): can't open file \"%s\" for writing: %s",\r
+                 txt_file,strerror(errno));\r
+    }\r
+    info->output=f;\r
+    fprintf(info->output,"Dump of \"%s\" for %s.\n",\r
+            bin_file,color==White?"white":"black");\r
+    if(color==White){\r
+        if(!Quiet){printf("generating lines for white...\n");}\r
+        search_book(board,info, BOOK);\r
+    }else{\r
+        if(!Quiet){printf("generating lines for black...\n");}\r
+        search_book(board,info, ALL);\r
+    }\r
+}\r
+\r
+// book_info()\r
+\r
+void book_info(int argc,char* argv[]){\r
+    const char *bin_file=NULL;\r
+    board_t board[1];\r
+    info_t info[1];\r
+    uint64 last_key;\r
+    int pos;\r
+    int white_pos,black_pos,total_pos,white_pos_extended,\r
+        black_pos_extended,white_pos_extended_diff,black_pos_extended_diff;\r
+    int s;\r
+    bool extended_search=FALSE;\r
+    int i;\r
+    Quiet=TRUE;\r
+    my_string_set(&bin_file,"book.bin");\r
+\r
+    for (i = 1; i < argc; i++) {\r
+        if (false) {\r
+        } else if (my_string_equal(argv[i],"info-book")) {\r
+                // skip\r
+        } else if (my_string_equal(argv[i],"-bin")) {\r
+            i++;\r
+            if (i==argc) my_fatal("book_info(): missing argument\n");\r
+            my_string_set(&bin_file,argv[i]);\r
+        } else if (my_string_equal(argv[i],"-exact")) {\r
+            extended_search=TRUE;\r
+        } else {\r
+            my_fatal("book_info(): unknown option \"%s\"\n",argv[i]);\r
+        }\r
+    }\r
+    book_clear();\r
+    if(!Quiet){printf("loading book ...\n");}\r
+    book_load(bin_file);\r
+    s=Book->size;\r
+\r
+    board_start(board);\r
+    init_info(info);\r
+    info->book_trans_only=FALSE;\r
+    info->initial_color=White;\r
+    info->extended_search=FALSE;\r
+    search_book(board,info, BOOK);\r
+    printf("Lines for white                : %8d\n",info->line-1);\r
+\r
+\r
+    info->line=1;\r
+    info->height=0;\r
+    info->initial_color=Black;\r
+    book_clean();\r
+    ASSERT(Book->size==s);\r
+    board_start(board);\r
+    search_book(board,info, ALL);\r
+    printf("Lines for black                : %8d\n",info->line-1);\r
+\r
+    book_clean();\r
+    ASSERT(Book->size==s);\r
+    white_pos=0;\r
+    black_pos=0;\r
+    total_pos=0;\r
+    last_key=0;\r
+    for(pos=0;pos<Book->size;pos++){\r
+        if(Book->entry[pos].key==last_key){\r
+            ASSERT(Book->entry[pos].colour==ColourNone);\r
+            continue;\r
+        }\r
+        last_key=Book->entry[pos].key;\r
+        total_pos++;\r
+        if(Book->entry[pos].colour==White){\r
+            white_pos++;\r
+        }else if(Book->entry[pos].colour==Black){\r
+            black_pos++;\r
+        }\r
+    }\r
+    printf("Positions on lines for white   : %8d\n",white_pos);\r
+    printf("Positions on lines for black   : %8d\n",black_pos);\r
+\r
+    \r
+    if(extended_search){\r
+        init_info(info);\r
+        info->book_trans_only=TRUE;\r
+        info->initial_color=White;\r
+        info->extended_search=TRUE;\r
+        book_clean();\r
+        board_start(board);\r
+        search_book(board,info, BOOK);\r
+\r
+        init_info(info);\r
+        info->book_trans_only=TRUE;\r
+        info->initial_color=Black;\r
+        info->extended_search=TRUE;\r
+        book_clean();\r
+        board_start(board);\r
+        search_book(board,info, ALL);\r
+        book_clean();\r
+        ASSERT(Book->size==s);\r
+        white_pos_extended=0;\r
+        black_pos_extended=0;\r
+        last_key=0;\r
+        for(pos=0;pos<Book->size;pos++){\r
+            if(Book->entry[pos].key==last_key){\r
+                ASSERT(Book->entry[pos].colour==ColourNone);\r
+                continue;\r
+            }\r
+            last_key=Book->entry[pos].key;\r
+            if(Book->entry[pos].colour==White){\r
+                white_pos_extended++;\r
+            }else if(Book->entry[pos].colour==Black){\r
+                black_pos_extended++;\r
+            }\r
+        }\r
+        white_pos_extended_diff=white_pos_extended-white_pos;\r
+        black_pos_extended_diff=black_pos_extended-black_pos;\r
+        printf("Unreachable white positions(?) : %8d\n",\r
+               white_pos_extended_diff);\r
+        printf("Unreachable black positions(?) : %8d\n",\r
+               black_pos_extended_diff);\r
+\r
+    }\r
+    if(extended_search){\r
+        printf("Isolated positions             : %8d\n",\r
+               total_pos-white_pos_extended-black_pos_extended);\r
+    }else{\r
+        printf("Isolated positions             : %8d\n",\r
+               total_pos-white_pos-black_pos);\r
+    }\r
+}\r
+\r
+\r
+\r
 // end of book_make.cpp\r
 \r