Merge commit 'v4.3.16'
[xboard.git] / pg_show.c
1 /* 
2  * This utility looks up the moves and their scores in a Polyglot book
3  *
4  * Usage:
5  * pg_show <book> <hex key>"
6  *
7  * You can find the hex key of a FEN using pg_key. 
8  *
9  * This code is released in the public domain by Michel Van den Bergh.
10  *
11  */
12
13
14 #include <stdio.h>
15 #include <string.h>
16
17 typedef unsigned char uint8;
18 typedef unsigned short uint16;
19 typedef unsigned int uint32;
20
21 #ifdef _MSC_VER
22   typedef unsigned __int64 uint64;
23 #else
24   typedef unsigned long long int uint64;
25 #endif
26
27 typedef struct {
28     uint64 key; 
29     uint16 move;
30     uint16 weight;
31     uint32 learn;
32 } entry_t;
33
34 entry_t entry_none = {
35     0, 0, 0, 0
36 };
37
38 char *promote_pieces=" nbrq";
39
40 #define MAX_MOVES 100
41
42 int int_from_file(FILE *f, int l, uint64 *r){
43     int i,c;
44     for(i=0;i<l;i++){
45         c=fgetc(f);
46         if(c==EOF){
47             return 1;
48         }
49         (*r)=((*r)<<8)+c;
50     }
51     return 0;
52 }
53
54 int entry_from_file(FILE *f, entry_t *entry){
55     int ret;
56     uint64 r;
57     ret=int_from_file(f,8,&r);
58     if(ret) return 1;
59     entry->key=r;
60     ret=int_from_file(f,2,&r);
61     if(ret) return 1;
62     entry->move=r;
63     ret=int_from_file(f,2,&r);
64     if(ret) return 1;
65     entry->weight=r;
66     ret=int_from_file(f,4,&r);
67     if(ret) return 1;
68     entry->learn=r;
69     return 0;
70 }
71
72 int find_key(FILE *f, uint64 key, entry_t *entry){
73     int first, last, middle;
74     entry_t first_entry=entry_none, last_entry,middle_entry;
75     first=-1;
76     if(fseek(f,-16,SEEK_END)){
77         *entry=entry_none;
78         entry->key=key+1; //hack
79         return -1;
80     }
81     last=ftell(f)/16;
82     entry_from_file(f,&last_entry);
83     while(1){
84         if(last-first==1){
85             *entry=last_entry;
86             return last;
87         }
88         middle=(first+last)/2;
89         fseek(f,16*middle,SEEK_SET);
90         entry_from_file(f,&middle_entry);
91         if(key<=middle_entry.key){
92             last=middle;
93             last_entry=middle_entry;
94         }else{
95             first=middle;
96             first_entry=middle_entry;
97         }
98     }
99 }
100
101 void move_to_string(char move_s[6], uint16 move){
102     int f,fr,ff,t,tr,tf,p;
103     f=(move>>6)&077;
104     fr=(f>>3)&0x7;
105     ff=f&0x7;
106     t=move&077;
107     tr=(t>>3)&0x7;
108     tf=t&0x7;
109     p=(move>>12)&0x7;
110     move_s[0]=ff+'a';
111     move_s[1]=fr+'1';
112     move_s[2]=tf+'a';
113     move_s[3]=tr+'1';
114     if(p){
115         move_s[4]=promote_pieces[p];
116         move_s[5]='\0';
117     }else{
118         move_s[4]='\0';
119     }
120     if(!strcmp(move_s,"e1h1")){
121         strcpy(move_s,"e1g1");
122     }else  if(!strcmp(move_s,"e1a1")){
123         strcpy(move_s,"e1c1");
124     }else  if(!strcmp(move_s,"e8h8")){
125         strcpy(move_s,"e8g8");
126     }else  if(!strcmp(move_s,"e8a8")){
127         strcpy(move_s,"e8c8");
128     }
129 }
130
131 int main(int argc, char *argv[]){
132     FILE *f;
133     entry_t entry;
134     int offset;
135     char *file_name;
136     uint64 key;
137     entry_t entries[MAX_MOVES];
138     int count=0;
139     int ret, i;
140     char move_s[6];
141     int total_weight;
142     if(argc<=2){
143         printf("Usage: pg_show <book> <hex key>\n");
144         return 1;
145     }
146     file_name=argv[1];
147 #ifdef _MSC_VER
148     sscanf(argv[2],"%16I64x",&key);
149 #else
150     sscanf(argv[2],"%16llx",&key);
151 #endif
152     f=fopen(file_name,"rb");
153     if(!f){
154         perror(file_name);
155         return 1;
156     }
157     offset=find_key(f,key,&entry);
158     if(entry.key!=key){
159 #ifdef _MSC_VER
160         printf("%016I64x: No such key\n",key);
161 #else
162         printf("%016llx: No such key\n",key);
163 #endif        
164         return 1;
165     }
166     entries[0]=entry;
167     count=1;
168     fseek(f,16*(offset+1),SEEK_SET);
169     while(1){
170         ret=entry_from_file(f,&entry);
171         if(ret){
172             break;
173         }
174         if(entry.key!=key){
175             break;
176         }
177         if(count==MAX_MOVES){
178             printf("Too many moves in this position (max=%d)\n",MAX_MOVES);
179             return 1;
180         }
181         entries[count++]=entry;
182     }
183     total_weight=0;
184     for(i=0;i<count;i++){
185         total_weight+=entries[i].weight;
186     }
187     for(i=0;i<count;i++){
188         move_to_string(move_s,entries[i].move);
189         printf("move=%s weight=%5.2f%%\n",
190                 move_s,
191                100*((double) entries[i].weight/ (double) total_weight));
192     }
193     return 0;
194 }