]> git.sesse.net Git - remoteglot/blob - booklook.c
c9eea593c853ddb648ec7a4d647a0290fb6aedeb
[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                 int i, nd = 8 - bits_left;
335                 for (i = 0; i < nd; ++i)
336                         put_bit(0);
337         }
338 #endif
339                 
340         // and the header byte
341         position[0] = pos_len;
342
343         if (strcmp(castling_rights, "-") != 0)
344                 position[0] |= 0x40;
345         if (ep_any)
346                 position[0] |= 0x20;
347
348 #if 0
349         // dump
350         {
351                 int i;
352                 for (i = 0; i < pos_len; ++i) {
353                         printf("%02x ", position[i]);
354                 }
355                 printf("\n");
356         }
357 #endif
358 }
359                 
360 int search_pos(unsigned c, char *result)
361 {
362         char buf[4];
363         unsigned char pagebuf[4096];
364         unsigned page;
365         unsigned page_len;
366
367         lseek(cto_fd, c * 4 + 16, SEEK_SET);
368         
369         read(cto_fd, buf, 4);
370         page = htonl(*((unsigned *)buf));
371         if (page == -1)
372                 return 0;
373
374         lseek(ctg_fd, page * 4096 + 4096, SEEK_SET);
375         read(ctg_fd, pagebuf, 4096);
376
377         // search the page
378         {
379                 int pos = 4;
380                 int page_end = htons(*((short *)(pagebuf + 2)));
381
382                 while (pos < page_end) {
383                         if (pagebuf[pos] != position[0] ||
384                             memcmp(pagebuf + pos, position, pos_len) != 0) {
385                                 // no match, skip through
386                                 pos += pagebuf[pos] & 0x1f;
387                                 pos += pagebuf[pos];
388                                 pos += 33;
389                                 continue;
390                         }
391                         pos += pagebuf[pos] & 0x1f;
392                         memcpy(result, pagebuf + pos, pagebuf[pos] + 33);
393                         return 1;
394                 }
395         }
396
397         return 0;
398 }
399
400 int lookup_position(char *pos, unsigned len, char *result)
401 {
402         int hash = gen_hash(position, pos_len);
403         int n;
404         
405         for (n = 0; n < 0x7fffffff; n = 2 * n + 1) {
406                 unsigned c = (hash & n) + n;
407
408                 // FIXME: adjust these bounds
409                 if (c < 0x80e0)
410                         continue;
411
412                 if (search_pos(c, result))
413                         return 1;
414                 
415                 if (c >= 0x1fd00)
416                         break;
417         }
418
419         return 0;
420 }
421
422 struct moveenc {
423         char encoding;
424         char piece;
425         int num;
426         int forward, right;
427 };
428 struct moveenc movetable[] = {
429         0x00, 'P', 5,  1,  1,
430         0x01, 'N', 2, -1, -2,
431         0x04, 'P', 2,  1,  0,
432         0x05, 'Q', 1,  1,  0,
433         0x06, 'P', 4,  1, -1,
434         0x09, 'B', 2,  6,  6,
435         0x0a, 'K', 1, -1,  0,
436         0x0c, 'P', 1,  1, -1,
437         0x0d, 'B', 1,  3,  3,
438         0x0e, 'R', 2,  0,  3,
439         0x0f, 'N', 1, -1, -2,
440         0x12, 'B', 1,  7,  7,
441         0x13, 'K', 1,  1,  0,
442         0x14, 'P', 8,  1,  1,
443         0x15, 'B', 1,  5,  5,
444         0x18, 'P', 7,  1,  0,
445         0x1b, 'B', 1,  1, -1,
446         0x1d, 'B', 2,  7,  7,
447         0x21, 'R', 2,  0,  7,
448         0x22, 'B', 2,  2, -2,
449         0x24, 'P', 8,  1, -1,
450         0x26, 'B', 1,  7, -7,
451         0x27, 'P', 3,  1, -1,
452         0x28, 'Q', 1,  5,  5,
453         0x29, 'Q', 1,  0,  6,
454         0x2a, 'N', 2, -2,  1,
455         0x2d, 'P', 6,  1,  1,
456         0x2e, 'B', 1,  1,  1,
457         0x2f, 'Q', 1,  0,  1,
458         0x30, 'N', 2, -2, -1,
459         0x31, 'Q', 1,  0,  3,
460         0x32, 'B', 2,  5,  5,
461         0x34, 'N', 1,  2,  1,
462         0x36, 'N', 1,  1,  2,
463         0x37, 'Q', 1,  4,  0,
464         0x39, 'Q', 1,  0,  5,
465         0x3a, 'B', 1,  6,  6,
466         0x3c, 'B', 1,  5, -5,
467         0x42, 'Q', 1,  7, -7,
468         0x44, 'K', 1, -1,  1,
469         0x45, 'Q', 1,  3,  3,
470         0x4a, 'P', 8,  2,  0,
471         0x4b, 'Q', 1,  5, -5,
472         0x4c, 'N', 2,  2,  1,
473         0x50, 'R', 1,  6,  0,
474         0x52, 'R', 1,  0,  6,
475         0x54, 'B', 2,  1, -1,
476         0x55, 'P', 3,  1,  0,
477         0x5c, 'P', 7,  1,  1,
478         0x5f, 'P', 5,  2,  0,
479         0x61, 'Q', 1,  6,  6,
480         0x62, 'P', 2,  2,  0,
481         0x66, 'B', 1,  3, -3,
482         0x67, 'K', 1,  1,  1,
483         0x69, 'R', 2,  7,  0,
484         0x6a, 'B', 1,  4,  4,
485         0x6b, 'K', 1,  0,  2,   /* short castling */
486         0x6e, 'R', 1,  0,  5,
487         0x72, 'B', 2,  7, -7,
488         0x74, 'Q', 1,  0,  2,
489         0x79, 'B', 2,  6, -6,
490         0x7a, 'R', 1,  3,  0,
491         0x7b, 'R', 2,  6,  0,
492         0x7c, 'P', 3,  1,  1,
493         0x7d, 'R', 2,  1,  0,
494         0x7e, 'Q', 1,  3, -3,
495         0x7f, 'R', 1,  0,  1,
496         0x80, 'Q', 1,  6, -6,
497         0x81, 'R', 1,  1,  0,
498         0x82, 'P', 6,  1, -1,
499         0x85, 'N', 1,  2, -1,
500         0x86, 'R', 1,  0,  7,
501         0x87, 'R', 1,  5,  0,
502         0x8a, 'N', 1, -2,  1,
503         0x8b, 'P', 1,  1,  1,
504         0x8c, 'K', 1, -1, -1,
505         0x8f, 'Q', 1,  0,  7,
506         0x94, 'Q', 1,  3,  0,
507         0x96, 'P', 2,  1,  1,
508         0x97, 'K', 1,  0, -1,
509         0x98, 'R', 1,  0,  3,
510         0x99, 'R', 1,  4,  0,
511         0x9a, 'Q', 1,  6,  0,
512         0x9b, 'P', 3,  2,  0,
513         0x9d, 'Q', 1,  2,  0,
514         0x9f, 'B', 2,  4, -4,
515         0xa2, 'Q', 1,  2,  2,
516         0xa3, 'P', 8,  1,  0,
517         0xa5, 'R', 2,  5,  0,
518         0xa9, 'R', 2,  0,  2,
519         0xad, 'R', 2,  0,  4,
520         0xb1, 'P', 6,  2,  0,
521         0xb2, 'B', 1,  6, -6,
522         0xb5, 'R', 2,  0,  5,
523         0xb7, 'Q', 1,  5,  0,
524         0xb9, 'B', 2,  3,  3,
525         0xbb, 'P', 5,  1,  0,
526         0xbe, 'K', 1,  0,  1,
527         0xc1, 'B', 1,  2,  2,
528         0xc2, 'B', 2,  2,  2,
529         0xc3, 'B', 1,  2, -2,
530         0xc4, 'R', 2,  0,  1,
531         0xc5, 'R', 2,  4,  0,
532         0xc7, 'P', 7,  1, -1,
533         0xc8, 'P', 7,  2,  0,
534         0xca, 'B', 2,  3, -3,
535         0xcb, 'P', 6,  1,  0,
536         0xcc, 'B', 2,  5, -5,
537         0xcd, 'R', 1,  0,  2,
538         0xcf, 'P', 4,  1,  0,
539         0xd1, 'P', 2,  1, -1,
540         0xd2, 'N', 2,  1,  2,
541         0xd3, 'N', 2,  1, -2,
542         0xd7, 'Q', 1,  1, -1,
543         0xd8, 'R', 2,  0,  6,
544         0xd9, 'Q', 1,  2, -2,
545         0xda, 'N', 1, -2, -1,
546         0xdb, 'P', 1,  2,  0,
547         0xde, 'P', 5,  1, -1,
548         0xdf, 'K', 1,  1, -1,
549         0xe0, 'N', 2, -1,  2,
550         0xe1, 'R', 1,  7,  0,
551         0xe3, 'R', 2,  3,  0,
552         0xe5, 'Q', 1,  0,  4,
553         0xe6, 'P', 4,  2,  0,
554         0xe7, 'Q', 1,  4,  4,
555         0xe8, 'R', 1,  2,  0,
556         0xe9, 'N', 1, -1,  2,
557         0xeb, 'P', 4,  1,  1,
558         0xec, 'P', 1,  1,  0,
559         0xed, 'Q', 1,  7,  7,
560         0xef, 'R', 1,  0,  4,
561         0xf1, 'Q', 1,  1,  1,
562         0xf3, 'N', 2,  2, -1,
563         0xf4, 'R', 2,  2,  0,
564         0xf5, 'B', 2,  1,  1,
565         0xf6, 'K', 1,  0, -2,   /* long castling */
566         0xf7, 'N', 1,  1, -2,
567         0xfd, 'Q', 1,  7,  0
568 };
569
570 int find_piece(char *board, char piece, int num)
571 {
572         int y, x;
573         for (x = 0; x < 8; ++x) {
574                 for (y = 0; y < 8; ++y) {
575                         if (board[(7-y) * 8 + x] != piece)
576                                 continue;
577                         if (--num == 0)
578                                 return (y * 8 + x);
579                 }
580         }
581
582         fprintf(stderr, "Couldn't find piece '%c' number %u\n", piece, num);
583 }
584
585 void execute_move(char *board, char *castling_rights, int inverted, char *ep_square, int from_square, int to_square)
586 {
587         int black_ks, black_qs, white_ks, white_qs;
588
589         // fudge
590         from_square = (7 - (from_square / 8)) * 8 + (from_square % 8);
591         to_square = (7 - (to_square / 8)) * 8 + (to_square % 8);
592
593         // compute the new castling rights
594         black_ks = (strchr(castling_rights, 'k') != NULL);
595         black_qs = (strchr(castling_rights, 'q') != NULL);
596         white_ks = (strchr(castling_rights, 'K') != NULL);
597         white_qs = (strchr(castling_rights, 'Q') != NULL);
598
599         if (board[from_square] == 'K') {
600                 if (inverted)
601                         black_ks = black_qs = 0;
602                 else
603                         white_ks = white_qs = 0;
604         } else if (board[from_square] == 'R') {
605                 if (inverted) {
606                         if (from_square == 0) // a1
607                                 black_qs = 0;
608                         else if (from_square == 7 * 8 + 0) // a8
609                                 black_ks = 0;
610                 } else {
611                         if (from_square == 0) // a1
612                                 white_qs = 0;
613                         else if (from_square == 7 * 8 + 0) // a8
614                                 white_ks = 0;
615                 }
616         }
617
618         if ((black_ks | black_qs | white_ks | white_qs) == 0) {
619                 strcpy(castling_rights, "-");
620         } else {
621                 strcpy(castling_rights, "");
622
623                 if (white_ks)
624                         strcat(castling_rights, "K");
625                 if (white_qs)
626                         strcat(castling_rights, "Q");
627                 if (black_ks)
628                         strcat(castling_rights, "k");
629                 if (black_qs)
630                         strcat(castling_rights, "q");
631         }
632
633         // now the ep square
634         if (board[from_square] == 'P' && to_square - from_square == -16) {
635                 sprintf(ep_square, "%c%u", "abcdefgh"[from_square % 8], from_square / 8 + 2);
636         } else {
637                 strcpy(ep_square, "-");
638         }
639
640         // is this move an en passant capture?
641         if (board[from_square] == 'P' && board[to_square] == ' ' &&
642             (to_square - from_square == -9 || to_square - from_square == -7)) {
643                 board[to_square + 8] = ' ';     
644         }
645
646         // make the move
647         board[to_square] = board[from_square];
648         board[from_square] = ' ';
649
650         if (board[to_square] == 'K' && to_square - from_square == 2) {
651                 // short castling
652                 board[to_square - 1] = 'R';
653                 board[to_square + 1] = ' ';
654         } else if (board[to_square] == 'K' && to_square - from_square == -2) {
655                 // long castling
656                 board[to_square + 1] = 'R';
657                 board[to_square - 2] = ' ';
658         }
659
660 #if 0
661         // dump the board
662         {
663                 int y, x;
664                 printf("\n\n");
665                 for (y = 0; y < 8; ++y) {
666                         for (x = 0; x < 8; ++x) {
667                                 putchar(board[y * 8 + x]);
668                         }
669                         putchar('\n');
670                 }
671         }
672         printf("cr='%s' ep='%s'\n", castling_rights, ep_square);
673 #endif
674 }
675
676 void dump_move(char *board, char *castling_rights, char *ep_col, int invert, char move, char annotation)
677 {
678         int i;
679         char newboard[64], nkr[5], neps[3];
680         for (i = 0; i < sizeof(movetable)/sizeof(movetable[0]); ++i) {
681                 int from_square, from_row, from_col;
682                 int to_square, to_row, to_col;
683                 int ret;
684                 char result[256];
685
686                 if (move != movetable[i].encoding)
687                         continue;
688
689                 from_square = find_piece(board, movetable[i].piece, movetable[i].num);
690                 from_row = from_square / 8;
691                 from_col = from_square % 8;
692
693                 to_row = (from_row + 8 + movetable[i].forward) % 8;
694                 to_col = (from_col + 8 + movetable[i].right) % 8;
695                 to_square = to_row * 8 + to_col;
696
697                 // output the move
698                 if (invert)
699                         printf("%c%u%c%u,",
700                                 "abcdefgh"[from_square % 8], (7 - from_square / 8) + 1,
701                                 "abcdefgh"[to_square % 8], (7 - to_square / 8) + 1);
702                 else
703                         printf("%c%u%c%u,",
704                                 "abcdefgh"[from_square % 8], from_square / 8 + 1,
705                                 "abcdefgh"[to_square % 8], to_square / 8 + 1);
706
707                 // annotation
708                 switch (annotation) {
709                 case 0x00:
710                         break;
711                 case 0x01:
712                         printf("!");
713                         break;
714                 case 0x02:
715                         printf("?");
716                         break;
717                 case 0x03:
718                         printf("!!");
719                         break;
720                 case 0x04:
721                         printf("??");
722                         break;
723                 case 0x05:
724                         printf("!?");
725                         break;
726                 case 0x06:
727                         printf("?!");
728                         break;
729                 case 0x08:
730                         printf(" (only move)");
731                         break;
732                 case 0x16:
733                         printf(" (zugzwang)");
734                         break;
735                 default:
736                         printf(" (unknown status 0x%02x)", annotation);
737                 }
738                 printf(",");
739
740                 // do the move, and look up the new position
741                 memcpy(newboard, board, 64);
742                 strcpy(nkr, castling_rights);
743                 execute_move(newboard, nkr, invert, neps, from_square, to_square);
744                 invert_board(newboard);
745         
746                 encode_position(newboard, !invert, nkr, neps);
747                 ret = lookup_position(position, pos_len, result);
748                 if (!ret) {
749                         fprintf(stderr, "Destination move not found in book.\n");
750                         exit(1);
751                 }
752
753                 output_stats(result, invert);
754                 return;
755         }
756
757         fprintf(stderr, "ERROR: Unknown move 0x%02x\n", move);
758 }
759
760 void dump_info(char *board, char *castling_rights, char *ep_col, int invert, char *result)
761 {
762         int book_moves = result[0] >> 1;
763         int i;
764                 
765         printf(",,");   
766         output_stats(result, !invert);
767
768         for (i = 0; i < book_moves; ++i) {
769                 dump_move(board, castling_rights, ep_col, invert, result[i * 2 + 1], result[i * 2 + 2]);
770         }
771 }
772
773 int main(int argc, char **argv)
774 {
775         // encode the position
776         char board[64], result[256];
777         int invert = 0;
778         int ret;
779         
780         ctg_fd = open("RybkaII.ctg", O_RDONLY);
781         cto_fd = open("RybkaII.cto", O_RDONLY);
782         ctb_fd = open("RybkaII.ctb", O_RDONLY);
783         decode_fen_board(argv[1], board);
784
785         // always from white's position
786         if (argv[2][0] == 'b') {
787                 invert = 1;
788                 invert_board(board);
789         }
790
791 #if 0
792         // dump the board
793         {
794                 int y, x;
795                 for (y = 0; y < 8; ++y) {
796                         for (x = 0; x < 8; ++x) {
797                                 putchar(board[y * 8 + x]);
798                         }
799                         putchar('\n');
800                 }
801         }
802 #endif
803
804         encode_position(board, invert, argv[3], argv[4]);
805         ret = lookup_position(position, pos_len, result);
806         if (!ret) {
807                 printf("Not found in book.\n");
808                 exit(1);
809         }
810
811         dump_info(board, argv[3], argv[4], invert, result);
812         exit(0);
813 }
814