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