fen_to_tty.c - chess-puzzles - chess puzzle book generator
 (HTM) git clone git://git.codemadness.org/chess-puzzles
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
       fen_to_tty.c (7357B)
       ---
            1 /* TODO: option to flip board? */
            2 
            3 #include <ctype.h>
            4 #include <stdio.h>
            5 #include <string.h>
            6 
            7 static char board[8][8];
            8 static char highlight[8][8];
            9 
           10 static int side_to_move = 'w'; /* default: white to move */
           11 static int white_can_castle[2] = { 0, 0 }; /* allow king side, allow queen side */
           12 static int black_can_castle[2] = { 0, 0 }; /* allow king side, allow queen side */
           13 
           14 static const int showcoords = 1; /* config: show board coordinates? */
           15 
           16 #define SETFGCOLOR(r,g,b)    printf("\x1b[38;2;%d;%d;%dm", r, g, b)
           17 #define SETBGCOLOR(r,g,b)    printf("\x1b[48;2;%d;%d;%dm", r, g, b)
           18 
           19 int
           20 isvalidsquare(int x, int y)
           21 {
           22         return !(x < 0 || x >= 8 || y < 0 || y >= 8);
           23 }
           24 
           25 /* place a piece, if possible */
           26 void
           27 place(int piece, int x, int y)
           28 {
           29         if (!isvalidsquare(x, y))
           30                 return;
           31 
           32         board[y][x] = piece;
           33 }
           34 
           35 /* get piece, if possible */
           36 int
           37 getpiece(int x, int y)
           38 {
           39         if (!isvalidsquare(x, y))
           40                 return 0;
           41         return board[y][x];
           42 }
           43 
           44 int
           45 squaretoxy(const char *s, int *x, int *y)
           46 {
           47         if (*s >= 'a' && *s <= 'h' &&
           48             *(s + 1) >= '1' && *(s + 1) <= '8') {
           49                 *x = *s - 'a';
           50                 *y = '8' - *(s + 1);
           51                 return 1;
           52         }
           53         return 0;
           54 }
           55 
           56 void
           57 highlightmove(int x1, int y1, int x2, int y2)
           58 {
           59         if (isvalidsquare(x1, y1))
           60                 highlight[y1][x1] = 1;
           61 
           62         if (isvalidsquare(x2, y2))
           63                 highlight[y2][x2] = 1;
           64 }
           65 
           66 void
           67 showpiece(int c)
           68 {
           69         const char *s = "";
           70 
           71         /* simple or use unicode character */
           72 #if 0
           73         putchar(c);
           74         return;
           75 #endif
           76 
           77         switch (c) {
           78         case 'K': s = "♔"; break;
           79         case 'Q': s = "♕"; break;
           80         case 'R': s = "♖"; break;
           81         case 'B': s = "♗"; break;
           82         case 'N': s = "♘"; break;
           83         case 'P': s = "♙"; break;
           84         case 'k': s = "♚"; break;
           85         case 'q': s = "♛"; break;
           86         case 'r': s = "♜"; break;
           87         case 'b': s = "♝"; break;
           88         case 'n': s = "♞"; break;
           89         case 'p': s = "♟"; break;
           90         }
           91 
           92         if (*s)
           93                 fputs(s, stdout);
           94 }
           95 
           96 void
           97 showboardfen(void)
           98 {
           99         int x, y, piece, skip = 0;
          100 
          101         for (y = 0; y < 8; y++) {
          102                 if (y > 0)
          103                         putchar('/');
          104                 skip = 0;
          105                 for (x = 0; x < 8; x++) {
          106                         piece = getpiece(x, y);
          107                         if (piece) {
          108                                 if (skip)
          109                                         putchar(skip + '0');
          110                                 putchar(piece);
          111                                 skip = 0;
          112                         } else {
          113                                 skip++;
          114                         }
          115                 }
          116                 if (skip)
          117                         putchar(skip + '0');
          118         }
          119 
          120         /* ? TODO: detect en passant, invalid castling etc? */
          121 }
          122 
          123 /* show board */
          124 void
          125 showboard(void)
          126 {
          127         int *color;
          128         int border[] = { 0x70, 0x49, 0x2d };
          129         int darksquare[] = { 0xb5, 0x88, 0x63 };
          130         int lightsquare[] = { 0xf0, 0xd9, 0xb5 };
          131         int darksquarehi[] = { 0xaa, 0xa2, 0x3a };
          132         int lightsquarehi[] = { 0xcd, 0xd2, 0x6a };
          133         int x, y, piece;
          134 
          135         printf("Board FEN:\n");
          136         showboardfen();
          137         printf("\n\n");
          138 
          139         SETFGCOLOR(0x00, 0x00, 0x00);
          140 
          141         color = border;
          142         SETBGCOLOR(color[0], color[1], color[2]);
          143         SETFGCOLOR(0xff, 0xff, 0xff);
          144         fputs("                             ", stdout);
          145         printf("\x1b[0m"); /* reset */
          146         SETFGCOLOR(0x00, 0x00, 0x00);
          147         putchar('\n');
          148 
          149         for (y = 0; y < 8; y++) {
          150                 color = border;
          151                 SETBGCOLOR(color[0], color[1], color[2]);
          152                 SETFGCOLOR(0xff, 0xff, 0xff);
          153                 fputs("  ", stdout);
          154 
          155                 for (x = 0; x < 8; x++) {
          156                         if (x % 2 == 0) {
          157                                 if (y % 2 == 0)
          158                                         color = highlight[y][x] ? lightsquarehi : lightsquare;
          159                                 else
          160                                         color = highlight[y][x] ? darksquarehi : darksquare;
          161                         } else {
          162                                 if (y % 2 == 0)
          163                                         color = highlight[y][x] ? darksquarehi : darksquare;
          164                                 else
          165                                         color = highlight[y][x] ? lightsquarehi : lightsquare;
          166                         }
          167                         SETBGCOLOR(color[0], color[1], color[2]);
          168 
          169                         fputs(" ", stdout);
          170                         piece = getpiece(x, y);
          171                         if (piece) {
          172                                 if (piece >= 'A' && piece <= 'Z')
          173                                         SETFGCOLOR(0xff, 0xff, 0xff);
          174                                 else
          175                                         SETFGCOLOR(0x00, 0x00, 0x00);
          176                                 /* workaround: use black chess symbol, because the color
          177                                    is filled and better visible */
          178                                 showpiece(tolower(piece));
          179                         } else {
          180                                 fputs(" ", stdout);
          181                         }
          182                         fputs(" ", stdout);
          183                 }
          184                 printf("\x1b[0m"); /* reset */
          185 
          186                 color = border;
          187                 SETBGCOLOR(color[0], color[1], color[2]);
          188                 SETFGCOLOR(0xff, 0xff, 0xff);
          189                 if (showcoords) {
          190                         putchar(' ');
          191                         putchar('8' - y);
          192                         putchar(' ');
          193                 } else {
          194                         fputs("   ", stdout);
          195                 }
          196 
          197                 printf("\x1b[0m"); /* reset */
          198                 SETFGCOLOR(0x00, 0x00, 0x00);
          199                 putchar('\n');
          200         }
          201         color = border;
          202         SETBGCOLOR(color[0], color[1], color[2]);
          203         SETFGCOLOR(0xff, 0xff, 0xff);
          204         if (showcoords)
          205                 fputs("   a  b  c  d  e  f  g  h    ", stdout);
          206         else
          207                 fputs("                             ", stdout);
          208         printf("\x1b[0m"); /* reset */
          209         printf("\n");
          210         printf("\x1b[0m"); /* reset */
          211 
          212 #if 0
          213         if (side_to_move == 'w') {
          214                 fputs("White to move\n", stdout);
          215         } else if (side_to_move == 'b')
          216                 fputs("Black to move\n", stdout);
          217 
          218         if (white_can_castle[0])
          219                 fputs("White can castle king side\n", stdout);
          220         if (white_can_castle[1])
          221                 fputs("White can castle queen side\n", stdout);
          222         if (black_can_castle[0])
          223                 fputs("Black can castle king side\n", stdout);
          224         if (black_can_castle[1])
          225                 fputs("Black can castle queen side\n", stdout);
          226 #endif
          227 }
          228 
          229 int
          230 main(int argc, char *argv[])
          231 {
          232         const char *fen, *moves, *s;
          233         int x, y, x2, y2, field, piece;
          234         char pieces[] = "PNBRQKpnbrqk", square[3];
          235 
          236         if (argc != 3) {
          237                 fprintf(stderr, "usage: %s <FEN> <moves>\n", argv[0]);
          238                 return 1;
          239         }
          240 
          241         fen = argv[1];
          242         moves = argv[2];
          243 
          244         /* initial board state, FEN format */
          245         x = y = field = 0;
          246         for (s = fen; *s; s++) {
          247                 /* next field, fields are: piece placement data, active color,
          248                    Castling availability, En passant target square,
          249                    Halfmove clock, Fullmove number */
          250                 if (*s == ' ') {
          251                         field++;
          252                         continue;
          253                 }
          254 
          255                 switch (field) {
          256                 case 0: /* piece placement data */
          257                         /* skip square */
          258                         if (*s >= '1' && *s <= '9') {
          259                                 x += (*s - '0');
          260                                 continue;
          261                         }
          262                         /* next rank */
          263                         if (*s == '/') {
          264                                 x = 0;
          265                                 y++;
          266                                 continue;
          267                         }
          268                         /* is piece? place it */
          269                         if (strchr(pieces, *s))
          270                                 place(*s, x++, y);
          271                         break;
          272                 case 1: /* active color */
          273                         if (*s == 'w' || *s == 'b')
          274                                 side_to_move = *s;
          275                         break;
          276                 case 2: /* castling availability */
          277                         if (*s == '-') {
          278                                 white_can_castle[0] = 0;
          279                                 white_can_castle[1] = 0;
          280                                 black_can_castle[0] = 0;
          281                                 black_can_castle[1] = 0;
          282                         } else if (*s == 'K') {
          283                                 white_can_castle[0] = 1;
          284                         } else if (*s == 'Q') {
          285                                 white_can_castle[1] = 1;
          286                         } else if (*s == 'k') {
          287                                 black_can_castle[0] = 1;
          288                         } else if (*s == 'q') {
          289                                 black_can_castle[1] = 1;
          290                         }
          291                         break;
          292                 case 3: /* TODO: en-passant square, rest of the fields */
          293                         break;
          294                 }
          295                 /* TODO: parse which side to move, en-passant, etc */
          296         }
          297 
          298         /* process moves */
          299         square[2] = '\0';
          300         x = y = x2 = y2 = -1;
          301         for (s = moves; *s; s++) {
          302                 if (*s == ' ')
          303                         continue;
          304                 if ((*s >= 'a' && *s <= 'h') &&
          305                     (*(s + 1) >= '1' && *(s + 1) <= '8') &&
          306                     (*(s + 2) >= 'a' && *(s + 2) <= 'h') &&
          307                     (*(s + 3) >= '1' && *(s + 3) <= '8')) {
          308                         square[0] = *s;
          309                         square[1] = *(s + 1);
          310 
          311                         s += 2;
          312                         squaretoxy(square, &x, &y);
          313                         piece = getpiece(x, y);
          314 
          315                         place(0, x, y); /* clear square */
          316 
          317                         /* place piece at new location */
          318                         square[0] = *s;
          319                         square[1] = *(s + 1);
          320                         squaretoxy(square, &x2, &y2);
          321                         place(piece, x2, y2);
          322                         s += 2;
          323 
          324                         /* possible promotion? (queen, knight, bishop) */
          325                         if (*s == 'q' || *s == 'n' || *s == 'b') {
          326                                 if (side_to_move == 'w')
          327                                         piece = toupper(*s);
          328                                 else
          329                                         piece = *s;
          330                                 place(piece, x2, y2);
          331                                 s++;
          332                         }
          333 
          334                         /* switch which side it is to move */
          335                         side_to_move = side_to_move == 'b' ? 'w' : 'b';
          336                 }
          337         }
          338         /* highlight last move */
          339         highlightmove(x, y, x2, y2);
          340 
          341         showboard();
          342 
          343         printf("\x1b[0m"); /* reset */
          344 
          345         return 0;
          346 }