]> git.sesse.net Git - remoteglot/blob - booklook.c
Add book lookups.
[remoteglot] / booklook.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <ctype.h>
5 #include <fcntl.h>
6
7 int cto_fd, ctg_fd, ctb_fd;
8
9 unsigned int tbl2[] = {
10         0x3100d2bf, 0x3118e3de, 0x34ab1372, 0x2807a847,
11         0x1633f566, 0x2143b359, 0x26d56488, 0x3b9e6f59,
12         0x37755656, 0x3089ca7b, 0x18e92d85, 0x0cd0e9d8,
13         0x1a9e3b54, 0x3eaa902f, 0x0d9bfaae, 0x2f32b45b,
14         0x31ed6102, 0x3d3c8398, 0x146660e3, 0x0f8d4b76,
15         0x02c77a5f, 0x146c8799, 0x1c47f51f, 0x249f8f36,
16         0x24772043, 0x1fbc1e4d, 0x1e86b3fa, 0x37df36a6,
17         0x16ed30e4, 0x02c3148e, 0x216e5929, 0x0636b34e,
18         0x317f9f56, 0x15f09d70, 0x131026fb, 0x38c784b1,
19         0x29ac3305, 0x2b485dc5, 0x3c049ddc, 0x35a9fbcd,
20         0x31d5373b, 0x2b246799, 0x0a2923d3, 0x08a96e9d,
21         0x30031a9f, 0x08f525b5, 0x33611c06, 0x2409db98,
22         0x0ca4feb2, 0x1000b71e, 0x30566e32, 0x39447d31,
23         0x194e3752, 0x08233a95, 0x0f38fe36, 0x29c7cd57,
24         0x0f7b3a39, 0x328e8a16, 0x1e7d1388, 0x0fba78f5,
25         0x274c7e7c, 0x1e8be65c, 0x2fa0b0bb, 0x1eb6c371
26 };
27
28 signed char data[] = {
29         0x36, 0xb6, 0x0f, 0x79, 0x61, 0x1f, 0x50, 0xde, 0x61, 0xb9, 0x52, 0x24, 0xb3, 0xac, 0x6e, 0x5e, 0x0a, 0x69, 0xbd, 0x61, 0x61, 0xc5
30 };
31
32 void output_stats(char *result, int invert)
33 {
34         unsigned char *ptr = result;
35         ptr += *ptr;
36         ptr += 3;
37
38         // wins-draw-loss
39         if (invert) {
40                 printf("%u,", (ptr[0] << 16) | (ptr[1] << 8) | ptr[2]);
41                 printf("%u,", (ptr[6] << 16) | (ptr[7] << 8) | ptr[8]);
42                 printf("%u,", (ptr[3] << 16) | (ptr[4] << 8) | ptr[5]);
43         } else {
44                 printf("%u,", (ptr[3] << 16) | (ptr[4] << 8) | ptr[5]);
45                 printf("%u,", (ptr[6] << 16) | (ptr[7] << 8) | ptr[8]);
46                 printf("%u,", (ptr[0] << 16) | (ptr[1] << 8) | ptr[2]);
47         }
48
49         ptr += 9;
50         ptr += 4;
51         ptr += 7;
52
53         // rating
54         {
55                 int rat2_sum, rat2_div;
56                 rat2_div = (ptr[0] << 16) | (ptr[1] << 8) | ptr[2];
57                 rat2_sum = (ptr[3] << 24) | (ptr[4] << 16) | (ptr[5] << 8) | ptr[6];
58
59                 if (rat2_div == 0) {
60                         printf(",0");
61                 } else {
62                         printf("%u,%u", rat2_sum / rat2_div, rat2_div);
63                 }
64         }
65                 
66         printf("\n");
67 }
68
69 unsigned int gen_hash(signed char *ptr, unsigned len)
70 {
71         signed hash = 0;
72         short tmp = 0;
73         int i;
74
75         for (i = 0; i < len; ++i) {
76                 signed char ch = *ptr++;
77                 tmp += ((0x0f - (ch & 0x0f)) << 2) + 1;
78                 hash += tbl2[tmp & 0x3f];
79                 tmp += ((0xf0 - (ch & 0xf0)) >> 2) + 1;
80                 hash += tbl2[tmp & 0x3f];
81         }
82         return hash;
83 }
84
85 void decode_fen_board(char *str, char *board)
86 {
87         while (*str) {
88                 switch (*str) {
89                 case 'r':
90                 case 'n':
91                 case 'b':
92                 case 'q':
93                 case 'k':
94                 case 'p':
95                 case 'R':
96                 case 'N':
97                 case 'B':
98                 case 'Q':
99                 case 'K':
100                 case 'P':
101                         *board++ = *str;
102                         break;
103                 case '8':
104                         *board++ = ' ';
105                         // fall through
106                 case '7':
107                         *board++ = ' ';
108                         // fall through
109                 case '6':
110                         *board++ = ' ';
111                         // fall through
112                 case '5':
113                         *board++ = ' ';
114                         // fall through
115                 case '4':
116                         *board++ = ' ';
117                         // fall through
118                 case '3':
119                         *board++ = ' ';
120                         // fall through
121                 case '2':
122                         *board++ = ' ';
123                         // fall through
124                 case '1':
125                         *board++ = ' ';
126                         break;
127                 case '/':
128                         // ignore
129                         break;
130                 default:
131                         fprintf(stderr, "Unknown FEN board character '%c'\n", *str);
132                         exit(1);
133                 }
134
135                 ++str;
136         }
137 }
138
139 void invert_board(char *board)
140 {
141         int y, x, i;
142
143         // flip the board
144         for (y = 0; y < 4; ++y) {
145                 for (x = 0; x < 8; ++x) {
146                         char tmp = board[y * 8 + (x)];
147                         board[y * 8 + (x)] = board[(7-y) * 8 + (x)];
148                         board[(7-y) * 8 + (x)] = tmp;
149                 }
150         }
151
152         // invert the colors
153         for (y = 0; y < 8; ++y) {
154                 for (x = 0; x < 8; ++x) {
155                         if (board[y * 8 + x] == toupper(board[y * 8 + x])) {
156                                 board[y * 8 + x] = tolower(board[y * 8 + x]);
157                         } else {
158                                 board[y * 8 + x] = toupper(board[y * 8 + x]);
159                         }
160                 }
161         }
162 }
163
164 unsigned char position[32];
165 int pos_len;
166 int bits_left;
167
168 void put_bit(int x)
169 {
170         position[pos_len] <<= 1;
171         if (x)
172                 position[pos_len] |= 1;
173
174         if (--bits_left == 0) {
175                 ++pos_len;
176                 bits_left = 8;
177         }
178 }
179
180 void encode_position(char *board, int invert, char *castling_rights, char *ep_column)
181 {
182         int x, y;
183         int ep_any = 0;
184
185         // clear out
186         memset(position, 0, 32);
187
188         // leave some room for the header byte, which will be filled last
189         pos_len = 1;
190         bits_left = 8;
191
192         // slightly unusual ordering
193         for (x = 0; x < 8; ++x) {
194                 for (y = 0; y < 8; ++y) {
195                         switch (board[(7-y) * 8 + x]) {
196                         case ' ':
197                                 put_bit(0);
198                                 break;
199                         case 'p':
200                                 put_bit(1);
201                                 put_bit(1);
202                                 put_bit(1);
203                                 break;
204                         case 'P':
205                                 put_bit(1);
206                                 put_bit(1);
207                                 put_bit(0);
208                                 break;
209                         case 'r':
210                                 put_bit(1);
211                                 put_bit(0);
212                                 put_bit(1);
213                                 put_bit(1);
214                                 put_bit(1);
215                                 break;
216                         case 'R':
217                                 put_bit(1);
218                                 put_bit(0);
219                                 put_bit(1);
220                                 put_bit(1);
221                                 put_bit(0);
222                                 break;
223                         case 'b':
224                                 put_bit(1);
225                                 put_bit(0);
226                                 put_bit(1);
227                                 put_bit(0);
228                                 put_bit(1);
229                                 break;
230                         case 'B':
231                                 put_bit(1);
232                                 put_bit(0);
233                                 put_bit(1);
234                                 put_bit(0);
235                                 put_bit(0);
236                                 break;
237                         case 'n':
238                                 put_bit(1);
239                                 put_bit(0);
240                                 put_bit(0);
241                                 put_bit(1);
242                                 put_bit(1);
243                                 break;
244                         case 'N':
245                                 put_bit(1);
246                                 put_bit(0);
247                                 put_bit(0);
248                                 put_bit(1);
249                                 put_bit(0);
250                                 break;
251                         case 'q':
252                                 put_bit(1);
253                                 put_bit(0);
254                                 put_bit(0);
255                                 put_bit(0);
256                                 put_bit(1);
257                                 put_bit(1);
258                                 break;
259                         case 'Q':
260                                 put_bit(1);
261                                 put_bit(0);
262                                 put_bit(0);
263                                 put_bit(0);
264                                 put_bit(1);
265                                 put_bit(0);
266                                 break;
267                         case 'k':
268                                 put_bit(1);
269                                 put_bit(0);
270                                 put_bit(0);
271                                 put_bit(0);
272                                 put_bit(0);
273                                 put_bit(1);
274                                 break;
275                         case 'K':
276                                 put_bit(1);
277                                 put_bit(0);
278                                 put_bit(0);
279                                 put_bit(0);
280                                 put_bit(0);
281                                 put_bit(0);
282                                 break;
283                         }
284                 }
285         }
286
287         // en passant
288         if (strcmp(ep_column, "-") != 0) {
289                 int epcn = ep_column[0] - 'a';
290
291                 // only encode en passant if a capture is actually possible
292                 if ((epcn > 0 && board[3*8 + epcn - 1] == 'P') ||
293                     (epcn < 7 && board[3*8 + epcn + 1] == 'P')) {
294                         ep_any = 1;
295
296                         put_bit(epcn & 0x80);
297                         put_bit(epcn & 0x40);
298                         put_bit(epcn & 0x20);
299                         put_bit(epcn & 0x10);
300                         put_bit(epcn & 0x08);
301                         put_bit(epcn & 0x04);
302                         put_bit(epcn & 0x02);
303                         put_bit(epcn & 0x01);
304                 }
305         }
306
307         // really odd padding
308         if (bits_left > 4) {
309                 int i, nb = bits_left - 4;
310                 for (i = 0; i < nb; ++i) {
311                         //printf("spare bit\n");
312                         put_bit(0);
313                 }
314         }
315         
316         // castling rights
317         if (strcmp(castling_rights, "-") != 0) {
318                 if (invert) {
319                         put_bit(strchr(castling_rights, 'K') != NULL);
320                         put_bit(strchr(castling_rights, 'Q') != NULL);
321                         put_bit(strchr(castling_rights, 'k') != NULL);
322                         put_bit(strchr(castling_rights, 'q') != NULL);
323                 } else {
324                         put_bit(strchr(castling_rights, 'k') != NULL);
325                         put_bit(strchr(castling_rights, 'q') != NULL);
326                         put_bit(strchr(castling_rights, 'K') != NULL);
327                         put_bit(strchr(castling_rights, 'Q') != NULL);
328                 }
329         }
330
331         // padding stuff
332 #if 1
333         if (bits_left != 8)
334                 ++pos_len;
335 #endif
336                 
337         // and the header byte
338         position[0] = pos_len;
339
340         if (strcmp(castling_rights, "-") != 0)
341                 position[0] |= 0x40;
342         if (ep_any)
343                 position[0] |= 0x20;
344
345 #if 1
346         // dump
347         {
348                 int i;
349                 for (i = 0; i < pos_len; ++i) {
350                         printf("%02x ", position[i]);
351                 }
352                 printf("\n");
353         }
354 #endif
355 }
356                 
357 int search_pos(unsigned c, char *result)
358 {
359         char buf[4];
360         unsigned char pagebuf[4096];
361         unsigned page;
362         unsigned page_len;
363
364         lseek(cto_fd, c * 4 + 16, SEEK_SET);
365         
366         read(cto_fd, buf, 4);
367         page = htonl(*((unsigned *)buf));
368         if (page == -1)
369                 return 0;
370
371         lseek(ctg_fd, page * 4096 + 4096, SEEK_SET);
372         read(ctg_fd, pagebuf, 4096);
373
374         // search the page
375         {
376                 int pos = 4;
377                 int page_end = htons(*((short *)(pagebuf + 2)));
378
379                 while (pos < page_end) {
380                         if (pagebuf[pos] != position[0] ||
381                             memcmp(pagebuf + pos, position, pos_len) != 0) {
382                                 // no match, skip through
383                                 pos += pagebuf[pos] & 0x1f;
384                                 pos += pagebuf[pos];
385                                 pos += 33;
386                                 continue;
387                         }
388                         pos += pagebuf[pos] & 0x1f;
389                         memcpy(result, pagebuf + pos, pagebuf[pos] + 33);
390                         return 1;
391                 }
392         }
393
394         return 0;
395 }
396
397 int lookup_position(char *pos, unsigned len, char *result)
398 {
399         int hash = gen_hash(position, pos_len);
400         int n;
401         
402         for (n = 0; n < 0x7fffffff; n = 2 * n + 1) {
403                 unsigned c = (hash & n) + n;
404
405                 // FIXME: adjust these bounds
406                 if (c < 0x80e0)
407                         continue;
408
409                 if (search_pos(c, result))
410                         return 1;
411                 
412                 if (c >= 0x1fd00)
413                         break;
414         }
415
416         return 0;
417 }
418
419 struct moveenc {
420         char encoding;
421         char piece;
422         int num;
423         int forward, right;
424 };
425 struct moveenc movetable[] = {
426         0x00, 'P', 5,  1,  1,
427         0x01, 'N', 2, -1, -2,
428         0x04, 'P', 2,  1,  0,
429         0x05, 'Q', 1,  1,  0,
430         0x06, 'P', 4,  1, -1,
431         0x09, 'B', 2,  6,  6,
432         0x0a, 'K', 1, -1,  0,
433         0x0c, 'P', 1,  1, -1,
434         0x0d, 'B', 1,  3,  3,
435         0x0e, 'R', 2,  0,  3,
436         0x0f, 'N', 1, -1, -2,
437         0x12, 'B', 1,  7,  7,
438         0x13, 'K', 1,  1,  0,
439         0x14, 'P', 8,  1,  1,
440         0x15, 'B', 1,  5,  5,
441         0x18, 'P', 7,  1,  0,
442         0x1b, 'B', 1,  1, -1,
443         0x1d, 'B', 2,  7,  7,
444         0x21, 'R', 2,  0,  7,
445         0x22, 'B', 2,  2, -2,
446         0x24, 'P', 8,  1, -1,
447         0x26, 'B', 1,  7, -7,
448         0x27, 'P', 3,  1, -1,
449         0x28, 'Q', 1,  5,  5,
450         0x29, 'Q', 1,  0,  6,
451         0x2a, 'N', 2, -2,  1,
452         0x2d, 'P', 6,  1,  1,
453         0x2e, 'B', 1,  1,  1,
454         0x2f, 'Q', 1,  0,  1,
455         0x30, 'N', 2, -2, -1,
456         0x31, 'Q', 1,  0,  3,
457         0x32, 'B', 2,  5,  5,
458         0x34, 'N', 1,  2,  1,
459         0x36, 'N', 1,  1,  2,
460         0x37, 'Q', 1,  4,  0,
461         0x39, 'Q', 1,  0,  5,
462         0x3a, 'B', 1,  6,  6,
463         0x3c, 'B', 1,  5, -5,
464         0x42, 'Q', 1,  7, -7,
465         0x44, 'K', 1, -1,  1,
466         0x45, 'Q', 1,  3,  3,
467         0x4a, 'P', 8,  2,  0,
468         0x4b, 'Q', 1,  5, -5,
469         0x4c, 'N', 2,  2,  1,
470         0x50, 'R', 1,  6,  0,
471         0x52, 'R', 1,  0,  6,
472         0x54, 'B', 2,  1, -1,
473         0x55, 'P', 3,  1,  0,
474         0x5c, 'P', 7,  1,  1,
475         0x5f, 'P', 5,  2,  0,
476         0x61, 'Q', 1,  6,  6,
477         0x62, 'P', 2,  2,  0,
478         0x66, 'B', 1,  3, -3,
479         0x67, 'K', 1,  1,  1,
480         0x69, 'R', 2,  7,  0,
481         0x6a, 'B', 1,  4,  4,
482         0x6b, 'K', 1,  0,  2,   /* short castling */
483         0x6e, 'R', 1,  0,  5,
484         0x72, 'B', 2,  7, -7,
485         0x74, 'Q', 1,  0,  2,
486         0x79, 'B', 2,  6, -6,
487         0x7a, 'R', 1,  3,  0,
488         0x7b, 'R', 2,  6,  0,
489         0x7c, 'P', 3,  1,  1,
490         0x7d, 'R', 2,  1,  0,
491         0x7e, 'Q', 1,  3, -3,
492         0x7f, 'R', 1,  0,  1,
493         0x80, 'Q', 1,  6, -6,
494         0x81, 'R', 1,  1,  0,
495         0x82, 'P', 6,  1, -1,
496         0x85, 'N', 1,  2, -1,
497         0x86, 'R', 1,  0,  7,
498         0x87, 'R', 1,  5,  0,
499         0x8a, 'N', 1, -2,  1,
500         0x8b, 'P', 1,  1,  1,
501         0x8c, 'K', 1, -1, -1,
502         0x8f, 'Q', 1,  0,  7,
503         0x94, 'Q', 1,  3,  0,
504         0x96, 'P', 2,  1,  1,
505         0x97, 'K', 1,  0, -1,
506         0x98, 'R', 1,  0,  3,
507         0x99, 'R', 1,  4,  0,
508         0x9a, 'Q', 1,  6,  0,
509         0x9b, 'P', 3,  2,  0,
510         0x9d, 'Q', 1,  2,  0,
511         0x9f, 'B', 2,  4, -4,
512         0xa2, 'Q', 1,  2,  2,
513         0xa3, 'P', 8,  1,  0,
514         0xa5, 'R', 2,  5,  0,
515         0xa9, 'R', 2,  0,  2,
516         0xad, 'R', 2,  0,  4,
517         0xb1, 'P', 6,  2,  0,
518         0xb2, 'B', 1,  6, -6,
519         0xb5, 'R', 2,  0,  5,
520         0xb7, 'Q', 1,  5,  0,
521         0xb9, 'B', 2,  3,  3,
522         0xbb, 'P', 5,  1,  0,
523         0xbe, 'K', 1,  0,  1,
524         0xc1, 'B', 1,  2,  2,
525         0xc2, 'B', 2,  2,  2,
526         0xc3, 'B', 1,  2, -2,
527         0xc4, 'R', 2,  0,  1,
528         0xc5, 'R', 2,  4,  0,
529         0xc7, 'P', 7,  1, -1,
530         0xc8, 'P', 7,  2,  0,
531         0xca, 'B', 2,  3, -3,
532         0xcb, 'P', 6,  1,  0,
533         0xcc, 'B', 2,  5, -5,
534         0xcd, 'R', 1,  0,  2,
535         0xcf, 'P', 4,  1,  0,
536         0xd1, 'P', 2,  1, -1,
537         0xd2, 'N', 2,  1,  2,
538         0xd3, 'N', 2,  1, -2,
539         0xd7, 'Q', 1,  1, -1,
540         0xd8, 'R', 2,  0,  6,
541         0xd9, 'Q', 1,  2, -2,
542         0xda, 'N', 1, -2, -1,
543         0xdb, 'P', 1,  2,  0,
544         0xde, 'P', 5,  1, -1,
545         0xdf, 'K', 1,  1, -1,
546         0xe0, 'N', 2, -1,  2,
547         0xe1, 'R', 1,  7,  0,
548         0xe3, 'R', 2,  3,  0,
549         0xe5, 'Q', 1,  0,  4,
550         0xe6, 'P', 4,  2,  0,
551         0xe7, 'Q', 1,  4,  4,
552         0xe8, 'R', 1,  2,  0,
553         0xe9, 'N', 1, -1,  2,
554         0xeb, 'P', 4,  1,  1,
555         0xec, 'P', 1,  1,  0,
556         0xed, 'Q', 1,  7,  7,
557         0xef, 'R', 1,  0,  4,
558         0xf1, 'Q', 1,  1,  1,
559         0xf3, 'N', 2,  2, -1,
560         0xf4, 'R', 2,  2,  0,
561         0xf5, 'B', 2,  1,  1,
562         0xf6, 'K', 1,  0, -2,   /* long castling */
563         0xf7, 'N', 1,  1, -2,
564         0xfd, 'Q', 1,  7,  0
565 };
566
567 int find_piece(char *board, char piece, int num)
568 {
569         int y, x;
570         for (x = 0; x < 8; ++x) {
571                 for (y = 0; y < 8; ++y) {
572                         if (board[(7-y) * 8 + x] != piece)
573                                 continue;
574                         if (--num == 0)
575                                 return (y * 8 + x);
576                 }
577         }
578
579         fprintf(stderr, "Couldn't find piece '%c' number %u\n", piece, num);
580 }
581
582 void execute_move(char *board, char *castling_rights, int inverted, char *ep_square, int from_square, int to_square)
583 {
584         int black_ks, black_qs, white_ks, white_qs;
585
586         // fudge
587         from_square = (7 - (from_square / 8)) * 8 + (from_square % 8);
588         to_square = (7 - (to_square / 8)) * 8 + (to_square % 8);
589
590         // compute the new castling rights
591         black_ks = (strchr(castling_rights, 'k') != NULL);
592         black_qs = (strchr(castling_rights, 'q') != NULL);
593         white_ks = (strchr(castling_rights, 'K') != NULL);
594         white_qs = (strchr(castling_rights, 'Q') != NULL);
595
596         if (board[from_square] == 'K') {
597                 if (inverted)
598                         black_ks = black_qs = 0;
599                 else
600                         white_ks = white_qs = 0;
601         } else if (board[from_square] == 'R') {
602                 if (inverted) {
603                         if (from_square == 0) // a1
604                                 black_qs = 0;
605                         else if (from_square == 7 * 8 + 0) // a8
606                                 black_ks = 0;
607                 } else {
608                         if (from_square == 0) // a1
609                                 white_qs = 0;
610                         else if (from_square == 7 * 8 + 0) // a8
611                                 white_ks = 0;
612                 }
613         }
614
615         if ((black_ks | black_qs | white_ks | white_qs) == 0) {
616                 strcpy(castling_rights, "-");
617         } else {
618                 strcpy(castling_rights, "");
619
620                 if (white_ks)
621                         strcat(castling_rights, "K");
622                 if (white_qs)
623                         strcat(castling_rights, "Q");
624                 if (black_ks)
625                         strcat(castling_rights, "k");
626                 if (black_qs)
627                         strcat(castling_rights, "q");
628         }
629
630         // now the ep square
631         if (board[from_square] == 'P' && to_square - from_square == -16) {
632                 sprintf(ep_square, "%c%u", "abcdefgh"[from_square % 8], from_square / 8 + 2);
633         } else {
634                 strcpy(ep_square, "-");
635         }
636
637         // is this move an en passant capture?
638         if (board[from_square] == 'P' && board[to_square] == ' ' &&
639             (to_square - from_square == -9 || to_square - from_square == -7)) {
640                 board[to_square + 8] = ' ';     
641         }
642
643         // make the move
644         board[to_square] = board[from_square];
645         board[from_square] = ' ';
646
647         if (board[to_square] == 'K' && to_square - from_square == 2) {
648                 // short castling
649                 board[to_square - 1] = 'R';
650                 board[to_square + 1] = ' ';
651         } else if (board[to_square] == 'K' && to_square - from_square == -2) {
652                 // long castling
653                 board[to_square + 1] = 'R';
654                 board[to_square - 2] = ' ';
655         }
656
657 #if 0
658         // dump the board
659         {
660                 int y, x;
661                 printf("\n\n");
662                 for (y = 0; y < 8; ++y) {
663                         for (x = 0; x < 8; ++x) {
664                                 putchar(board[y * 8 + x]);
665                         }
666                         putchar('\n');
667                 }
668         }
669         printf("cr='%s' ep='%s'\n", castling_rights, ep_square);
670 #endif
671 }
672
673 void dump_move(char *board, char *castling_rights, char *ep_col, int invert, char move, char annotation)
674 {
675         int i;
676         char newboard[64], nkr[5], neps[3];
677         for (i = 0; i < sizeof(movetable)/sizeof(movetable[0]); ++i) {
678                 int from_square, from_row, from_col;
679                 int to_square, to_row, to_col;
680                 int ret;
681                 char result[256];
682
683                 if (move != movetable[i].encoding)
684                         continue;
685
686                 from_square = find_piece(board, movetable[i].piece, movetable[i].num);
687                 from_row = from_square / 8;
688                 from_col = from_square % 8;
689
690                 to_row = (from_row + 8 + movetable[i].forward) % 8;
691                 to_col = (from_col + 8 + movetable[i].right) % 8;
692                 to_square = to_row * 8 + to_col;
693
694                 // output the move
695                 if (invert)
696                         printf("%c%u%c%u,",
697                                 "abcdefgh"[from_square % 8], (7 - from_square / 8) + 1,
698                                 "abcdefgh"[to_square % 8], (7 - to_square / 8) + 1);
699                 else
700                         printf("%c%u%c%u,",
701                                 "abcdefgh"[from_square % 8], from_square / 8 + 1,
702                                 "abcdefgh"[to_square % 8], to_square / 8 + 1);
703
704                 // annotation
705                 switch (annotation) {
706                 case 0x00:
707                         break;
708                 case 0x01:
709                         printf("!");
710                         break;
711                 case 0x02:
712                         printf("?");
713                         break;
714                 case 0x03:
715                         printf("!!");
716                         break;
717                 case 0x04:
718                         printf("??");
719                         break;
720                 case 0x05:
721                         printf("!?");
722                         break;
723                 case 0x06:
724                         printf("?!");
725                         break;
726                 case 0x08:
727                         printf(" (only move)");
728                         break;
729                 case 0x16:
730                         printf(" (zugzwang)");
731                         break;
732                 default:
733                         printf(" (unknown status 0x%02x)", annotation);
734                 }
735                 printf(",");
736
737                 // do the move, and look up the new position
738                 memcpy(newboard, board, 64);
739                 strcpy(nkr, castling_rights);
740                 execute_move(newboard, nkr, invert, neps, from_square, to_square);
741                 invert_board(newboard);
742         
743                 encode_position(newboard, !invert, nkr, neps);
744                 ret = lookup_position(position, pos_len, result);
745                 if (!ret) {
746                         fprintf(stderr, "Destination move not found in book.\n");
747                         exit(1);
748                 }
749
750                 output_stats(result, invert);
751                 return;
752         }
753
754         fprintf(stderr, "ERROR: Unknown move 0x%02x\n", move);
755 }
756
757 void dump_info(char *board, char *castling_rights, char *ep_col, int invert, char *result)
758 {
759         int book_moves = result[0] >> 1;
760         int i;
761                 
762         printf(",,");   
763         output_stats(result, !invert);
764
765         for (i = 0; i < book_moves; ++i) {
766                 dump_move(board, castling_rights, ep_col, invert, result[i * 2 + 1], result[i * 2 + 2]);
767         }
768 }
769
770 int main(int argc, char **argv)
771 {
772         // encode the position
773         char board[64], result[256];
774         int invert = 0;
775         int ret;
776         
777         ctg_fd = open("RybkaII.ctg", O_RDONLY);
778         cto_fd = open("RybkaII.cto", O_RDONLY);
779         ctb_fd = open("RybkaII.ctb", O_RDONLY);
780         decode_fen_board(argv[1], board);
781
782         // always from white's position
783         if (argv[2][0] == 'b') {
784                 invert = 1;
785                 invert_board(board);
786         }
787
788 #if 0
789         // dump the board
790         {
791                 int y, x;
792                 for (y = 0; y < 8; ++y) {
793                         for (x = 0; x < 8; ++x) {
794                                 putchar(board[y * 8 + x]);
795                         }
796                         putchar('\n');
797                 }
798         }
799 #endif
800
801         encode_position(board, invert, argv[3], argv[4]);
802         ret = lookup_position(position, pos_len, result);
803         if (!ret) {
804                 printf("Not found in book.\n");
805                 exit(1);
806         }
807
808         dump_info(board, argv[3], argv[4], invert, result);
809 }
810