Add book lookups.
authorSteinar H. Gunderson <sesse@debian.org>
Wed, 18 Jul 2007 15:52:45 +0000 (17:52 +0200)
committerSteinar H. Gunderson <sesse@debian.org>
Wed, 18 Jul 2007 15:52:45 +0000 (17:52 +0200)
booklook.c [new file with mode: 0644]
remoteglot.pl

diff --git a/booklook.c b/booklook.c
new file mode 100644 (file)
index 0000000..c4705b7
--- /dev/null
@@ -0,0 +1,810 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <fcntl.h>
+
+int cto_fd, ctg_fd, ctb_fd;
+
+unsigned int tbl2[] = {
+       0x3100d2bf, 0x3118e3de, 0x34ab1372, 0x2807a847,
+       0x1633f566, 0x2143b359, 0x26d56488, 0x3b9e6f59,
+       0x37755656, 0x3089ca7b, 0x18e92d85, 0x0cd0e9d8,
+       0x1a9e3b54, 0x3eaa902f, 0x0d9bfaae, 0x2f32b45b,
+       0x31ed6102, 0x3d3c8398, 0x146660e3, 0x0f8d4b76,
+       0x02c77a5f, 0x146c8799, 0x1c47f51f, 0x249f8f36,
+       0x24772043, 0x1fbc1e4d, 0x1e86b3fa, 0x37df36a6,
+       0x16ed30e4, 0x02c3148e, 0x216e5929, 0x0636b34e,
+       0x317f9f56, 0x15f09d70, 0x131026fb, 0x38c784b1,
+       0x29ac3305, 0x2b485dc5, 0x3c049ddc, 0x35a9fbcd,
+       0x31d5373b, 0x2b246799, 0x0a2923d3, 0x08a96e9d,
+       0x30031a9f, 0x08f525b5, 0x33611c06, 0x2409db98,
+       0x0ca4feb2, 0x1000b71e, 0x30566e32, 0x39447d31,
+       0x194e3752, 0x08233a95, 0x0f38fe36, 0x29c7cd57,
+       0x0f7b3a39, 0x328e8a16, 0x1e7d1388, 0x0fba78f5,
+       0x274c7e7c, 0x1e8be65c, 0x2fa0b0bb, 0x1eb6c371
+};
+
+signed char data[] = {
+       0x36, 0xb6, 0x0f, 0x79, 0x61, 0x1f, 0x50, 0xde, 0x61, 0xb9, 0x52, 0x24, 0xb3, 0xac, 0x6e, 0x5e, 0x0a, 0x69, 0xbd, 0x61, 0x61, 0xc5
+};
+
+void output_stats(char *result, int invert)
+{
+       unsigned char *ptr = result;
+       ptr += *ptr;
+       ptr += 3;
+
+       // wins-draw-loss
+       if (invert) {
+               printf("%u,", (ptr[0] << 16) | (ptr[1] << 8) | ptr[2]);
+               printf("%u,", (ptr[6] << 16) | (ptr[7] << 8) | ptr[8]);
+               printf("%u,", (ptr[3] << 16) | (ptr[4] << 8) | ptr[5]);
+       } else {
+               printf("%u,", (ptr[3] << 16) | (ptr[4] << 8) | ptr[5]);
+               printf("%u,", (ptr[6] << 16) | (ptr[7] << 8) | ptr[8]);
+               printf("%u,", (ptr[0] << 16) | (ptr[1] << 8) | ptr[2]);
+       }
+
+       ptr += 9;
+       ptr += 4;
+       ptr += 7;
+
+       // rating
+       {
+               int rat2_sum, rat2_div;
+               rat2_div = (ptr[0] << 16) | (ptr[1] << 8) | ptr[2];
+               rat2_sum = (ptr[3] << 24) | (ptr[4] << 16) | (ptr[5] << 8) | ptr[6];
+
+               if (rat2_div == 0) {
+                       printf(",0");
+               } else {
+                       printf("%u,%u", rat2_sum / rat2_div, rat2_div);
+               }
+       }
+               
+       printf("\n");
+}
+
+unsigned int gen_hash(signed char *ptr, unsigned len)
+{
+       signed hash = 0;
+       short tmp = 0;
+       int i;
+
+       for (i = 0; i < len; ++i) {
+               signed char ch = *ptr++;
+               tmp += ((0x0f - (ch & 0x0f)) << 2) + 1;
+               hash += tbl2[tmp & 0x3f];
+               tmp += ((0xf0 - (ch & 0xf0)) >> 2) + 1;
+               hash += tbl2[tmp & 0x3f];
+       }
+       return hash;
+}
+
+void decode_fen_board(char *str, char *board)
+{
+       while (*str) {
+               switch (*str) {
+               case 'r':
+               case 'n':
+               case 'b':
+               case 'q':
+               case 'k':
+               case 'p':
+               case 'R':
+               case 'N':
+               case 'B':
+               case 'Q':
+               case 'K':
+               case 'P':
+                       *board++ = *str;
+                       break;
+               case '8':
+                       *board++ = ' ';
+                       // fall through
+               case '7':
+                       *board++ = ' ';
+                       // fall through
+               case '6':
+                       *board++ = ' ';
+                       // fall through
+               case '5':
+                       *board++ = ' ';
+                       // fall through
+               case '4':
+                       *board++ = ' ';
+                       // fall through
+               case '3':
+                       *board++ = ' ';
+                       // fall through
+               case '2':
+                       *board++ = ' ';
+                       // fall through
+               case '1':
+                       *board++ = ' ';
+                       break;
+               case '/':
+                       // ignore
+                       break;
+               default:
+                       fprintf(stderr, "Unknown FEN board character '%c'\n", *str);
+                       exit(1);
+               }
+
+               ++str;
+       }
+}
+
+void invert_board(char *board)
+{
+       int y, x, i;
+
+       // flip the board
+       for (y = 0; y < 4; ++y) {
+               for (x = 0; x < 8; ++x) {
+                       char tmp = board[y * 8 + (x)];
+                       board[y * 8 + (x)] = board[(7-y) * 8 + (x)];
+                       board[(7-y) * 8 + (x)] = tmp;
+               }
+       }
+
+       // invert the colors
+       for (y = 0; y < 8; ++y) {
+               for (x = 0; x < 8; ++x) {
+                       if (board[y * 8 + x] == toupper(board[y * 8 + x])) {
+                               board[y * 8 + x] = tolower(board[y * 8 + x]);
+                       } else {
+                               board[y * 8 + x] = toupper(board[y * 8 + x]);
+                       }
+               }
+       }
+}
+
+unsigned char position[32];
+int pos_len;
+int bits_left;
+
+void put_bit(int x)
+{
+       position[pos_len] <<= 1;
+       if (x)
+               position[pos_len] |= 1;
+
+       if (--bits_left == 0) {
+               ++pos_len;
+               bits_left = 8;
+       }
+}
+
+void encode_position(char *board, int invert, char *castling_rights, char *ep_column)
+{
+       int x, y;
+       int ep_any = 0;
+
+       // clear out
+       memset(position, 0, 32);
+
+       // leave some room for the header byte, which will be filled last
+       pos_len = 1;
+       bits_left = 8;
+
+       // slightly unusual ordering
+       for (x = 0; x < 8; ++x) {
+               for (y = 0; y < 8; ++y) {
+                       switch (board[(7-y) * 8 + x]) {
+                       case ' ':
+                               put_bit(0);
+                               break;
+                       case 'p':
+                               put_bit(1);
+                               put_bit(1);
+                               put_bit(1);
+                               break;
+                       case 'P':
+                               put_bit(1);
+                               put_bit(1);
+                               put_bit(0);
+                               break;
+                       case 'r':
+                               put_bit(1);
+                               put_bit(0);
+                               put_bit(1);
+                               put_bit(1);
+                               put_bit(1);
+                               break;
+                       case 'R':
+                               put_bit(1);
+                               put_bit(0);
+                               put_bit(1);
+                               put_bit(1);
+                               put_bit(0);
+                               break;
+                       case 'b':
+                               put_bit(1);
+                               put_bit(0);
+                               put_bit(1);
+                               put_bit(0);
+                               put_bit(1);
+                               break;
+                       case 'B':
+                               put_bit(1);
+                               put_bit(0);
+                               put_bit(1);
+                               put_bit(0);
+                               put_bit(0);
+                               break;
+                       case 'n':
+                               put_bit(1);
+                               put_bit(0);
+                               put_bit(0);
+                               put_bit(1);
+                               put_bit(1);
+                               break;
+                       case 'N':
+                               put_bit(1);
+                               put_bit(0);
+                               put_bit(0);
+                               put_bit(1);
+                               put_bit(0);
+                               break;
+                       case 'q':
+                               put_bit(1);
+                               put_bit(0);
+                               put_bit(0);
+                               put_bit(0);
+                               put_bit(1);
+                               put_bit(1);
+                               break;
+                       case 'Q':
+                               put_bit(1);
+                               put_bit(0);
+                               put_bit(0);
+                               put_bit(0);
+                               put_bit(1);
+                               put_bit(0);
+                               break;
+                       case 'k':
+                               put_bit(1);
+                               put_bit(0);
+                               put_bit(0);
+                               put_bit(0);
+                               put_bit(0);
+                               put_bit(1);
+                               break;
+                       case 'K':
+                               put_bit(1);
+                               put_bit(0);
+                               put_bit(0);
+                               put_bit(0);
+                               put_bit(0);
+                               put_bit(0);
+                               break;
+                       }
+               }
+       }
+
+       // en passant
+       if (strcmp(ep_column, "-") != 0) {
+               int epcn = ep_column[0] - 'a';
+
+               // only encode en passant if a capture is actually possible
+               if ((epcn > 0 && board[3*8 + epcn - 1] == 'P') ||
+                   (epcn < 7 && board[3*8 + epcn + 1] == 'P')) {
+                       ep_any = 1;
+
+                       put_bit(epcn & 0x80);
+                       put_bit(epcn & 0x40);
+                       put_bit(epcn & 0x20);
+                       put_bit(epcn & 0x10);
+                       put_bit(epcn & 0x08);
+                       put_bit(epcn & 0x04);
+                       put_bit(epcn & 0x02);
+                       put_bit(epcn & 0x01);
+               }
+       }
+
+       // really odd padding
+       if (bits_left > 4) {
+               int i, nb = bits_left - 4;
+               for (i = 0; i < nb; ++i) {
+                       //printf("spare bit\n");
+                       put_bit(0);
+               }
+       }
+       
+       // castling rights
+       if (strcmp(castling_rights, "-") != 0) {
+               if (invert) {
+                       put_bit(strchr(castling_rights, 'K') != NULL);
+                       put_bit(strchr(castling_rights, 'Q') != NULL);
+                       put_bit(strchr(castling_rights, 'k') != NULL);
+                       put_bit(strchr(castling_rights, 'q') != NULL);
+               } else {
+                       put_bit(strchr(castling_rights, 'k') != NULL);
+                       put_bit(strchr(castling_rights, 'q') != NULL);
+                       put_bit(strchr(castling_rights, 'K') != NULL);
+                       put_bit(strchr(castling_rights, 'Q') != NULL);
+               }
+       }
+
+       // padding stuff
+#if 1
+       if (bits_left != 8)
+               ++pos_len;
+#endif
+               
+       // and the header byte
+       position[0] = pos_len;
+
+       if (strcmp(castling_rights, "-") != 0)
+               position[0] |= 0x40;
+       if (ep_any)
+               position[0] |= 0x20;
+
+#if 1
+       // dump
+       {
+               int i;
+               for (i = 0; i < pos_len; ++i) {
+                       printf("%02x ", position[i]);
+               }
+               printf("\n");
+       }
+#endif
+}
+               
+int search_pos(unsigned c, char *result)
+{
+       char buf[4];
+       unsigned char pagebuf[4096];
+       unsigned page;
+       unsigned page_len;
+
+       lseek(cto_fd, c * 4 + 16, SEEK_SET);
+       
+       read(cto_fd, buf, 4);
+       page = htonl(*((unsigned *)buf));
+       if (page == -1)
+               return 0;
+
+       lseek(ctg_fd, page * 4096 + 4096, SEEK_SET);
+       read(ctg_fd, pagebuf, 4096);
+
+       // search the page
+       {
+               int pos = 4;
+               int page_end = htons(*((short *)(pagebuf + 2)));
+
+               while (pos < page_end) {
+                       if (pagebuf[pos] != position[0] ||
+                           memcmp(pagebuf + pos, position, pos_len) != 0) {
+                               // no match, skip through
+                               pos += pagebuf[pos] & 0x1f;
+                               pos += pagebuf[pos];
+                               pos += 33;
+                               continue;
+                       }
+                       pos += pagebuf[pos] & 0x1f;
+                       memcpy(result, pagebuf + pos, pagebuf[pos] + 33);
+                       return 1;
+               }
+       }
+
+       return 0;
+}
+
+int lookup_position(char *pos, unsigned len, char *result)
+{
+       int hash = gen_hash(position, pos_len);
+       int n;
+       
+       for (n = 0; n < 0x7fffffff; n = 2 * n + 1) {
+               unsigned c = (hash & n) + n;
+
+               // FIXME: adjust these bounds
+               if (c < 0x80e0)
+                       continue;
+
+               if (search_pos(c, result))
+                       return 1;
+               
+               if (c >= 0x1fd00)
+                       break;
+       }
+
+       return 0;
+}
+
+struct moveenc {
+       char encoding;
+       char piece;
+       int num;
+       int forward, right;
+};
+struct moveenc movetable[] = {
+       0x00, 'P', 5,  1,  1,
+       0x01, 'N', 2, -1, -2,
+       0x04, 'P', 2,  1,  0,
+       0x05, 'Q', 1,  1,  0,
+       0x06, 'P', 4,  1, -1,
+       0x09, 'B', 2,  6,  6,
+       0x0a, 'K', 1, -1,  0,
+       0x0c, 'P', 1,  1, -1,
+       0x0d, 'B', 1,  3,  3,
+       0x0e, 'R', 2,  0,  3,
+       0x0f, 'N', 1, -1, -2,
+       0x12, 'B', 1,  7,  7,
+       0x13, 'K', 1,  1,  0,
+       0x14, 'P', 8,  1,  1,
+       0x15, 'B', 1,  5,  5,
+       0x18, 'P', 7,  1,  0,
+       0x1b, 'B', 1,  1, -1,
+       0x1d, 'B', 2,  7,  7,
+       0x21, 'R', 2,  0,  7,
+       0x22, 'B', 2,  2, -2,
+       0x24, 'P', 8,  1, -1,
+       0x26, 'B', 1,  7, -7,
+       0x27, 'P', 3,  1, -1,
+       0x28, 'Q', 1,  5,  5,
+       0x29, 'Q', 1,  0,  6,
+       0x2a, 'N', 2, -2,  1,
+       0x2d, 'P', 6,  1,  1,
+       0x2e, 'B', 1,  1,  1,
+       0x2f, 'Q', 1,  0,  1,
+       0x30, 'N', 2, -2, -1,
+       0x31, 'Q', 1,  0,  3,
+       0x32, 'B', 2,  5,  5,
+       0x34, 'N', 1,  2,  1,
+       0x36, 'N', 1,  1,  2,
+       0x37, 'Q', 1,  4,  0,
+       0x39, 'Q', 1,  0,  5,
+       0x3a, 'B', 1,  6,  6,
+       0x3c, 'B', 1,  5, -5,
+       0x42, 'Q', 1,  7, -7,
+       0x44, 'K', 1, -1,  1,
+       0x45, 'Q', 1,  3,  3,
+       0x4a, 'P', 8,  2,  0,
+       0x4b, 'Q', 1,  5, -5,
+       0x4c, 'N', 2,  2,  1,
+       0x50, 'R', 1,  6,  0,
+       0x52, 'R', 1,  0,  6,
+       0x54, 'B', 2,  1, -1,
+       0x55, 'P', 3,  1,  0,
+       0x5c, 'P', 7,  1,  1,
+       0x5f, 'P', 5,  2,  0,
+       0x61, 'Q', 1,  6,  6,
+       0x62, 'P', 2,  2,  0,
+       0x66, 'B', 1,  3, -3,
+       0x67, 'K', 1,  1,  1,
+       0x69, 'R', 2,  7,  0,
+       0x6a, 'B', 1,  4,  4,
+       0x6b, 'K', 1,  0,  2,   /* short castling */
+       0x6e, 'R', 1,  0,  5,
+       0x72, 'B', 2,  7, -7,
+       0x74, 'Q', 1,  0,  2,
+       0x79, 'B', 2,  6, -6,
+       0x7a, 'R', 1,  3,  0,
+       0x7b, 'R', 2,  6,  0,
+       0x7c, 'P', 3,  1,  1,
+       0x7d, 'R', 2,  1,  0,
+       0x7e, 'Q', 1,  3, -3,
+       0x7f, 'R', 1,  0,  1,
+       0x80, 'Q', 1,  6, -6,
+       0x81, 'R', 1,  1,  0,
+       0x82, 'P', 6,  1, -1,
+       0x85, 'N', 1,  2, -1,
+       0x86, 'R', 1,  0,  7,
+       0x87, 'R', 1,  5,  0,
+       0x8a, 'N', 1, -2,  1,
+       0x8b, 'P', 1,  1,  1,
+       0x8c, 'K', 1, -1, -1,
+       0x8f, 'Q', 1,  0,  7,
+       0x94, 'Q', 1,  3,  0,
+       0x96, 'P', 2,  1,  1,
+       0x97, 'K', 1,  0, -1,
+       0x98, 'R', 1,  0,  3,
+       0x99, 'R', 1,  4,  0,
+       0x9a, 'Q', 1,  6,  0,
+       0x9b, 'P', 3,  2,  0,
+       0x9d, 'Q', 1,  2,  0,
+       0x9f, 'B', 2,  4, -4,
+       0xa2, 'Q', 1,  2,  2,
+       0xa3, 'P', 8,  1,  0,
+       0xa5, 'R', 2,  5,  0,
+       0xa9, 'R', 2,  0,  2,
+       0xad, 'R', 2,  0,  4,
+       0xb1, 'P', 6,  2,  0,
+       0xb2, 'B', 1,  6, -6,
+       0xb5, 'R', 2,  0,  5,
+       0xb7, 'Q', 1,  5,  0,
+       0xb9, 'B', 2,  3,  3,
+       0xbb, 'P', 5,  1,  0,
+       0xbe, 'K', 1,  0,  1,
+       0xc1, 'B', 1,  2,  2,
+       0xc2, 'B', 2,  2,  2,
+       0xc3, 'B', 1,  2, -2,
+       0xc4, 'R', 2,  0,  1,
+       0xc5, 'R', 2,  4,  0,
+       0xc7, 'P', 7,  1, -1,
+       0xc8, 'P', 7,  2,  0,
+       0xca, 'B', 2,  3, -3,
+       0xcb, 'P', 6,  1,  0,
+       0xcc, 'B', 2,  5, -5,
+       0xcd, 'R', 1,  0,  2,
+       0xcf, 'P', 4,  1,  0,
+       0xd1, 'P', 2,  1, -1,
+       0xd2, 'N', 2,  1,  2,
+       0xd3, 'N', 2,  1, -2,
+       0xd7, 'Q', 1,  1, -1,
+       0xd8, 'R', 2,  0,  6,
+       0xd9, 'Q', 1,  2, -2,
+       0xda, 'N', 1, -2, -1,
+       0xdb, 'P', 1,  2,  0,
+       0xde, 'P', 5,  1, -1,
+       0xdf, 'K', 1,  1, -1,
+       0xe0, 'N', 2, -1,  2,
+       0xe1, 'R', 1,  7,  0,
+       0xe3, 'R', 2,  3,  0,
+       0xe5, 'Q', 1,  0,  4,
+       0xe6, 'P', 4,  2,  0,
+       0xe7, 'Q', 1,  4,  4,
+       0xe8, 'R', 1,  2,  0,
+       0xe9, 'N', 1, -1,  2,
+       0xeb, 'P', 4,  1,  1,
+       0xec, 'P', 1,  1,  0,
+       0xed, 'Q', 1,  7,  7,
+       0xef, 'R', 1,  0,  4,
+       0xf1, 'Q', 1,  1,  1,
+       0xf3, 'N', 2,  2, -1,
+       0xf4, 'R', 2,  2,  0,
+       0xf5, 'B', 2,  1,  1,
+       0xf6, 'K', 1,  0, -2,   /* long castling */
+       0xf7, 'N', 1,  1, -2,
+       0xfd, 'Q', 1,  7,  0
+};
+
+int find_piece(char *board, char piece, int num)
+{
+       int y, x;
+       for (x = 0; x < 8; ++x) {
+               for (y = 0; y < 8; ++y) {
+                       if (board[(7-y) * 8 + x] != piece)
+                               continue;
+                       if (--num == 0)
+                               return (y * 8 + x);
+               }
+       }
+
+       fprintf(stderr, "Couldn't find piece '%c' number %u\n", piece, num);
+}
+
+void execute_move(char *board, char *castling_rights, int inverted, char *ep_square, int from_square, int to_square)
+{
+       int black_ks, black_qs, white_ks, white_qs;
+
+       // fudge
+       from_square = (7 - (from_square / 8)) * 8 + (from_square % 8);
+       to_square = (7 - (to_square / 8)) * 8 + (to_square % 8);
+
+       // compute the new castling rights
+       black_ks = (strchr(castling_rights, 'k') != NULL);
+       black_qs = (strchr(castling_rights, 'q') != NULL);
+       white_ks = (strchr(castling_rights, 'K') != NULL);
+       white_qs = (strchr(castling_rights, 'Q') != NULL);
+
+       if (board[from_square] == 'K') {
+               if (inverted)
+                       black_ks = black_qs = 0;
+               else
+                       white_ks = white_qs = 0;
+       } else if (board[from_square] == 'R') {
+               if (inverted) {
+                       if (from_square == 0) // a1
+                               black_qs = 0;
+                       else if (from_square == 7 * 8 + 0) // a8
+                               black_ks = 0;
+               } else {
+                       if (from_square == 0) // a1
+                               white_qs = 0;
+                       else if (from_square == 7 * 8 + 0) // a8
+                               white_ks = 0;
+               }
+       }
+
+       if ((black_ks | black_qs | white_ks | white_qs) == 0) {
+               strcpy(castling_rights, "-");
+       } else {
+               strcpy(castling_rights, "");
+
+               if (white_ks)
+                       strcat(castling_rights, "K");
+               if (white_qs)
+                       strcat(castling_rights, "Q");
+               if (black_ks)
+                       strcat(castling_rights, "k");
+               if (black_qs)
+                       strcat(castling_rights, "q");
+       }
+
+       // now the ep square
+       if (board[from_square] == 'P' && to_square - from_square == -16) {
+               sprintf(ep_square, "%c%u", "abcdefgh"[from_square % 8], from_square / 8 + 2);
+       } else {
+               strcpy(ep_square, "-");
+       }
+
+       // is this move an en passant capture?
+       if (board[from_square] == 'P' && board[to_square] == ' ' &&
+           (to_square - from_square == -9 || to_square - from_square == -7)) {
+               board[to_square + 8] = ' ';     
+       }
+
+       // make the move
+       board[to_square] = board[from_square];
+       board[from_square] = ' ';
+
+       if (board[to_square] == 'K' && to_square - from_square == 2) {
+               // short castling
+               board[to_square - 1] = 'R';
+               board[to_square + 1] = ' ';
+       } else if (board[to_square] == 'K' && to_square - from_square == -2) {
+               // long castling
+               board[to_square + 1] = 'R';
+               board[to_square - 2] = ' ';
+       }
+
+#if 0
+       // dump the board
+       {
+               int y, x;
+               printf("\n\n");
+               for (y = 0; y < 8; ++y) {
+                       for (x = 0; x < 8; ++x) {
+                               putchar(board[y * 8 + x]);
+                       }
+                       putchar('\n');
+               }
+       }
+       printf("cr='%s' ep='%s'\n", castling_rights, ep_square);
+#endif
+}
+
+void dump_move(char *board, char *castling_rights, char *ep_col, int invert, char move, char annotation)
+{
+       int i;
+       char newboard[64], nkr[5], neps[3];
+       for (i = 0; i < sizeof(movetable)/sizeof(movetable[0]); ++i) {
+               int from_square, from_row, from_col;
+               int to_square, to_row, to_col;
+               int ret;
+               char result[256];
+
+               if (move != movetable[i].encoding)
+                       continue;
+
+               from_square = find_piece(board, movetable[i].piece, movetable[i].num);
+               from_row = from_square / 8;
+               from_col = from_square % 8;
+
+               to_row = (from_row + 8 + movetable[i].forward) % 8;
+               to_col = (from_col + 8 + movetable[i].right) % 8;
+               to_square = to_row * 8 + to_col;
+
+               // output the move
+               if (invert)
+                       printf("%c%u%c%u,",
+                               "abcdefgh"[from_square % 8], (7 - from_square / 8) + 1,
+                               "abcdefgh"[to_square % 8], (7 - to_square / 8) + 1);
+               else
+                       printf("%c%u%c%u,",
+                               "abcdefgh"[from_square % 8], from_square / 8 + 1,
+                               "abcdefgh"[to_square % 8], to_square / 8 + 1);
+
+               // annotation
+               switch (annotation) {
+               case 0x00:
+                       break;
+               case 0x01:
+                       printf("!");
+                       break;
+               case 0x02:
+                       printf("?");
+                       break;
+               case 0x03:
+                       printf("!!");
+                       break;
+               case 0x04:
+                       printf("??");
+                       break;
+               case 0x05:
+                       printf("!?");
+                       break;
+               case 0x06:
+                       printf("?!");
+                       break;
+               case 0x08:
+                       printf(" (only move)");
+                       break;
+               case 0x16:
+                       printf(" (zugzwang)");
+                       break;
+               default:
+                       printf(" (unknown status 0x%02x)", annotation);
+               }
+               printf(",");
+
+               // do the move, and look up the new position
+               memcpy(newboard, board, 64);
+               strcpy(nkr, castling_rights);
+               execute_move(newboard, nkr, invert, neps, from_square, to_square);
+               invert_board(newboard);
+       
+               encode_position(newboard, !invert, nkr, neps);
+               ret = lookup_position(position, pos_len, result);
+               if (!ret) {
+                       fprintf(stderr, "Destination move not found in book.\n");
+                       exit(1);
+               }
+
+               output_stats(result, invert);
+               return;
+       }
+
+       fprintf(stderr, "ERROR: Unknown move 0x%02x\n", move);
+}
+
+void dump_info(char *board, char *castling_rights, char *ep_col, int invert, char *result)
+{
+       int book_moves = result[0] >> 1;
+       int i;
+               
+       printf(",,");   
+       output_stats(result, !invert);
+
+       for (i = 0; i < book_moves; ++i) {
+               dump_move(board, castling_rights, ep_col, invert, result[i * 2 + 1], result[i * 2 + 2]);
+       }
+}
+
+int main(int argc, char **argv)
+{
+       // encode the position
+       char board[64], result[256];
+       int invert = 0;
+       int ret;
+       
+       ctg_fd = open("RybkaII.ctg", O_RDONLY);
+       cto_fd = open("RybkaII.cto", O_RDONLY);
+       ctb_fd = open("RybkaII.ctb", O_RDONLY);
+       decode_fen_board(argv[1], board);
+
+       // always from white's position
+       if (argv[2][0] == 'b') {
+               invert = 1;
+               invert_board(board);
+       }
+
+#if 0
+       // dump the board
+       {
+               int y, x;
+               for (y = 0; y < 8; ++y) {
+                       for (x = 0; x < 8; ++x) {
+                               putchar(board[y * 8 + x]);
+                       }
+                       putchar('\n');
+               }
+       }
+#endif
+
+       encode_position(board, invert, argv[3], argv[4]);
+       ret = lookup_position(position, pos_len, result);
+       if (!ret) {
+               printf("Not found in book.\n");
+               exit(1);
+       }
+
+       dump_info(board, argv[3], argv[4], invert, result);
+}
+
index 16a4f8d..655a9ae 100755 (executable)
@@ -18,9 +18,10 @@ use warnings;
 
 # Configuration
 my $server = "freechess.org";
-my $target = "224";
+my $target = "Sessse";
 # my $engine = "/usr/games/toga2";
-my $engine = "wine Rybkav2.3.2a.mp.w32.exe";
+# my $engine = "wine Rybkav2.3.2a.mp.w32.exe";
+my $engine = "~/microwine-0.2/microwine Rybkav2.3.2a.mp.x64.exe";
 my $telltarget = undef;   # undef to be silent
 my @tell_intervals = (5, 20, 60, 120, 240, 480, 960);  # after each move
 my $uci_assume_full_compliance = 1;                    # dangerous :-)
@@ -67,10 +68,10 @@ while (<UCIREAD>) {
 
 uciprint("setoption name UCI_AnalyseMode value true");
 # uciprint("setoption name Preserve Analysis value true");
-uciprint("setoption name NalimovPath value c:\\nalimov");
+uciprint("setoption name NalimovPath value /srv/tablebase");
 uciprint("setoption name NalimovUsage value Rarely");
 uciprint("setoption name Hash value 1024");
-uciprint("setoption name MultiPV value 3");
+uciprint("setoption name MultiPV value 2");
 # uciprint("setoption name Contempt value 1000");
 # uciprint("setoption name Outlook value Ultra Optimistic");
 uciprint("ucinewgame");
@@ -382,7 +383,7 @@ sub style12_to_fen {
 
 sub prettyprint_pv {
        my ($board, @pvs) = @_;
-       
+
        if (scalar @pvs == 0 || !defined($pvs[0])) {
                return ();
        }
@@ -652,6 +653,8 @@ sub output_screen {
                $text .=  "\n\n";
        }
 
+       $text .= book_info($pos_calculating->{'fen'}, $pos_calculating->{'board'}, $pos_calculating->{'toplay'});
+
        if ($last_text ne $text) {
                print "\e[H\e[2J"; # clear the screen
                print $text;
@@ -953,3 +956,55 @@ sub long_score {
 
        return undef;
 }
+
+my %book_cache = ();
+sub book_info {
+       my ($fen, $board, $toplay) = @_;
+
+       if (exists($book_cache{$fen})) {
+               return $book_cache{$fen};
+       }
+
+       my $ret = `./booklook $fen`;
+       return "[$fen]" if ($ret =~ /Not found/ || $ret eq '');
+
+       my @moves = ();
+
+       for my $m (split /\n/, $ret) {
+               my ($move, $annotation, $win, $draw, $lose, $rating, $rating_div) = split /,/, $m;
+
+               my $pmove;
+               if ($move eq '')  {
+                       $pmove = '(current)';
+               } else {
+                       ($pmove) = prettyprint_pv($board, $move);
+                       $pmove .= $annotation;
+               }
+
+               my $score;
+               if ($toplay eq 'W') {
+                       $score = 1.0 * $win + 0.5 * $draw + 0.0 * $lose;
+               } else {
+                       $score = 0.0 * $win + 0.5 * $draw + 1.0 * $lose;
+               }
+               my $n = $win + $draw + $lose;
+               
+               my $percent;
+               if ($n == 0) {
+                       $percent = "     ";
+               } else {
+                       $percent = sprintf "%4u%%", int(100.0 * $score / $n + 0.5);
+               }
+
+               push @moves, [ $pmove, $n, $percent, $rating ];
+       }
+
+       @moves[1..$#moves] = sort { $b->[2] cmp $a->[2] } @moves[1..$#moves];
+       
+       my $text = "Book moves:\n\n              Perf.     N     Rating\n\n";
+       for my $m (@moves) {
+               $text .= sprintf "  %-10s %s   %6u    %4s\n", $m->[0], $m->[2], $m->[1], $m->[3]
+       }
+
+       return $text;
+}