12 #include "book_make.h"
\r
14 #include "move_do.h"
\r
15 #include "move_gen.h"
\r
16 #include "move_legal.h"
\r
23 static const int COUNT_MAX = 16384;
\r
24 static const int StringSize = 4096;
\r
26 static const int NIL = -1;
\r
30 #define opp_search(s) ((s)==BOOK?ALL:BOOK)
\r
38 // Unfortunately the minggw32 cross compiler [4.2.1-sjlj (mingw32-2)]
\r
39 // seems to have a bug with anon structs contained in unions when using -O2.
\r
40 // See the ASSERT below in "read_entry_file"...
\r
41 // To be fair this seems to be illegal in C++
\r
42 // although it is hard to understand why, and the compiler does not complain
\r
74 bool book_trans_only;
\r
75 bool extended_search;
\r
87 static double MinScore;
\r
88 static bool RemoveWhite, RemoveBlack;
\r
89 static bool Uniform;
\r
90 static bool Quiet=FALSE;
\r
92 static book_t Book[1];
\r
96 static void book_clear ();
\r
97 static void book_insert (const char file_name[]);
\r
98 static void book_filter ();
\r
99 static void book_sort ();
\r
100 static void book_save (const char file_name[]);
\r
102 static int find_entry (const board_t * board, int move);
\r
103 static void resize ();
\r
104 static void halve_stats (uint64 key);
\r
106 static bool keep_entry (int pos);
\r
108 static int entry_score (const entry_t * entry);
\r
110 static int key_compare (const void * p1, const void * p2);
\r
112 static void write_integer (FILE * file, int size, uint64 n);
\r
113 static uint64 read_integer(FILE * file, int size);
\r
115 static void read_entry_file(FILE *f, entry_t *entry);
\r
116 static void write_entry_file(FILE * f, const entry_t * entry);
\r
122 void book_make(int argc, char * argv[]) {
\r
125 const char * pgn_file;
\r
126 const char * bin_file;
\r
129 my_string_set(&pgn_file,"book.pgn");
\r
132 my_string_set(&bin_file,"book.bin");
\r
137 RemoveWhite = FALSE;
\r
138 RemoveBlack = FALSE;
\r
141 for (i = 1; i < argc; i++) {
\r
145 } else if (my_string_equal(argv[i],"make-book")) {
\r
149 } else if (my_string_equal(argv[i],"-pgn")) {
\r
152 if (argv[i] == NULL) my_fatal("book_make(): missing argument\n");
\r
154 my_string_set(&pgn_file,argv[i]);
\r
156 } else if (my_string_equal(argv[i],"-bin")) {
\r
159 if (argv[i] == NULL) my_fatal("book_make(): missing argument\n");
\r
161 my_string_set(&bin_file,argv[i]);
\r
163 } else if (my_string_equal(argv[i],"-max-ply")) {
\r
166 if (argv[i] == NULL) my_fatal("book_make(): missing argument\n");
\r
168 MaxPly = atoi(argv[i]);
\r
171 } else if (my_string_equal(argv[i],"-min-game")) {
\r
174 if (argv[i] == NULL) my_fatal("book_make(): missing argument\n");
\r
176 MinGame = atoi(argv[i]);
\r
179 } else if (my_string_equal(argv[i],"-min-score")) {
\r
182 if (argv[i] == NULL) my_fatal("book_make(): missing argument\n");
\r
184 MinScore = atof(argv[i]) / 100.0;
\r
185 ASSERT(MinScore>=0.0&&MinScore<=1.0);
\r
187 } else if (my_string_equal(argv[i],"-only-white")) {
\r
189 RemoveWhite = FALSE;
\r
190 RemoveBlack = TRUE;
\r
192 } else if (my_string_equal(argv[i],"-only-black")) {
\r
194 RemoveWhite = TRUE;
\r
195 RemoveBlack = FALSE;
\r
197 } else if (my_string_equal(argv[i],"-uniform")) {
\r
203 my_fatal("book_make(): unknown option \"%s\"\n",argv[i]);
\r
209 printf("inserting games ...\n");
\r
210 book_insert(pgn_file);
\r
212 printf("filtering entries ...\n");
\r
215 printf("sorting entries ...\n");
\r
218 printf("saving entries ...\n");
\r
219 book_save(bin_file);
\r
221 printf("all done!\n");
\r
226 static void book_clear() {
\r
231 Book->mask = (Book->alloc * 2) - 1;
\r
233 Book->entry = (entry_t *) my_malloc(Book->alloc*sizeof(entry_t));
\r
236 Book->hash = (sint32 *) my_malloc((Book->alloc*2)*sizeof(sint32));
\r
237 for (index = 0; index < Book->alloc*2; index++) {
\r
238 Book->hash[index] = NIL;
\r
244 static void book_insert(const char file_name[]) {
\r
254 ASSERT(file_name!=NULL);
\r
261 pgn_open(pgn,file_name);
\r
263 while (pgn_next_game(pgn)) {
\r
265 board_start(board);
\r
270 } else if (my_string_equal(pgn->result,"1-0")) {
\r
272 } else if (my_string_equal(pgn->result,"0-1")) {
\r
276 while (pgn_next_move(pgn,string,256)) {
\r
278 if (ply < MaxPly) {
\r
280 move = move_from_san(string,board);
\r
282 if (move == MoveNone || !move_is_legal(move,board)) {
\r
283 my_fatal("book_insert(): illegal move \"%s\" at line %d, column %d,game %d\n",string,pgn->move_line,pgn->move_column,pgn->game_nb);
\r
286 pos = find_entry(board,move);
\r
288 Book->entry[pos].n++;
\r
289 Book->entry[pos].sum += result+1;
\r
291 if (Book->entry[pos].n >= COUNT_MAX) {
\r
292 halve_stats(board->key);
\r
295 move_do(board,move);
\r
301 if (pgn->game_nb % 10000 == 0) printf("%d games ...\n",pgn->game_nb);
\r
306 printf("%d game%s.\n",pgn->game_nb,(pgn->game_nb>2)?"s":"");
\r
307 printf("%d entries.\n",Book->size);
\r
314 static void book_filter() {
\r
322 for (src = 0; src < Book->size; src++) {
\r
323 if (keep_entry(src)) Book->entry[dst++] = Book->entry[src];
\r
326 ASSERT(dst>=0&&dst<=Book->size);
\r
329 printf("%d entries.\n",Book->size);
\r
334 static void book_sort() {
\r
336 // sort keys for binary search
\r
338 qsort(Book->entry,Book->size,sizeof(entry_t),&key_compare);
\r
343 static void book_save(const char file_name[]) {
\r
348 ASSERT(file_name!=NULL);
\r
350 file = fopen(file_name,"wb");
\r
351 if (file == NULL) my_fatal("book_save(): can't open file \"%s\" for writing: %s\n",file_name,strerror(errno));
\r
355 for (pos = 0; pos < Book->size; pos++) {
\r
357 ASSERT(keep_entry(pos));
\r
359 write_integer(file,8,Book->entry[pos].key);
\r
360 write_integer(file,2,Book->entry[pos].move);
\r
361 write_integer(file,2,entry_score(&Book->entry[pos]));
\r
362 write_integer(file,2,0);
\r
363 write_integer(file,2,0);
\r
371 static int find_entry(const board_t * board, int move) {
\r
377 ASSERT(board!=NULL);
\r
378 ASSERT(move==MoveNone || move_is_ok(move));
\r
380 ASSERT(move==MoveNone || move_is_legal(move,board));
\r
388 for (index = key & (uint64) Book->mask; (pos=Book->hash[index]) != NIL; index = (index+1) & Book->mask) {
\r
390 ASSERT(pos>=0&&pos<Book->size);
\r
392 if (Book->entry[pos].key == key && Book->entry[pos].move == move) {
\r
393 return pos; // found
\r
399 ASSERT(Book->size<=Book->alloc);
\r
401 if (Book->size == Book->alloc) {
\r
403 // allocate more memory
\r
407 for (index = key & (uint64) Book->mask; Book->hash[index] != NIL; index = (index+1) & Book->mask)
\r
411 // create a new entry
\r
413 ASSERT(Book->size<Book->alloc);
\r
414 pos = Book->size++;
\r
416 Book->entry[pos].key = key;
\r
417 Book->entry[pos].move = move;
\r
418 Book->entry[pos].n = 0;
\r
419 Book->entry[pos].sum = 0;
\r
420 Book->entry[pos].colour = board->turn;
\r
422 // insert into the hash table
\r
424 ASSERT(index>=0&&index<Book->alloc*2);
\r
425 ASSERT(Book->hash[index]==NIL);
\r
426 Book->hash[index] = pos;
\r
428 ASSERT(pos>=0&&pos<Book->size);
\r
433 // rebuild_hash_table
\r
435 static void rebuild_hash_table(){
\r
437 for (index = 0; index < Book->alloc*2; index++) {
\r
438 Book->hash[index] = NIL;
\r
440 for (pos = 0; pos < Book->size; pos++) {
\r
441 for (index = Book->entry[pos].key & (uint64) Book->mask; Book->hash[index] != NIL; index = (index+1) & Book->mask)
\r
443 ASSERT(index>=0&&index<Book->alloc*2);
\r
444 Book->hash[index] = pos;
\r
448 static void resize() {
\r
452 ASSERT(Book->size==Book->alloc);
\r
455 Book->mask = (Book->alloc * 2) - 1;
\r
458 size += Book->alloc * sizeof(entry_t);
\r
459 size += (Book->alloc*2) * sizeof(sint32);
\r
461 if (size >= 1048576) if(!Quiet){
\r
462 printf("allocating %gMB ...\n",((double)size)/1048576.0);
\r
467 Book->entry = (entry_t *) my_realloc(Book->entry,Book->alloc*sizeof(entry_t));
\r
468 Book->hash = (sint32 *) my_realloc(Book->hash,(Book->alloc*2)*sizeof(sint32));
\r
470 // rebuild hash table
\r
472 rebuild_hash_table();
\r
478 static void halve_stats(uint64 key) {
\r
485 for (index = key & (uint64) Book->mask; (pos=Book->hash[index]) != NIL; index = (index+1) & Book->mask) {
\r
487 ASSERT(pos>=0&&pos<Book->size);
\r
489 if (Book->entry[pos].key == key) {
\r
490 Book->entry[pos].n = (Book->entry[pos].n + 1) / 2;
\r
491 Book->entry[pos].sum = (Book->entry[pos].sum + 1) / 2;
\r
498 static bool keep_entry(int pos) {
\r
500 const entry_t * entry;
\r
504 ASSERT(pos>=0&&pos<Book->size);
\r
506 entry = &Book->entry[pos];
\r
508 // if (entry->n == 0) return FALSE;
\r
509 if (entry->n < MinGame) return FALSE;
\r
511 if (entry->sum == 0) return FALSE;
\r
513 score = (((double)entry->sum) / ((double)entry->n)) / 2.0;
\r
514 ASSERT(score>=0.0&&score<=1.0);
\r
516 if (score < MinScore) return FALSE;
\r
518 colour = entry->colour;
\r
520 if ((RemoveWhite && colour_is_white(colour))
\r
521 || (RemoveBlack && colour_is_black(colour))) {
\r
525 if (entry_score(entry) == 0) return FALSE; // REMOVE ME?
\r
532 static int entry_score(const entry_t * entry) {
\r
536 ASSERT(entry!=NULL);
\r
538 // score = entry->n; // popularity
\r
539 score = entry->sum; // "expectancy"
\r
541 if (Uniform) score = 1;
\r
550 static int key_compare(const void * p1, const void * p2) {
\r
552 const entry_t * entry_1, * entry_2;
\r
557 entry_1 = (const entry_t *) p1;
\r
558 entry_2 = (const entry_t *) p2;
\r
560 if (entry_1->key > entry_2->key) {
\r
562 } else if (entry_1->key < entry_2->key) {
\r
565 return entry_score(entry_2) - entry_score(entry_1); // highest score first
\r
571 static void write_integer(FILE * file, int size, uint64 n) {
\r
576 ASSERT(file!=NULL);
\r
577 ASSERT(size>0&&size<=8);
\r
578 ASSERT(size==8||n>>(size*8)==0);
\r
580 for (i = size-1; i >= 0; i--) {
\r
581 b = (n >> (i*8)) & 0xFF;
\r
582 ASSERT(b>=0&&b<256);
\r
589 static uint64 read_integer(FILE * file, int size) {
\r
593 ASSERT(file!=NULL);
\r
594 ASSERT(size>0&&size<=8);
\r
596 for (i = 0; i < size; i++) {
\r
600 my_fatal("read_integer(): fgetc(): EOF reached\n");
\r
602 my_fatal("read_integer(): fgetc(): %s\n",strerror(errno));
\r
605 ASSERT(b>=0&&b<256);
\r
613 static void read_entry_file(FILE *f, entry_t *entry){
\r
615 ASSERT(entry!=NULL);
\r
616 n = entry->key = read_integer(f,8);
\r
617 entry->move = read_integer(f,2);
\r
618 entry->count = read_integer(f,2);
\r
619 entry->n = read_integer(f,2);
\r
620 entry->sum = read_integer(f,2);
\r
621 ASSERT(n==entry->key); // test for mingw compiler bug with anon structs
\r
624 // write_entry_file
\r
626 static void write_entry_file(FILE * f, const entry_t * entry) {
\r
627 ASSERT(entry!=NULL);
\r
628 write_integer(f,8,entry->key);
\r
629 write_integer(f,2,entry->move);
\r
630 write_integer(f,2,entry->count);
\r
631 write_integer(f,2,entry->n);
\r
632 write_integer(f,2,entry->sum);
\r
635 static void print_list(const board_t *board, list_t *list){
\r
638 char move_string[256];
\r
639 for (i = 0; i < list_size(list); i++) {
\r
640 move = list_move(list,i);
\r
641 move_to_san(move,board,move_string,256);
\r
642 printf("%s",move_string);
\r
648 // loads a polyglot book
\r
650 static void book_load(const char filename[]){
\r
657 ASSERT(filename!=NULL);
\r
658 if(!(f=fopen(filename,"rb"))){
\r
659 my_fatal("book_load() : can't open file \"%s\" for reading: %s\n",filename,strerror(errno));
\r
661 fseek(f,0L,SEEK_END); // superportable way to get size of book!
\r
663 fseek(f,0,SEEK_SET);
\r
664 for(i=0L;i<size;i++){
\r
665 read_entry_file(f,entry);
\r
666 ASSERT(Book->size<=Book->alloc);
\r
667 if (Book->size == Book->alloc) {
\r
668 // allocate more memoryx
\r
671 // insert into the book
\r
672 pos = Book->size++;
\r
673 Book->entry[pos].key = entry->key;
\r
674 ASSERT(entry->move!=MoveNone);
\r
675 Book->entry[pos].move = entry->move;
\r
676 Book->entry[pos].count = entry->count;
\r
677 Book->entry[pos].n = entry->n;
\r
678 Book->entry[pos].sum = entry->sum;
\r
679 Book->entry[pos].colour = ColourNone;
\r
680 // find free hash table spot
\r
681 for (index = entry->key & (uint64) Book->mask;
\r
682 Book->hash[index] != NIL;
\r
683 index = (index+1) & Book->mask);
\r
684 // insert into the hash table
\r
685 ASSERT(index>=0&&index<Book->alloc*2);
\r
686 ASSERT(Book->hash[index]==NIL);
\r
687 Book->hash[index] = pos;
\r
688 ASSERT(pos>=0&&pos<Book->size);
\r
693 // gen_book_moves()
\r
694 // similar signature as gen_legal_moves
\r
695 static int gen_book_moves(list_t * list, const board_t * board){
\r
696 int first_pos, pos, index;
\r
701 for (index = board->key & (uint64) Book->mask; (first_pos=Book->hash[index]) != NIL; index = (index+1) & Book->mask) {
\r
702 ASSERT(first_pos>=0&&first_pos<Book->size);
\r
703 if (Book->entry[first_pos].key == board->key) {
\r
708 if(!found) return -1;
\r
709 if(Book->entry[first_pos].move==MoveNone) return -1;
\r
710 for (pos = first_pos; pos < Book->size; pos++) {
\r
711 *entry=Book->entry[pos];
\r
712 if (entry->key != board->key) break;
\r
713 if (entry->count > 0 &&
\r
714 entry->move != MoveNone &&
\r
715 move_is_legal(entry->move,board)) {
\r
716 list_add_ex(list,entry->move,entry->count);
\r
722 // gen_opp_book_moves()
\r
723 // moves to which opponent has a reply in book
\r
724 // similar signature as gen_legal_moves
\r
725 static void gen_opp_book_moves(list_t * list, const board_t * board){
\r
727 list_t new_list[1], legal_moves[1];
\r
728 board_t new_board[1];
\r
731 gen_legal_moves(legal_moves,board);
\r
732 for (i = 0; i < list_size(legal_moves); i++) {
\r
733 move = list_move(legal_moves,i);
\r
735 memcpy(new_board, board, sizeof(board_t));
\r
736 move_do(new_board,move);
\r
737 gen_book_moves(new_list,new_board); // wasteful in time but tested!
\r
738 if(list_size(new_list)!=0){
\r
739 list_add(list,move);
\r
744 static void print_moves(info_t *info){
\r
746 char move_string[256];
\r
752 board_start(board);
\r
753 for(i=0;i<info->height;i++){
\r
755 fprintf(info->output,"%d. ",i/2+1);
\r
760 move_to_san(info->moves[i],board,move_string,256);
\r
761 fprintf(info->output,"%s", move_string);
\r
762 if(color==colour_opp(info->initial_color)){
\r
763 fprintf(info->output,"{%.0f%%} ",100*info->probs[i]);
\r
765 fprintf(info->output," ");
\r
767 move_do(board,info->moves[i]);
\r
771 static int search_book(board_t *board, info_t *info, search_t search){
\r
773 board_t new_board[1];
\r
783 for(i=0;i<256;i++){
\r
784 probs[i]=0.0; // kill compiler warnings
\r
786 for(i=0;i<info->height;i++){
\r
787 if(board->key==info->keys[i]){
\r
789 fprintf(info->output,"%d: ",info->line);
\r
791 fprintf(info->output,"{cycle: ply=%d}\n",i);
\r
794 return 1; // end of line because of cycle
\r
797 if(!info->book_trans_only || (info->book_trans_only && search==BOOK)){
\r
798 info->keys[info->height]=board->key;
\r
799 size=Book->size; // hack
\r
800 pos=find_entry(board,MoveNone);
\r
801 if(size==Book->size){
\r
803 fprintf(info->output,"%d: ",info->line);
\r
805 fprintf(info->output,"{trans: line=%d, ply=%d}\n",
\r
806 Book->entry[pos].line,
\r
807 Book->entry[pos].height);
\r
810 return 1; // end of line because of transposition
\r
812 Book->entry[pos].height=info->height;
\r
813 Book->entry[pos].line=info->line;
\r
818 offset=gen_book_moves(list,board);
\r
819 if(info->extended_search){
\r
820 gen_legal_moves(list,board);
\r
822 // ASSERT(offset!=-1);
\r
823 if(offset!=-1){ // only FALSE in starting position for black book
\r
824 Book->entry[offset].colour=board->turn;
\r
826 if(!info->extended_search){
\r
827 for(i=0;i<list_size(list);i++){
\r
828 prob_sum+=((uint16)list_value(list,i));
\r
830 for(i=0;i<list_size(list);i++){
\r
831 probs[i]=((double)((uint16)list_value(list,i)))/((double)prob_sum);
\r
836 gen_opp_book_moves(list,board);
\r
838 for (i = 0; i < list_size(list); i++) {
\r
839 move = list_move(list,i);
\r
840 memcpy(new_board, board, sizeof(board_t));
\r
841 ASSERT(move_is_legal(move,new_board));
\r
842 move_do(new_board,move);
\r
843 ASSERT(search!=opp_search(search));
\r
844 info->moves[info->height++]=move;
\r
846 info->probs[info->height-1]=probs[i];
\r
848 ret=search_book(new_board, info, opp_search(search));
\r
849 if(ret==0 && search==BOOK){
\r
851 fprintf(info->output,"%d: ",info->line);
\r
853 fprintf(info->output,"\n");
\r
856 ret=1; // end of line book move counts for 1
\r
859 ASSERT(info->height>=0);
\r
865 void init_info(info_t *info){
\r
869 info->initial_color=White;
\r
870 info->book_trans_only=FALSE;
\r
874 // remove MoveNone entries from book and rebuild hash table
\r
876 int read_ptr,write_ptr;
\r
878 for(read_ptr=0;read_ptr<Book->size;read_ptr++){
\r
879 if(Book->entry[read_ptr].move!=MoveNone){
\r
880 Book->entry[write_ptr++]=Book->entry[read_ptr];
\r
883 Book->size=write_ptr;
\r
884 rebuild_hash_table();
\r
889 void book_dump(int argc, char * argv[]) {
\r
890 const char * bin_file=NULL;
\r
891 const char * txt_file=NULL;
\r
892 char string[StringSize];
\r
893 int color=ColourNone;
\r
898 my_string_set(&bin_file,"book.bin");
\r
899 for (i = 1; i < argc; i++) {
\r
901 } else if (my_string_equal(argv[i],"dump-book")) {
\r
903 } else if (my_string_equal(argv[i],"-bin")) {
\r
905 if (i==argc) my_fatal("book_dump(): missing argument\n");
\r
906 my_string_set(&bin_file,argv[i]);
\r
907 } else if (my_string_equal(argv[i],"-out")) {
\r
909 if (i==argc) my_fatal("book_dump(): missing argument\n");
\r
910 my_string_set(&txt_file,argv[i]);
\r
911 } else if (my_string_equal(argv[i],"-color") || my_string_equal(argv[i],"-colour")) {
\r
913 if (i == argc) my_fatal("book_dump(): missing argument\n");
\r
914 if(my_string_equal(argv[i],"white")){
\r
916 }else if (my_string_equal(argv[i],"black")){
\r
919 my_fatal("book_dump(): unknown color \"%s\"\n",argv[i]);
\r
922 my_fatal("book_dump(): unknown option \"%s\"\n",argv[i]);
\r
925 if(color==ColourNone){
\r
926 my_fatal("book_dump(): you must specify a color\n");
\r
928 if(txt_file==NULL){
\r
929 snprintf(string,StringSize,"book_%s.txt",color?"white":"black");
\r
930 my_string_set(&txt_file,string);
\r
934 if(!Quiet){printf("loading book ...\n");}
\r
935 book_load(bin_file);
\r
936 board_start(board);
\r
938 info->initial_color=color;
\r
939 if(!(f=fopen(txt_file,"w"))){
\r
940 my_fatal("book_dump(): can't open file \"%s\" for writing: %s",
\r
941 txt_file,strerror(errno));
\r
944 fprintf(info->output,"Dump of \"%s\" for %s.\n",
\r
945 bin_file,color==White?"white":"black");
\r
947 if(!Quiet){printf("generating lines for white...\n");}
\r
948 search_book(board,info, BOOK);
\r
950 if(!Quiet){printf("generating lines for black...\n");}
\r
951 search_book(board,info, ALL);
\r
957 void book_info(int argc,char* argv[]){
\r
958 const char *bin_file=NULL;
\r
963 int white_pos,black_pos,total_pos,white_pos_extended,
\r
964 black_pos_extended,white_pos_extended_diff,black_pos_extended_diff;
\r
966 bool extended_search=FALSE;
\r
969 my_string_set(&bin_file,"book.bin");
\r
971 for (i = 1; i < argc; i++) {
\r
973 } else if (my_string_equal(argv[i],"info-book")) {
\r
975 } else if (my_string_equal(argv[i],"-bin")) {
\r
977 if (i==argc) my_fatal("book_info(): missing argument\n");
\r
978 my_string_set(&bin_file,argv[i]);
\r
979 } else if (my_string_equal(argv[i],"-exact")) {
\r
980 extended_search=TRUE;
\r
982 my_fatal("book_info(): unknown option \"%s\"\n",argv[i]);
\r
986 if(!Quiet){printf("loading book ...\n");}
\r
987 book_load(bin_file);
\r
990 board_start(board);
\r
992 info->book_trans_only=FALSE;
\r
993 info->initial_color=White;
\r
994 info->extended_search=FALSE;
\r
995 search_book(board,info, BOOK);
\r
996 printf("Lines for white : %8d\n",info->line-1);
\r
1001 info->initial_color=Black;
\r
1003 ASSERT(Book->size==s);
\r
1004 board_start(board);
\r
1005 search_book(board,info, ALL);
\r
1006 printf("Lines for black : %8d\n",info->line-1);
\r
1009 ASSERT(Book->size==s);
\r
1014 for(pos=0;pos<Book->size;pos++){
\r
1015 if(Book->entry[pos].key==last_key){
\r
1016 ASSERT(Book->entry[pos].colour==ColourNone);
\r
1019 last_key=Book->entry[pos].key;
\r
1021 if(Book->entry[pos].colour==White){
\r
1023 }else if(Book->entry[pos].colour==Black){
\r
1027 printf("Positions on lines for white : %8d\n",white_pos);
\r
1028 printf("Positions on lines for black : %8d\n",black_pos);
\r
1031 if(extended_search){
\r
1033 info->book_trans_only=TRUE;
\r
1034 info->initial_color=White;
\r
1035 info->extended_search=TRUE;
\r
1037 board_start(board);
\r
1038 search_book(board,info, BOOK);
\r
1041 info->book_trans_only=TRUE;
\r
1042 info->initial_color=Black;
\r
1043 info->extended_search=TRUE;
\r
1045 board_start(board);
\r
1046 search_book(board,info, ALL);
\r
1048 ASSERT(Book->size==s);
\r
1049 white_pos_extended=0;
\r
1050 black_pos_extended=0;
\r
1052 for(pos=0;pos<Book->size;pos++){
\r
1053 if(Book->entry[pos].key==last_key){
\r
1054 ASSERT(Book->entry[pos].colour==ColourNone);
\r
1057 last_key=Book->entry[pos].key;
\r
1058 if(Book->entry[pos].colour==White){
\r
1059 white_pos_extended++;
\r
1060 }else if(Book->entry[pos].colour==Black){
\r
1061 black_pos_extended++;
\r
1064 white_pos_extended_diff=white_pos_extended-white_pos;
\r
1065 black_pos_extended_diff=black_pos_extended-black_pos;
\r
1066 printf("Unreachable white positions(?) : %8d\n",
\r
1067 white_pos_extended_diff);
\r
1068 printf("Unreachable black positions(?) : %8d\n",
\r
1069 black_pos_extended_diff);
\r
1072 if(extended_search){
\r
1073 printf("Isolated positions : %8d\n",
\r
1074 total_pos-white_pos_extended-black_pos_extended);
\r
1076 printf("Isolated positions : %8d\n",
\r
1077 total_pos-white_pos-black_pos);
\r
1083 // end of book_make.cpp
\r