fen_to_ascii.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_ascii.c (5802B)
       ---
            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 int
           17 isvalidsquare(int x, int y)
           18 {
           19         return !(x < 0 || x >= 8 || y < 0 || y >= 8);
           20 }
           21 
           22 /* place a piece, if possible */
           23 void
           24 place(int piece, int x, int y)
           25 {
           26         if (!isvalidsquare(x, y))
           27                 return;
           28 
           29         board[y][x] = piece;
           30 }
           31 
           32 /* get piece, if possible */
           33 int
           34 getpiece(int x, int y)
           35 {
           36         if (!isvalidsquare(x, y))
           37                 return 0;
           38         return board[y][x];
           39 }
           40 
           41 int
           42 squaretoxy(const char *s, int *x, int *y)
           43 {
           44         if (*s >= 'a' && *s <= 'h' &&
           45             *(s + 1) >= '1' && *(s + 1) <= '8') {
           46                 *x = *s - 'a';
           47                 *y = '8' - *(s + 1);
           48                 return 1;
           49         }
           50         return 0;
           51 }
           52 
           53 void
           54 highlightmove(int x1, int y1, int x2, int y2)
           55 {
           56         if (isvalidsquare(x1, y1))
           57                 highlight[y1][x1] = 1;
           58 
           59         if (isvalidsquare(x2, y2))
           60                 highlight[y2][x2] = 1;
           61 }
           62 
           63 void
           64 showpiece(int c)
           65 {
           66         const char *s = "";
           67 
           68         /* simple or use unicode character */
           69 #if 1
           70         putchar(c);
           71         return;
           72 #endif
           73 
           74         switch (c) {
           75         case 'K': s = "♔"; break;
           76         case 'Q': s = "♕"; break;
           77         case 'R': s = "♖"; break;
           78         case 'B': s = "♗"; break;
           79         case 'N': s = "♘"; break;
           80         case 'P': s = "♙"; break;
           81         case 'k': s = "♚"; break;
           82         case 'q': s = "♛"; break;
           83         case 'r': s = "♜"; break;
           84         case 'b': s = "♝"; break;
           85         case 'n': s = "♞"; break;
           86         case 'p': s = "♟"; break;
           87         }
           88 
           89         if (*s)
           90                 fputs(s, stdout);
           91 }
           92 
           93 void
           94 showboardfen(void)
           95 {
           96         int x, y, piece, skip = 0;
           97 
           98         for (y = 0; y < 8; y++) {
           99                 if (y > 0)
          100                         putchar('/');
          101                 skip = 0;
          102                 for (x = 0; x < 8; x++) {
          103                         piece = getpiece(x, y);
          104                         if (piece) {
          105                                 if (skip)
          106                                         putchar(skip + '0');
          107                                 putchar(piece);
          108                                 skip = 0;
          109                         } else {
          110                                 skip++;
          111                         }
          112                 }
          113                 if (skip)
          114                         putchar(skip + '0');
          115         }
          116 
          117         /* ? TODO: detect en passant, invalid castling etc? */
          118 }
          119 
          120 /* show board */
          121 /* TODO: show fancier, unicode and background square color */
          122 /* TODO: use the output format similar to stockfish "d" command */
          123 void
          124 showboard(void)
          125 {
          126         int x, y, piece;
          127 
          128         printf("Board FEN:\n");
          129         showboardfen();
          130         printf("\n\n");
          131 
          132         for (y = 0; y < 8; y++) {
          133                 printf("+---+---+---+---+---+---+---+---+\n");
          134                 for (x = 0; x < 8; x++) {
          135                         if (x == 0)
          136                                 putchar('|');
          137                         fputs(" ", stdout);
          138                         piece = getpiece(x, y);
          139                         if (piece)
          140                                 showpiece(piece);
          141                         else
          142                                 fputs(" ", stdout);
          143                         fputs(" ", stdout);
          144                         putchar('|');
          145                 }
          146                 if (showcoords) {
          147                         putchar(' ');
          148                         putchar('8' - y);
          149                 }
          150                 putchar('\n');
          151         }
          152         printf("+---+---+---+---+---+---+---+---+\n");
          153         if (showcoords)
          154                 printf("  a | b | c | d | e | f | g | h |\n");
          155 
          156         fputs("\n", stdout);
          157 
          158 #if 0
          159         if (side_to_move == 'w') {
          160                 fputs("White to move\n", stdout);
          161         } else if (side_to_move == 'b')
          162                 fputs("Black to move\n", stdout);
          163 
          164         if (white_can_castle[0])
          165                 fputs("White can castle king side\n", stdout);
          166         if (white_can_castle[1])
          167                 fputs("White can castle queen side\n", stdout);
          168         if (black_can_castle[0])
          169                 fputs("Black can castle king side\n", stdout);
          170         if (black_can_castle[1])
          171                 fputs("Black can castle queen side\n", stdout);
          172 #endif
          173 }
          174 
          175 int
          176 main(int argc, char *argv[])
          177 {
          178         const char *fen, *moves, *s;
          179         int x, y, x2, y2, field, piece;
          180         char pieces[] = "PNBRQKpnbrqk", square[3];
          181 
          182         if (argc != 3) {
          183                 fprintf(stderr, "usage: %s <FEN> <moves>\n", argv[0]);
          184                 return 1;
          185         }
          186 
          187         fen = argv[1];
          188         moves = argv[2];
          189 
          190         /* initial board state, FEN format */
          191         x = y = field = 0;
          192         for (s = fen; *s; s++) {
          193                 /* next field, fields are: piece placement data, active color,
          194                    Castling availability, En passant target square,
          195                    Halfmove clock, Fullmove number */
          196                 if (*s == ' ') {
          197                         field++;
          198                         continue;
          199                 }
          200 
          201                 switch (field) {
          202                 case 0: /* piece placement data */
          203                         /* skip square */
          204                         if (*s >= '1' && *s <= '9') {
          205                                 x += (*s - '0');
          206                                 continue;
          207                         }
          208                         /* next rank */
          209                         if (*s == '/') {
          210                                 x = 0;
          211                                 y++;
          212                                 continue;
          213                         }
          214                         /* is piece? place it */
          215                         if (strchr(pieces, *s))
          216                                 place(*s, x++, y);
          217                         break;
          218                 case 1: /* active color */
          219                         if (*s == 'w' || *s == 'b')
          220                                 side_to_move = *s;
          221                         break;
          222                 case 2: /* castling availability */
          223                         if (*s == '-') {
          224                                 white_can_castle[0] = 0;
          225                                 white_can_castle[1] = 0;
          226                                 black_can_castle[0] = 0;
          227                                 black_can_castle[1] = 0;
          228                         } else if (*s == 'K') {
          229                                 white_can_castle[0] = 1;
          230                         } else if (*s == 'Q') {
          231                                 white_can_castle[1] = 1;
          232                         } else if (*s == 'k') {
          233                                 black_can_castle[0] = 1;
          234                         } else if (*s == 'q') {
          235                                 black_can_castle[1] = 1;
          236                         }
          237                         break;
          238                 case 3: /* TODO: en-passant square, rest of the fields */
          239                         break;
          240                 }
          241                 /* TODO: parse which side to move, en-passant, etc */
          242         }
          243 
          244         /* process moves */
          245         square[2] = '\0';
          246         x = y = x2 = y2 = -1;
          247         for (s = moves; *s; s++) {
          248                 if (*s == ' ')
          249                         continue;
          250                 if ((*s >= 'a' && *s <= 'h') &&
          251                     (*(s + 1) >= '1' && *(s + 1) <= '8') &&
          252                     (*(s + 2) >= 'a' && *(s + 2) <= 'h') &&
          253                     (*(s + 3) >= '1' && *(s + 3) <= '8')) {
          254                         square[0] = *s;
          255                         square[1] = *(s + 1);
          256 
          257                         s += 2;
          258                         squaretoxy(square, &x, &y);
          259                         piece = getpiece(x, y);
          260 
          261                         place(0, x, y); /* clear square */
          262 
          263                         /* place piece at new location */
          264                         square[0] = *s;
          265                         square[1] = *(s + 1);
          266                         squaretoxy(square, &x2, &y2);
          267                         place(piece, x2, y2);
          268                         s += 2;
          269 
          270                         /* possible promotion? (queen, knight, bishop) */
          271                         if (*s == 'q' || *s == 'n' || *s == 'b') {
          272                                 if (side_to_move == 'w')
          273                                         piece = toupper(*s);
          274                                 else
          275                                         piece = *s;
          276                                 place(piece, x2, y2);
          277                                 s++;
          278                         }
          279 
          280                         /* switch which side it is to move */
          281                         side_to_move = side_to_move == 'b' ? 'w' : 'b';
          282                 }
          283         }
          284         /* highlight last move */
          285         highlightmove(x, y, x2, y2);
          286 
          287         showboard();
          288 
          289         return 0;
          290 }