merge code together, symlink binaries - 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
       ---
 (DIR) commit d7273cde403340578a406a58fc419ae03277a84f
 (DIR) parent 318de62766d2fd0caa0594f939cd1b2d9d143e0a
 (HTM) Author: Hiltjo Posthuma <hiltjo@codemadness.org>
       Date:   Tue, 19 Dec 2023 00:49:17 +0100
       
       merge code together, symlink binaries
       
       Diffstat:
         M Makefile                            |       4 ++--
         D fen_to_ascii.c                      |     290 -------------------------------
         M fen_to_svg.c                        |     260 +++++++++++++++++++++++++++----
         D fen_to_tty.c                        |     346 -------------------------------
       
       4 files changed, 228 insertions(+), 672 deletions(-)
       ---
 (DIR) diff --git a/Makefile b/Makefile
       @@ -1,7 +1,7 @@
        build: clean
                ${CC} -o fen_to_svg fen_to_svg.c ${CFLAGS} ${LDFLAGS}
       -        ${CC} -o fen_to_ascii fen_to_ascii.c ${CFLAGS} ${LDFLAGS}
       -        ${CC} -o fen_to_tty fen_to_tty.c ${CFLAGS} ${LDFLAGS}
       +        ln -s fen_to_svg fen_to_ascii
       +        ln -s fen_to_svg fen_to_tty
        
        db:
                rm -f lichess_db_puzzle.csv.zst lichess_db_puzzle.csv
 (DIR) diff --git a/fen_to_ascii.c b/fen_to_ascii.c
       @@ -1,290 +0,0 @@
       -/* TODO: option to flip board? */
       -
       -#include <ctype.h>
       -#include <stdio.h>
       -#include <string.h>
       -
       -static char board[8][8];
       -static char highlight[8][8];
       -
       -static int side_to_move = 'w'; /* default: white to move */
       -static int white_can_castle[2] = { 0, 0 }; /* allow king side, allow queen side */
       -static int black_can_castle[2] = { 0, 0 }; /* allow king side, allow queen side */
       -
       -static const int showcoords = 1; /* config: show board coordinates? */
       -
       -int
       -isvalidsquare(int x, int y)
       -{
       -        return !(x < 0 || x >= 8 || y < 0 || y >= 8);
       -}
       -
       -/* place a piece, if possible */
       -void
       -place(int piece, int x, int y)
       -{
       -        if (!isvalidsquare(x, y))
       -                return;
       -
       -        board[y][x] = piece;
       -}
       -
       -/* get piece, if possible */
       -int
       -getpiece(int x, int y)
       -{
       -        if (!isvalidsquare(x, y))
       -                return 0;
       -        return board[y][x];
       -}
       -
       -int
       -squaretoxy(const char *s, int *x, int *y)
       -{
       -        if (*s >= 'a' && *s <= 'h' &&
       -            *(s + 1) >= '1' && *(s + 1) <= '8') {
       -                *x = *s - 'a';
       -                *y = '8' - *(s + 1);
       -                return 1;
       -        }
       -        return 0;
       -}
       -
       -void
       -highlightmove(int x1, int y1, int x2, int y2)
       -{
       -        if (isvalidsquare(x1, y1))
       -                highlight[y1][x1] = 1;
       -
       -        if (isvalidsquare(x2, y2))
       -                highlight[y2][x2] = 1;
       -}
       -
       -void
       -showpiece(int c)
       -{
       -        const char *s = "";
       -
       -        /* simple or use unicode character */
       -#if 1
       -        putchar(c);
       -        return;
       -#endif
       -
       -        switch (c) {
       -        case 'K': s = "♔"; break;
       -        case 'Q': s = "♕"; break;
       -        case 'R': s = "♖"; break;
       -        case 'B': s = "♗"; break;
       -        case 'N': s = "♘"; break;
       -        case 'P': s = "♙"; break;
       -        case 'k': s = "♚"; break;
       -        case 'q': s = "♛"; break;
       -        case 'r': s = "♜"; break;
       -        case 'b': s = "♝"; break;
       -        case 'n': s = "♞"; break;
       -        case 'p': s = "♟"; break;
       -        }
       -
       -        if (*s)
       -                fputs(s, stdout);
       -}
       -
       -void
       -showboardfen(void)
       -{
       -        int x, y, piece, skip = 0;
       -
       -        for (y = 0; y < 8; y++) {
       -                if (y > 0)
       -                        putchar('/');
       -                skip = 0;
       -                for (x = 0; x < 8; x++) {
       -                        piece = getpiece(x, y);
       -                        if (piece) {
       -                                if (skip)
       -                                        putchar(skip + '0');
       -                                putchar(piece);
       -                                skip = 0;
       -                        } else {
       -                                skip++;
       -                        }
       -                }
       -                if (skip)
       -                        putchar(skip + '0');
       -        }
       -
       -        /* ? TODO: detect en passant, invalid castling etc? */
       -}
       -
       -/* show board */
       -/* TODO: show fancier, unicode and background square color */
       -/* TODO: use the output format similar to stockfish "d" command */
       -void
       -showboard(void)
       -{
       -        int x, y, piece;
       -
       -        printf("Board FEN:\n");
       -        showboardfen();
       -        printf("\n\n");
       -
       -        for (y = 0; y < 8; y++) {
       -                printf("+---+---+---+---+---+---+---+---+\n");
       -                for (x = 0; x < 8; x++) {
       -                        if (x == 0)
       -                                putchar('|');
       -                        fputs(" ", stdout);
       -                        piece = getpiece(x, y);
       -                        if (piece)
       -                                showpiece(piece);
       -                        else
       -                                fputs(" ", stdout);
       -                        fputs(" ", stdout);
       -                        putchar('|');
       -                }
       -                if (showcoords) {
       -                        putchar(' ');
       -                        putchar('8' - y);
       -                }
       -                putchar('\n');
       -        }
       -        printf("+---+---+---+---+---+---+---+---+\n");
       -        if (showcoords)
       -                printf("  a | b | c | d | e | f | g | h |\n");
       -
       -        fputs("\n", stdout);
       -
       -#if 0
       -        if (side_to_move == 'w') {
       -                fputs("White to move\n", stdout);
       -        } else if (side_to_move == 'b')
       -                fputs("Black to move\n", stdout);
       -
       -        if (white_can_castle[0])
       -                fputs("White can castle king side\n", stdout);
       -        if (white_can_castle[1])
       -                fputs("White can castle queen side\n", stdout);
       -        if (black_can_castle[0])
       -                fputs("Black can castle king side\n", stdout);
       -        if (black_can_castle[1])
       -                fputs("Black can castle queen side\n", stdout);
       -#endif
       -}
       -
       -int
       -main(int argc, char *argv[])
       -{
       -        const char *fen, *moves, *s;
       -        int x, y, x2, y2, field, piece;
       -        char pieces[] = "PNBRQKpnbrqk", square[3];
       -
       -        if (argc != 3) {
       -                fprintf(stderr, "usage: %s <FEN> <moves>\n", argv[0]);
       -                return 1;
       -        }
       -
       -        fen = argv[1];
       -        moves = argv[2];
       -
       -        /* initial board state, FEN format */
       -        x = y = field = 0;
       -        for (s = fen; *s; s++) {
       -                /* next field, fields are: piece placement data, active color,
       -                   Castling availability, En passant target square,
       -                   Halfmove clock, Fullmove number */
       -                if (*s == ' ') {
       -                        field++;
       -                        continue;
       -                }
       -
       -                switch (field) {
       -                case 0: /* piece placement data */
       -                        /* skip square */
       -                        if (*s >= '1' && *s <= '9') {
       -                                x += (*s - '0');
       -                                continue;
       -                        }
       -                        /* next rank */
       -                        if (*s == '/') {
       -                                x = 0;
       -                                y++;
       -                                continue;
       -                        }
       -                        /* is piece? place it */
       -                        if (strchr(pieces, *s))
       -                                place(*s, x++, y);
       -                        break;
       -                case 1: /* active color */
       -                        if (*s == 'w' || *s == 'b')
       -                                side_to_move = *s;
       -                        break;
       -                case 2: /* castling availability */
       -                        if (*s == '-') {
       -                                white_can_castle[0] = 0;
       -                                white_can_castle[1] = 0;
       -                                black_can_castle[0] = 0;
       -                                black_can_castle[1] = 0;
       -                        } else if (*s == 'K') {
       -                                white_can_castle[0] = 1;
       -                        } else if (*s == 'Q') {
       -                                white_can_castle[1] = 1;
       -                        } else if (*s == 'k') {
       -                                black_can_castle[0] = 1;
       -                        } else if (*s == 'q') {
       -                                black_can_castle[1] = 1;
       -                        }
       -                        break;
       -                case 3: /* TODO: en-passant square, rest of the fields */
       -                        break;
       -                }
       -                /* TODO: parse which side to move, en-passant, etc */
       -        }
       -
       -        /* process moves */
       -        square[2] = '\0';
       -        x = y = x2 = y2 = -1;
       -        for (s = moves; *s; s++) {
       -                if (*s == ' ')
       -                        continue;
       -                if ((*s >= 'a' && *s <= 'h') &&
       -                    (*(s + 1) >= '1' && *(s + 1) <= '8') &&
       -                    (*(s + 2) >= 'a' && *(s + 2) <= 'h') &&
       -                    (*(s + 3) >= '1' && *(s + 3) <= '8')) {
       -                        square[0] = *s;
       -                        square[1] = *(s + 1);
       -
       -                        s += 2;
       -                        squaretoxy(square, &x, &y);
       -                        piece = getpiece(x, y);
       -
       -                        place(0, x, y); /* clear square */
       -
       -                        /* place piece at new location */
       -                        square[0] = *s;
       -                        square[1] = *(s + 1);
       -                        squaretoxy(square, &x2, &y2);
       -                        place(piece, x2, y2);
       -                        s += 2;
       -
       -                        /* possible promotion? (queen, knight, bishop) */
       -                        if (*s == 'q' || *s == 'n' || *s == 'b') {
       -                                if (side_to_move == 'w')
       -                                        piece = toupper(*s);
       -                                else
       -                                        piece = *s;
       -                                place(piece, x2, y2);
       -                                s++;
       -                        }
       -
       -                        /* switch which side it is to move */
       -                        side_to_move = side_to_move == 'b' ? 'w' : 'b';
       -                }
       -        }
       -        /* highlight last move */
       -        highlightmove(x, y, x2, y2);
       -
       -        showboard();
       -
       -        return 0;
       -}
 (DIR) diff --git a/fen_to_svg.c b/fen_to_svg.c
       @@ -4,6 +4,9 @@
        #include <stdio.h>
        #include <string.h>
        
       +#define SETFGCOLOR(r,g,b)    printf("\x1b[38;2;%d;%d;%dm", r, g, b)
       +#define SETBGCOLOR(r,g,b)    printf("\x1b[48;2;%d;%d;%dm", r, g, b)
       +
        static char board[8][8];
        static char highlight[8][8];
        
       @@ -19,6 +22,14 @@ isvalidsquare(int x, int y)
                return !(x < 0 || x >= 8 || y < 0 || y >= 8);
        }
        
       +int
       +isvalidpiece(int c)
       +{
       +        static char pieces[] = "PNBRQKpnbrqk";
       +
       +        return strchr(pieces, c) ? 1 : 0;
       +}
       +
        /* place a piece, if possible */
        void
        place(int piece, int x, int y)
       @@ -61,32 +72,6 @@ highlightmove(int x1, int y1, int x2, int y2)
        }
        
        void
       -showpiece(int c)
       -{
       -        const char *s = "";
       -
       -        /* lichess default set,
       -           extracted from https://github.com/lichess-org/lila/tree/master/public/piece/cburnett */
       -        switch (c) {
       -        case 'K': s = "<g fill=\"none\" fill-rule=\"evenodd\" stroke=\"#000\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M22.5 11.63V6M20 8h5\" stroke-linejoin=\"miter\"/><path d=\"M22.5 25s4.5-7.5 3-10.5c0 0-1-2.5-3-2.5s-3 2.5-3 2.5c-1.5 3 3 10.5 3 10.5\" fill=\"#fff\" stroke-linecap=\"butt\" stroke-linejoin=\"miter\"/><path d=\"M11.5 37c5.5 3.5 15.5 3.5 21 0v-7s9-4.5 6-10.5c-4-6.5-13.5-3.5-16 4V27v-3.5c-3.5-7.5-13-10.5-16-4-3 6 5 10 5 10V37z\" fill=\"#fff\"/><path d=\"M11.5 30c5.5-3 15.5-3 21 0m-21 3.5c5.5-3 15.5-3 21 0m-21 3.5c5.5-3 15.5-3 21 0\"/></g>"; break;
       -        case 'Q': s = "<g fill=\"#fff\" fill-rule=\"evenodd\" stroke=\"#000\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M8 12a2 2 0 1 1-4 0 2 2 0 1 1 4 0zm16.5-4.5a2 2 0 1 1-4 0 2 2 0 1 1 4 0zM41 12a2 2 0 1 1-4 0 2 2 0 1 1 4 0zM16 8.5a2 2 0 1 1-4 0 2 2 0 1 1 4 0zM33 9a2 2 0 1 1-4 0 2 2 0 1 1 4 0z\"/><path d=\"M9 26c8.5-1.5 21-1.5 27 0l2-12-7 11V11l-5.5 13.5-3-15-3 15-5.5-14V25L7 14l2 12z\" stroke-linecap=\"butt\"/><path d=\"M9 26c0 2 1.5 2 2.5 4 1 1.5 1 1 .5 3.5-1.5 1-1.5 2.5-1.5 2.5-1.5 1.5.5 2.5.5 2.5 6.5 1 16.5 1 23 0 0 0 1.5-1 0-2.5 0 0 .5-1.5-1-2.5-.5-2.5-.5-2 .5-3.5 1-2 2.5-2 2.5-4-8.5-1.5-18.5-1.5-27 0z\" stroke-linecap=\"butt\"/><path d=\"M11.5 30c3.5-1 18.5-1 22 0M12 33.5c6-1 15-1 21 0\" fill=\"none\"/></g>"; break;
       -        case 'R': s = "<g fill=\"#fff\" fill-rule=\"evenodd\" stroke=\"#000\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M9 39h27v-3H9v3zm3-3v-4h21v4H12zm-1-22V9h4v2h5V9h5v2h5V9h4v5\" stroke-linecap=\"butt\"/><path d=\"M34 14l-3 3H14l-3-3\"/><path d=\"M31 17v12.5H14V17\" stroke-linecap=\"butt\" stroke-linejoin=\"miter\"/><path d=\"M31 29.5l1.5 2.5h-20l1.5-2.5\"/><path d=\"M11 14h23\" fill=\"none\" stroke-linejoin=\"miter\"/></g>"; break;
       -        case 'B': s = "<g fill=\"none\" fill-rule=\"evenodd\" stroke=\"#000\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><g fill=\"#fff\" stroke-linecap=\"butt\"><path d=\"M9 36c3.39-.97 10.11.43 13.5-2 3.39 2.43 10.11 1.03 13.5 2 0 0 1.65.54 3 2-.68.97-1.65.99-3 .5-3.39-.97-10.11.46-13.5-1-3.39 1.46-10.11.03-13.5 1-1.354.49-2.323.47-3-.5 1.354-1.94 3-2 3-2z\"/><path d=\"M15 32c2.5 2.5 12.5 2.5 15 0 .5-1.5 0-2 0-2 0-2.5-2.5-4-2.5-4 5.5-1.5 6-11.5-5-15.5-11 4-10.5 14-5 15.5 0 0-2.5 1.5-2.5 4 0 0-.5.5 0 2z\"/><path d=\"M25 8a2.5 2.5 0 1 1-5 0 2.5 2.5 0 1 1 5 0z\"/></g><path d=\"M17.5 26h10M15 30h15m-7.5-14.5v5M20 18h5\" stroke-linejoin=\"miter\"/></g>"; break;
       -        case 'N': s = "<g fill=\"none\" fill-rule=\"evenodd\" stroke=\"#000\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M22 10c10.5 1 16.5 8 16 29H15c0-9 10-6.5 8-21\" fill=\"#fff\"/><path d=\"M24 18c.38 2.91-5.55 7.37-8 9-3 2-2.82 4.34-5 4-1.042-.94 1.41-3.04 0-3-1 0 .19 1.23-1 2-1 0-4.003 1-4-4 0-2 6-12 6-12s1.89-1.9 2-3.5c-.73-.994-.5-2-.5-3 1-1 3 2.5 3 2.5h2s.78-1.992 2.5-3c1 0 1 3 1 3\" fill=\"#fff\"/><path d=\"M9.5 25.5a.5.5 0 1 1-1 0 .5.5 0 1 1 1 0zm5.433-9.75a.5 1.5 30 1 1-.866-.5.5 1.5 30 1 1 .866.5z\" fill=\"#000\"/></g>"; break;
       -        case 'P': s = "<path d=\"M22.5 9c-2.21 0-4 1.79-4 4 0 .89.29 1.71.78 2.38C17.33 16.5 16 18.59 16 21c0 2.03.94 3.84 2.41 5.03-3 1.06-7.41 5.55-7.41 13.47h23c0-7.92-4.41-12.41-7.41-13.47 1.47-1.19 2.41-3 2.41-5.03 0-2.41-1.33-4.5-3.28-5.62.49-.67.78-1.49.78-2.38 0-2.21-1.79-4-4-4z\" fill=\"#fff\" stroke=\"#000\" stroke-width=\"1.5\" stroke-linecap=\"round\"/>"; break;
       -        case 'k': s = "<g fill=\"none\" fill-rule=\"evenodd\" stroke=\"#000\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M22.5 11.63V6\" stroke-linejoin=\"miter\"/><path d=\"M22.5 25s4.5-7.5 3-10.5c0 0-1-2.5-3-2.5s-3 2.5-3 2.5c-1.5 3 3 10.5 3 10.5\" fill=\"#000\" stroke-linecap=\"butt\" stroke-linejoin=\"miter\"/><path d=\"M11.5 37c5.5 3.5 15.5 3.5 21 0v-7s9-4.5 6-10.5c-4-6.5-13.5-3.5-16 4V27v-3.5c-3.5-7.5-13-10.5-16-4-3 6 5 10 5 10V37z\" fill=\"#000\"/><path d=\"M20 8h5\" stroke-linejoin=\"miter\"/><path d=\"M32 29.5s8.5-4 6.03-9.65C34.15 14 25 18 22.5 24.5l.01 2.1-.01-2.1C20 18 9.906 14 6.997 19.85c-2.497 5.65 4.853 9 4.853 9\" stroke=\"#ececec\"/><path d=\"M11.5 30c5.5-3 15.5-3 21 0m-21 3.5c5.5-3 15.5-3 21 0m-21 3.5c5.5-3 15.5-3 21 0\" stroke=\"#ececec\"/></g>"; break;
       -        case 'q': s = "<g fill-rule=\"evenodd\" stroke=\"#000\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><g stroke=\"none\"><circle cx=\"6\" cy=\"12\" r=\"2.75\"/><circle cx=\"14\" cy=\"9\" r=\"2.75\"/><circle cx=\"22.5\" cy=\"8\" r=\"2.75\"/><circle cx=\"31\" cy=\"9\" r=\"2.75\"/><circle cx=\"39\" cy=\"12\" r=\"2.75\"/></g><path d=\"M9 26c8.5-1.5 21-1.5 27 0l2.5-12.5L31 25l-.3-14.1-5.2 13.6-3-14.5-3 14.5-5.2-13.6L14 25 6.5 13.5 9 26z\" stroke-linecap=\"butt\"/><path d=\"M9 26c0 2 1.5 2 2.5 4 1 1.5 1 1 .5 3.5-1.5 1-1.5 2.5-1.5 2.5-1.5 1.5.5 2.5.5 2.5 6.5 1 16.5 1 23 0 0 0 1.5-1 0-2.5 0 0 .5-1.5-1-2.5-.5-2.5-.5-2 .5-3.5 1-2 2.5-2 2.5-4-8.5-1.5-18.5-1.5-27 0z\" stroke-linecap=\"butt\"/><path d=\"M11 38.5a35 35 1 0 0 23 0\" fill=\"none\" stroke-linecap=\"butt\"/><path d=\"M11 29a35 35 1 0 1 23 0m-21.5 2.5h20m-21 3a35 35 1 0 0 22 0m-23 3a35 35 1 0 0 24 0\" fill=\"none\" stroke=\"#ececec\"/></g>"; break;
       -        case 'r': s = "<g fill-rule=\"evenodd\" stroke=\"#000\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M9 39h27v-3H9v3zm3.5-7l1.5-2.5h17l1.5 2.5h-20zm-.5 4v-4h21v4H12z\" stroke-linecap=\"butt\"/><path d=\"M14 29.5v-13h17v13H14z\" stroke-linecap=\"butt\" stroke-linejoin=\"miter\"/><path d=\"M14 16.5L11 14h23l-3 2.5H14zM11 14V9h4v2h5V9h5v2h5V9h4v5H11z\" stroke-linecap=\"butt\"/><path d=\"M12 35.5h21m-20-4h19m-18-2h17m-17-13h17M11 14h23\" fill=\"none\" stroke=\"#ececec\" stroke-width=\"1\" stroke-linejoin=\"miter\"/></g>"; break;
       -        case 'b': s = "<g fill=\"none\" fill-rule=\"evenodd\" stroke=\"#000\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><g fill=\"#000\" stroke-linecap=\"butt\"><path d=\"M9 36c3.39-.97 10.11.43 13.5-2 3.39 2.43 10.11 1.03 13.5 2 0 0 1.65.54 3 2-.68.97-1.65.99-3 .5-3.39-.97-10.11.46-13.5-1-3.39 1.46-10.11.03-13.5 1-1.354.49-2.323.47-3-.5 1.354-1.94 3-2 3-2z\"/><path d=\"M15 32c2.5 2.5 12.5 2.5 15 0 .5-1.5 0-2 0-2 0-2.5-2.5-4-2.5-4 5.5-1.5 6-11.5-5-15.5-11 4-10.5 14-5 15.5 0 0-2.5 1.5-2.5 4 0 0-.5.5 0 2z\"/><path d=\"M25 8a2.5 2.5 0 1 1-5 0 2.5 2.5 0 1 1 5 0z\"/></g><path d=\"M17.5 26h10M15 30h15m-7.5-14.5v5M20 18h5\" stroke=\"#ececec\" stroke-linejoin=\"miter\"/></g>"; break;
       -        case 'n': s = "<g fill=\"none\" fill-rule=\"evenodd\" stroke=\"#000\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M22 10c10.5 1 16.5 8 16 29H15c0-9 10-6.5 8-21\" fill=\"#000\"/><path d=\"M24 18c.38 2.91-5.55 7.37-8 9-3 2-2.82 4.34-5 4-1.042-.94 1.41-3.04 0-3-1 0 .19 1.23-1 2-1 0-4.003 1-4-4 0-2 6-12 6-12s1.89-1.9 2-3.5c-.73-.994-.5-2-.5-3 1-1 3 2.5 3 2.5h2s.78-1.992 2.5-3c1 0 1 3 1 3\" fill=\"#000\"/><path d=\"M9.5 25.5a.5.5 0 1 1-1 0 .5.5 0 1 1 1 0zm5.433-9.75a.5 1.5 30 1 1-.866-.5.5 1.5 30 1 1 .866.5z\" fill=\"#ececec\" stroke=\"#ececec\"/><path d=\"M24.55 10.4l-.45 1.45.5.15c3.15 1 5.65 2.49 7.9 6.75S35.75 29.06 35.25 39l-.05.5h2.25l.05-.5c.5-10.06-.88-16.85-3.25-21.34-2.37-4.49-5.79-6.64-9.19-7.16l-.51-.1z\" fill=\"#ececec\" stroke=\"none\"/></g>"; break;
       -        case 'p': s = "<path d=\"M22.5 9c-2.21 0-4 1.79-4 4 0 .89.29 1.71.78 2.38C17.33 16.5 16 18.59 16 21c0 2.03.94 3.84 2.41 5.03-3 1.06-7.41 5.55-7.41 13.47h23c0-7.92-4.41-12.41-7.41-13.47 1.47-1.19 2.41-3 2.41-5.03 0-2.41-1.33-4.5-3.28-5.62.49-.67.78-1.49.78-2.38 0-2.21-1.79-4-4-4z\" stroke=\"#000\" stroke-width=\"1.5\" stroke-linecap=\"round\"/>"; break;
       -        }
       -
       -        if (*s)
       -                fputs(s, stdout);
       -}
       -
       -void
        showboardfen(void)
        {
                int x, y, piece, skip = 0;
       @@ -114,7 +99,33 @@ showboardfen(void)
        }
        
        void
       -showboard(void)
       +svg_showpiece(int c)
       +{
       +        const char *s = "";
       +
       +        /* lichess default set,
       +           extracted from https://github.com/lichess-org/lila/tree/master/public/piece/cburnett */
       +        switch (c) {
       +        case 'K': s = "<g fill=\"none\" fill-rule=\"evenodd\" stroke=\"#000\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M22.5 11.63V6M20 8h5\" stroke-linejoin=\"miter\"/><path d=\"M22.5 25s4.5-7.5 3-10.5c0 0-1-2.5-3-2.5s-3 2.5-3 2.5c-1.5 3 3 10.5 3 10.5\" fill=\"#fff\" stroke-linecap=\"butt\" stroke-linejoin=\"miter\"/><path d=\"M11.5 37c5.5 3.5 15.5 3.5 21 0v-7s9-4.5 6-10.5c-4-6.5-13.5-3.5-16 4V27v-3.5c-3.5-7.5-13-10.5-16-4-3 6 5 10 5 10V37z\" fill=\"#fff\"/><path d=\"M11.5 30c5.5-3 15.5-3 21 0m-21 3.5c5.5-3 15.5-3 21 0m-21 3.5c5.5-3 15.5-3 21 0\"/></g>"; break;
       +        case 'Q': s = "<g fill=\"#fff\" fill-rule=\"evenodd\" stroke=\"#000\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M8 12a2 2 0 1 1-4 0 2 2 0 1 1 4 0zm16.5-4.5a2 2 0 1 1-4 0 2 2 0 1 1 4 0zM41 12a2 2 0 1 1-4 0 2 2 0 1 1 4 0zM16 8.5a2 2 0 1 1-4 0 2 2 0 1 1 4 0zM33 9a2 2 0 1 1-4 0 2 2 0 1 1 4 0z\"/><path d=\"M9 26c8.5-1.5 21-1.5 27 0l2-12-7 11V11l-5.5 13.5-3-15-3 15-5.5-14V25L7 14l2 12z\" stroke-linecap=\"butt\"/><path d=\"M9 26c0 2 1.5 2 2.5 4 1 1.5 1 1 .5 3.5-1.5 1-1.5 2.5-1.5 2.5-1.5 1.5.5 2.5.5 2.5 6.5 1 16.5 1 23 0 0 0 1.5-1 0-2.5 0 0 .5-1.5-1-2.5-.5-2.5-.5-2 .5-3.5 1-2 2.5-2 2.5-4-8.5-1.5-18.5-1.5-27 0z\" stroke-linecap=\"butt\"/><path d=\"M11.5 30c3.5-1 18.5-1 22 0M12 33.5c6-1 15-1 21 0\" fill=\"none\"/></g>"; break;
       +        case 'R': s = "<g fill=\"#fff\" fill-rule=\"evenodd\" stroke=\"#000\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M9 39h27v-3H9v3zm3-3v-4h21v4H12zm-1-22V9h4v2h5V9h5v2h5V9h4v5\" stroke-linecap=\"butt\"/><path d=\"M34 14l-3 3H14l-3-3\"/><path d=\"M31 17v12.5H14V17\" stroke-linecap=\"butt\" stroke-linejoin=\"miter\"/><path d=\"M31 29.5l1.5 2.5h-20l1.5-2.5\"/><path d=\"M11 14h23\" fill=\"none\" stroke-linejoin=\"miter\"/></g>"; break;
       +        case 'B': s = "<g fill=\"none\" fill-rule=\"evenodd\" stroke=\"#000\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><g fill=\"#fff\" stroke-linecap=\"butt\"><path d=\"M9 36c3.39-.97 10.11.43 13.5-2 3.39 2.43 10.11 1.03 13.5 2 0 0 1.65.54 3 2-.68.97-1.65.99-3 .5-3.39-.97-10.11.46-13.5-1-3.39 1.46-10.11.03-13.5 1-1.354.49-2.323.47-3-.5 1.354-1.94 3-2 3-2z\"/><path d=\"M15 32c2.5 2.5 12.5 2.5 15 0 .5-1.5 0-2 0-2 0-2.5-2.5-4-2.5-4 5.5-1.5 6-11.5-5-15.5-11 4-10.5 14-5 15.5 0 0-2.5 1.5-2.5 4 0 0-.5.5 0 2z\"/><path d=\"M25 8a2.5 2.5 0 1 1-5 0 2.5 2.5 0 1 1 5 0z\"/></g><path d=\"M17.5 26h10M15 30h15m-7.5-14.5v5M20 18h5\" stroke-linejoin=\"miter\"/></g>"; break;
       +        case 'N': s = "<g fill=\"none\" fill-rule=\"evenodd\" stroke=\"#000\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M22 10c10.5 1 16.5 8 16 29H15c0-9 10-6.5 8-21\" fill=\"#fff\"/><path d=\"M24 18c.38 2.91-5.55 7.37-8 9-3 2-2.82 4.34-5 4-1.042-.94 1.41-3.04 0-3-1 0 .19 1.23-1 2-1 0-4.003 1-4-4 0-2 6-12 6-12s1.89-1.9 2-3.5c-.73-.994-.5-2-.5-3 1-1 3 2.5 3 2.5h2s.78-1.992 2.5-3c1 0 1 3 1 3\" fill=\"#fff\"/><path d=\"M9.5 25.5a.5.5 0 1 1-1 0 .5.5 0 1 1 1 0zm5.433-9.75a.5 1.5 30 1 1-.866-.5.5 1.5 30 1 1 .866.5z\" fill=\"#000\"/></g>"; break;
       +        case 'P': s = "<path d=\"M22.5 9c-2.21 0-4 1.79-4 4 0 .89.29 1.71.78 2.38C17.33 16.5 16 18.59 16 21c0 2.03.94 3.84 2.41 5.03-3 1.06-7.41 5.55-7.41 13.47h23c0-7.92-4.41-12.41-7.41-13.47 1.47-1.19 2.41-3 2.41-5.03 0-2.41-1.33-4.5-3.28-5.62.49-.67.78-1.49.78-2.38 0-2.21-1.79-4-4-4z\" fill=\"#fff\" stroke=\"#000\" stroke-width=\"1.5\" stroke-linecap=\"round\"/>"; break;
       +        case 'k': s = "<g fill=\"none\" fill-rule=\"evenodd\" stroke=\"#000\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M22.5 11.63V6\" stroke-linejoin=\"miter\"/><path d=\"M22.5 25s4.5-7.5 3-10.5c0 0-1-2.5-3-2.5s-3 2.5-3 2.5c-1.5 3 3 10.5 3 10.5\" fill=\"#000\" stroke-linecap=\"butt\" stroke-linejoin=\"miter\"/><path d=\"M11.5 37c5.5 3.5 15.5 3.5 21 0v-7s9-4.5 6-10.5c-4-6.5-13.5-3.5-16 4V27v-3.5c-3.5-7.5-13-10.5-16-4-3 6 5 10 5 10V37z\" fill=\"#000\"/><path d=\"M20 8h5\" stroke-linejoin=\"miter\"/><path d=\"M32 29.5s8.5-4 6.03-9.65C34.15 14 25 18 22.5 24.5l.01 2.1-.01-2.1C20 18 9.906 14 6.997 19.85c-2.497 5.65 4.853 9 4.853 9\" stroke=\"#ececec\"/><path d=\"M11.5 30c5.5-3 15.5-3 21 0m-21 3.5c5.5-3 15.5-3 21 0m-21 3.5c5.5-3 15.5-3 21 0\" stroke=\"#ececec\"/></g>"; break;
       +        case 'q': s = "<g fill-rule=\"evenodd\" stroke=\"#000\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><g stroke=\"none\"><circle cx=\"6\" cy=\"12\" r=\"2.75\"/><circle cx=\"14\" cy=\"9\" r=\"2.75\"/><circle cx=\"22.5\" cy=\"8\" r=\"2.75\"/><circle cx=\"31\" cy=\"9\" r=\"2.75\"/><circle cx=\"39\" cy=\"12\" r=\"2.75\"/></g><path d=\"M9 26c8.5-1.5 21-1.5 27 0l2.5-12.5L31 25l-.3-14.1-5.2 13.6-3-14.5-3 14.5-5.2-13.6L14 25 6.5 13.5 9 26z\" stroke-linecap=\"butt\"/><path d=\"M9 26c0 2 1.5 2 2.5 4 1 1.5 1 1 .5 3.5-1.5 1-1.5 2.5-1.5 2.5-1.5 1.5.5 2.5.5 2.5 6.5 1 16.5 1 23 0 0 0 1.5-1 0-2.5 0 0 .5-1.5-1-2.5-.5-2.5-.5-2 .5-3.5 1-2 2.5-2 2.5-4-8.5-1.5-18.5-1.5-27 0z\" stroke-linecap=\"butt\"/><path d=\"M11 38.5a35 35 1 0 0 23 0\" fill=\"none\" stroke-linecap=\"butt\"/><path d=\"M11 29a35 35 1 0 1 23 0m-21.5 2.5h20m-21 3a35 35 1 0 0 22 0m-23 3a35 35 1 0 0 24 0\" fill=\"none\" stroke=\"#ececec\"/></g>"; break;
       +        case 'r': s = "<g fill-rule=\"evenodd\" stroke=\"#000\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M9 39h27v-3H9v3zm3.5-7l1.5-2.5h17l1.5 2.5h-20zm-.5 4v-4h21v4H12z\" stroke-linecap=\"butt\"/><path d=\"M14 29.5v-13h17v13H14z\" stroke-linecap=\"butt\" stroke-linejoin=\"miter\"/><path d=\"M14 16.5L11 14h23l-3 2.5H14zM11 14V9h4v2h5V9h5v2h5V9h4v5H11z\" stroke-linecap=\"butt\"/><path d=\"M12 35.5h21m-20-4h19m-18-2h17m-17-13h17M11 14h23\" fill=\"none\" stroke=\"#ececec\" stroke-width=\"1\" stroke-linejoin=\"miter\"/></g>"; break;
       +        case 'b': s = "<g fill=\"none\" fill-rule=\"evenodd\" stroke=\"#000\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><g fill=\"#000\" stroke-linecap=\"butt\"><path d=\"M9 36c3.39-.97 10.11.43 13.5-2 3.39 2.43 10.11 1.03 13.5 2 0 0 1.65.54 3 2-.68.97-1.65.99-3 .5-3.39-.97-10.11.46-13.5-1-3.39 1.46-10.11.03-13.5 1-1.354.49-2.323.47-3-.5 1.354-1.94 3-2 3-2z\"/><path d=\"M15 32c2.5 2.5 12.5 2.5 15 0 .5-1.5 0-2 0-2 0-2.5-2.5-4-2.5-4 5.5-1.5 6-11.5-5-15.5-11 4-10.5 14-5 15.5 0 0-2.5 1.5-2.5 4 0 0-.5.5 0 2z\"/><path d=\"M25 8a2.5 2.5 0 1 1-5 0 2.5 2.5 0 1 1 5 0z\"/></g><path d=\"M17.5 26h10M15 30h15m-7.5-14.5v5M20 18h5\" stroke=\"#ececec\" stroke-linejoin=\"miter\"/></g>"; break;
       +        case 'n': s = "<g fill=\"none\" fill-rule=\"evenodd\" stroke=\"#000\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M22 10c10.5 1 16.5 8 16 29H15c0-9 10-6.5 8-21\" fill=\"#000\"/><path d=\"M24 18c.38 2.91-5.55 7.37-8 9-3 2-2.82 4.34-5 4-1.042-.94 1.41-3.04 0-3-1 0 .19 1.23-1 2-1 0-4.003 1-4-4 0-2 6-12 6-12s1.89-1.9 2-3.5c-.73-.994-.5-2-.5-3 1-1 3 2.5 3 2.5h2s.78-1.992 2.5-3c1 0 1 3 1 3\" fill=\"#000\"/><path d=\"M9.5 25.5a.5.5 0 1 1-1 0 .5.5 0 1 1 1 0zm5.433-9.75a.5 1.5 30 1 1-.866-.5.5 1.5 30 1 1 .866.5z\" fill=\"#ececec\" stroke=\"#ececec\"/><path d=\"M24.55 10.4l-.45 1.45.5.15c3.15 1 5.65 2.49 7.9 6.75S35.75 29.06 35.25 39l-.05.5h2.25l.05-.5c.5-10.06-.88-16.85-3.25-21.34-2.37-4.49-5.79-6.64-9.19-7.16l-.51-.1z\" fill=\"#ececec\" stroke=\"none\"/></g>"; break;
       +        case 'p': s = "<path d=\"M22.5 9c-2.21 0-4 1.79-4 4 0 .89.29 1.71.78 2.38C17.33 16.5 16 18.59 16 21c0 2.03.94 3.84 2.41 5.03-3 1.06-7.41 5.55-7.41 13.47h23c0-7.92-4.41-12.41-7.41-13.47 1.47-1.19 2.41-3 2.41-5.03 0-2.41-1.33-4.5-3.28-5.62.49-.67.78-1.49.78-2.38 0-2.21-1.79-4-4-4z\" stroke=\"#000\" stroke-width=\"1.5\" stroke-linecap=\"round\"/>"; break;
       +        }
       +
       +        if (*s)
       +                fputs(s, stdout);
       +}
       +
       +void
       +svg_showboard(void)
        {
                /* lichess default theme colors */
                const char *darksquare = "#b58863";
       @@ -153,7 +164,7 @@ showboard(void)
                                piece = getpiece(x, y);
                                if (piece) {
                                        printf("<g transform=\"translate(%d %d)\">", x * 45, y * 45);
       -                                showpiece(piece);
       +                                svg_showpiece(piece);
                                        fputs("</g>\n", stdout);
                                }
                        }
       @@ -183,18 +194,191 @@ showboard(void)
                fputs("</svg>\n", stdout);
        }
        
       -int
       -isvalidpiece(int c)
       +void
       +tty_showpiece(int c)
        {
       -        static char pieces[] = "PNBRQKpnbrqk";
       +        const char *s = "";
        
       -        return strchr(pieces, c) ? 1 : 0;
       +        /* simple or use unicode character */
       +#if 0
       +        putchar(c);
       +        return;
       +#endif
       +
       +        switch (c) {
       +        case 'K': s = "♔"; break;
       +        case 'Q': s = "♕"; break;
       +        case 'R': s = "♖"; break;
       +        case 'B': s = "♗"; break;
       +        case 'N': s = "♘"; break;
       +        case 'P': s = "♙"; break;
       +        case 'k': s = "♚"; break;
       +        case 'q': s = "♛"; break;
       +        case 'r': s = "♜"; break;
       +        case 'b': s = "♝"; break;
       +        case 'n': s = "♞"; break;
       +        case 'p': s = "♟"; break;
       +        }
       +
       +        if (*s)
       +                fputs(s, stdout);
       +}
       +
       +/* show board */
       +void
       +tty_showboard(void)
       +{
       +        int *color;
       +        int border[] = { 0x70, 0x49, 0x2d };
       +        int darksquare[] = { 0xb5, 0x88, 0x63 };
       +        int lightsquare[] = { 0xf0, 0xd9, 0xb5 };
       +        int darksquarehi[] = { 0xaa, 0xa2, 0x3a };
       +        int lightsquarehi[] = { 0xcd, 0xd2, 0x6a };
       +        int x, y, piece;
       +
       +        printf("Board FEN:\n");
       +        showboardfen();
       +        printf("\n\n");
       +
       +        SETFGCOLOR(0x00, 0x00, 0x00);
       +
       +        color = border;
       +        SETBGCOLOR(color[0], color[1], color[2]);
       +        SETFGCOLOR(0xff, 0xff, 0xff);
       +        fputs("                             ", stdout);
       +        printf("\x1b[0m"); /* reset */
       +        SETFGCOLOR(0x00, 0x00, 0x00);
       +        putchar('\n');
       +
       +        for (y = 0; y < 8; y++) {
       +                color = border;
       +                SETBGCOLOR(color[0], color[1], color[2]);
       +                SETFGCOLOR(0xff, 0xff, 0xff);
       +                fputs("  ", stdout);
       +
       +                for (x = 0; x < 8; x++) {
       +                        if (x % 2 == 0) {
       +                                if (y % 2 == 0)
       +                                        color = highlight[y][x] ? lightsquarehi : lightsquare;
       +                                else
       +                                        color = highlight[y][x] ? darksquarehi : darksquare;
       +                        } else {
       +                                if (y % 2 == 0)
       +                                        color = highlight[y][x] ? darksquarehi : darksquare;
       +                                else
       +                                        color = highlight[y][x] ? lightsquarehi : lightsquare;
       +                        }
       +                        SETBGCOLOR(color[0], color[1], color[2]);
       +
       +                        fputs(" ", stdout);
       +                        piece = getpiece(x, y);
       +                        if (piece) {
       +                                if (piece >= 'A' && piece <= 'Z')
       +                                        SETFGCOLOR(0xff, 0xff, 0xff);
       +                                else
       +                                        SETFGCOLOR(0x00, 0x00, 0x00);
       +                                /* workaround: use black chess symbol, because the color
       +                                   is filled and better visible */
       +                                tty_showpiece(tolower(piece));
       +                        } else {
       +                                fputs(" ", stdout);
       +                        }
       +                        fputs(" ", stdout);
       +                }
       +                printf("\x1b[0m"); /* reset */
       +
       +                color = border;
       +                SETBGCOLOR(color[0], color[1], color[2]);
       +                SETFGCOLOR(0xff, 0xff, 0xff);
       +                if (showcoords) {
       +                        putchar(' ');
       +                        putchar('8' - y);
       +                        putchar(' ');
       +                } else {
       +                        fputs("   ", stdout);
       +                }
       +
       +                printf("\x1b[0m"); /* reset */
       +                SETFGCOLOR(0x00, 0x00, 0x00);
       +                putchar('\n');
       +        }
       +        color = border;
       +        SETBGCOLOR(color[0], color[1], color[2]);
       +        SETFGCOLOR(0xff, 0xff, 0xff);
       +        if (showcoords)
       +                fputs("   a  b  c  d  e  f  g  h    ", stdout);
       +        else
       +                fputs("                             ", stdout);
       +        printf("\x1b[0m"); /* reset */
       +        printf("\n");
       +        printf("\x1b[0m"); /* reset */
       +}
       +
       +void
       +ascii_showpiece(int c)
       +{
       +        putchar(c);
       +}
       +
       +/* show board */
       +/* TODO: show fancier, unicode and background square color */
       +/* TODO: use the output format similar to stockfish "d" command */
       +void
       +ascii_showboard(void)
       +{
       +        int x, y, piece;
       +
       +        printf("Board FEN:\n");
       +        showboardfen();
       +        printf("\n\n");
       +
       +        for (y = 0; y < 8; y++) {
       +                printf("+---+---+---+---+---+---+---+---+\n");
       +                for (x = 0; x < 8; x++) {
       +                        if (x == 0)
       +                                putchar('|');
       +                        fputs(" ", stdout);
       +                        piece = getpiece(x, y);
       +                        if (piece)
       +                                ascii_showpiece(piece);
       +                        else
       +                                fputs(" ", stdout);
       +                        fputs(" ", stdout);
       +                        putchar('|');
       +                }
       +                if (showcoords) {
       +                        putchar(' ');
       +                        putchar('8' - y);
       +                }
       +                putchar('\n');
       +        }
       +        printf("+---+---+---+---+---+---+---+---+\n");
       +        if (showcoords)
       +                printf("  a | b | c | d | e | f | g | h |\n");
       +
       +        fputs("\n", stdout);
       +
       +#if 0
       +        if (side_to_move == 'w') {
       +                fputs("White to move\n", stdout);
       +        } else if (side_to_move == 'b')
       +                fputs("Black to move\n", stdout);
       +
       +        if (white_can_castle[0])
       +                fputs("White can castle king side\n", stdout);
       +        if (white_can_castle[1])
       +                fputs("White can castle queen side\n", stdout);
       +        if (black_can_castle[0])
       +                fputs("Black can castle king side\n", stdout);
       +        if (black_can_castle[1])
       +                fputs("Black can castle queen side\n", stdout);
       +#endif
        }
        
        int
        main(int argc, char *argv[])
        {
       -        const char *fen, *moves, *s;
       +        const char *progname, *fen, *moves, *s;
                int x, y, x2, y2, field, piece;
                char square[3];
        
       @@ -337,7 +521,15 @@ main(int argc, char *argv[])
                /* highlight last move */
                highlightmove(x, y, x2, y2);
        
       -        showboard();
       +        progname = argv[0] ? argv[0] : "fen_to_svg";
       +        if ((s = strrchr(progname, '/')))
       +                progname = s + 1;
       +        if (!strcmp(progname, "fen_to_ascii"))
       +                ascii_showboard();
       +        else if (!strcmp(progname, "fen_to_tty"))
       +                tty_showboard();
       +        else
       +                svg_showboard();
        
                return 0;
        }
 (DIR) diff --git a/fen_to_tty.c b/fen_to_tty.c
       @@ -1,346 +0,0 @@
       -/* TODO: option to flip board? */
       -
       -#include <ctype.h>
       -#include <stdio.h>
       -#include <string.h>
       -
       -static char board[8][8];
       -static char highlight[8][8];
       -
       -static int side_to_move = 'w'; /* default: white to move */
       -static int white_can_castle[2] = { 0, 0 }; /* allow king side, allow queen side */
       -static int black_can_castle[2] = { 0, 0 }; /* allow king side, allow queen side */
       -
       -static const int showcoords = 1; /* config: show board coordinates? */
       -
       -#define SETFGCOLOR(r,g,b)    printf("\x1b[38;2;%d;%d;%dm", r, g, b)
       -#define SETBGCOLOR(r,g,b)    printf("\x1b[48;2;%d;%d;%dm", r, g, b)
       -
       -int
       -isvalidsquare(int x, int y)
       -{
       -        return !(x < 0 || x >= 8 || y < 0 || y >= 8);
       -}
       -
       -/* place a piece, if possible */
       -void
       -place(int piece, int x, int y)
       -{
       -        if (!isvalidsquare(x, y))
       -                return;
       -
       -        board[y][x] = piece;
       -}
       -
       -/* get piece, if possible */
       -int
       -getpiece(int x, int y)
       -{
       -        if (!isvalidsquare(x, y))
       -                return 0;
       -        return board[y][x];
       -}
       -
       -int
       -squaretoxy(const char *s, int *x, int *y)
       -{
       -        if (*s >= 'a' && *s <= 'h' &&
       -            *(s + 1) >= '1' && *(s + 1) <= '8') {
       -                *x = *s - 'a';
       -                *y = '8' - *(s + 1);
       -                return 1;
       -        }
       -        return 0;
       -}
       -
       -void
       -highlightmove(int x1, int y1, int x2, int y2)
       -{
       -        if (isvalidsquare(x1, y1))
       -                highlight[y1][x1] = 1;
       -
       -        if (isvalidsquare(x2, y2))
       -                highlight[y2][x2] = 1;
       -}
       -
       -void
       -showpiece(int c)
       -{
       -        const char *s = "";
       -
       -        /* simple or use unicode character */
       -#if 0
       -        putchar(c);
       -        return;
       -#endif
       -
       -        switch (c) {
       -        case 'K': s = "♔"; break;
       -        case 'Q': s = "♕"; break;
       -        case 'R': s = "♖"; break;
       -        case 'B': s = "♗"; break;
       -        case 'N': s = "♘"; break;
       -        case 'P': s = "♙"; break;
       -        case 'k': s = "♚"; break;
       -        case 'q': s = "♛"; break;
       -        case 'r': s = "♜"; break;
       -        case 'b': s = "♝"; break;
       -        case 'n': s = "♞"; break;
       -        case 'p': s = "♟"; break;
       -        }
       -
       -        if (*s)
       -                fputs(s, stdout);
       -}
       -
       -void
       -showboardfen(void)
       -{
       -        int x, y, piece, skip = 0;
       -
       -        for (y = 0; y < 8; y++) {
       -                if (y > 0)
       -                        putchar('/');
       -                skip = 0;
       -                for (x = 0; x < 8; x++) {
       -                        piece = getpiece(x, y);
       -                        if (piece) {
       -                                if (skip)
       -                                        putchar(skip + '0');
       -                                putchar(piece);
       -                                skip = 0;
       -                        } else {
       -                                skip++;
       -                        }
       -                }
       -                if (skip)
       -                        putchar(skip + '0');
       -        }
       -
       -        /* ? TODO: detect en passant, invalid castling etc? */
       -}
       -
       -/* show board */
       -void
       -showboard(void)
       -{
       -        int *color;
       -        int border[] = { 0x70, 0x49, 0x2d };
       -        int darksquare[] = { 0xb5, 0x88, 0x63 };
       -        int lightsquare[] = { 0xf0, 0xd9, 0xb5 };
       -        int darksquarehi[] = { 0xaa, 0xa2, 0x3a };
       -        int lightsquarehi[] = { 0xcd, 0xd2, 0x6a };
       -        int x, y, piece;
       -
       -        printf("Board FEN:\n");
       -        showboardfen();
       -        printf("\n\n");
       -
       -        SETFGCOLOR(0x00, 0x00, 0x00);
       -
       -        color = border;
       -        SETBGCOLOR(color[0], color[1], color[2]);
       -        SETFGCOLOR(0xff, 0xff, 0xff);
       -        fputs("                             ", stdout);
       -        printf("\x1b[0m"); /* reset */
       -        SETFGCOLOR(0x00, 0x00, 0x00);
       -        putchar('\n');
       -
       -        for (y = 0; y < 8; y++) {
       -                color = border;
       -                SETBGCOLOR(color[0], color[1], color[2]);
       -                SETFGCOLOR(0xff, 0xff, 0xff);
       -                fputs("  ", stdout);
       -
       -                for (x = 0; x < 8; x++) {
       -                        if (x % 2 == 0) {
       -                                if (y % 2 == 0)
       -                                        color = highlight[y][x] ? lightsquarehi : lightsquare;
       -                                else
       -                                        color = highlight[y][x] ? darksquarehi : darksquare;
       -                        } else {
       -                                if (y % 2 == 0)
       -                                        color = highlight[y][x] ? darksquarehi : darksquare;
       -                                else
       -                                        color = highlight[y][x] ? lightsquarehi : lightsquare;
       -                        }
       -                        SETBGCOLOR(color[0], color[1], color[2]);
       -
       -                        fputs(" ", stdout);
       -                        piece = getpiece(x, y);
       -                        if (piece) {
       -                                if (piece >= 'A' && piece <= 'Z')
       -                                        SETFGCOLOR(0xff, 0xff, 0xff);
       -                                else
       -                                        SETFGCOLOR(0x00, 0x00, 0x00);
       -                                /* workaround: use black chess symbol, because the color
       -                                   is filled and better visible */
       -                                showpiece(tolower(piece));
       -                        } else {
       -                                fputs(" ", stdout);
       -                        }
       -                        fputs(" ", stdout);
       -                }
       -                printf("\x1b[0m"); /* reset */
       -
       -                color = border;
       -                SETBGCOLOR(color[0], color[1], color[2]);
       -                SETFGCOLOR(0xff, 0xff, 0xff);
       -                if (showcoords) {
       -                        putchar(' ');
       -                        putchar('8' - y);
       -                        putchar(' ');
       -                } else {
       -                        fputs("   ", stdout);
       -                }
       -
       -                printf("\x1b[0m"); /* reset */
       -                SETFGCOLOR(0x00, 0x00, 0x00);
       -                putchar('\n');
       -        }
       -        color = border;
       -        SETBGCOLOR(color[0], color[1], color[2]);
       -        SETFGCOLOR(0xff, 0xff, 0xff);
       -        if (showcoords)
       -                fputs("   a  b  c  d  e  f  g  h    ", stdout);
       -        else
       -                fputs("                             ", stdout);
       -        printf("\x1b[0m"); /* reset */
       -        printf("\n");
       -        printf("\x1b[0m"); /* reset */
       -
       -#if 0
       -        if (side_to_move == 'w') {
       -                fputs("White to move\n", stdout);
       -        } else if (side_to_move == 'b')
       -                fputs("Black to move\n", stdout);
       -
       -        if (white_can_castle[0])
       -                fputs("White can castle king side\n", stdout);
       -        if (white_can_castle[1])
       -                fputs("White can castle queen side\n", stdout);
       -        if (black_can_castle[0])
       -                fputs("Black can castle king side\n", stdout);
       -        if (black_can_castle[1])
       -                fputs("Black can castle queen side\n", stdout);
       -#endif
       -}
       -
       -int
       -main(int argc, char *argv[])
       -{
       -        const char *fen, *moves, *s;
       -        int x, y, x2, y2, field, piece;
       -        char pieces[] = "PNBRQKpnbrqk", square[3];
       -
       -        if (argc != 3) {
       -                fprintf(stderr, "usage: %s <FEN> <moves>\n", argv[0]);
       -                return 1;
       -        }
       -
       -        fen = argv[1];
       -        moves = argv[2];
       -
       -        /* initial board state, FEN format */
       -        x = y = field = 0;
       -        for (s = fen; *s; s++) {
       -                /* next field, fields are: piece placement data, active color,
       -                   Castling availability, En passant target square,
       -                   Halfmove clock, Fullmove number */
       -                if (*s == ' ') {
       -                        field++;
       -                        continue;
       -                }
       -
       -                switch (field) {
       -                case 0: /* piece placement data */
       -                        /* skip square */
       -                        if (*s >= '1' && *s <= '9') {
       -                                x += (*s - '0');
       -                                continue;
       -                        }
       -                        /* next rank */
       -                        if (*s == '/') {
       -                                x = 0;
       -                                y++;
       -                                continue;
       -                        }
       -                        /* is piece? place it */
       -                        if (strchr(pieces, *s))
       -                                place(*s, x++, y);
       -                        break;
       -                case 1: /* active color */
       -                        if (*s == 'w' || *s == 'b')
       -                                side_to_move = *s;
       -                        break;
       -                case 2: /* castling availability */
       -                        if (*s == '-') {
       -                                white_can_castle[0] = 0;
       -                                white_can_castle[1] = 0;
       -                                black_can_castle[0] = 0;
       -                                black_can_castle[1] = 0;
       -                        } else if (*s == 'K') {
       -                                white_can_castle[0] = 1;
       -                        } else if (*s == 'Q') {
       -                                white_can_castle[1] = 1;
       -                        } else if (*s == 'k') {
       -                                black_can_castle[0] = 1;
       -                        } else if (*s == 'q') {
       -                                black_can_castle[1] = 1;
       -                        }
       -                        break;
       -                case 3: /* TODO: en-passant square, rest of the fields */
       -                        break;
       -                }
       -                /* TODO: parse which side to move, en-passant, etc */
       -        }
       -
       -        /* process moves */
       -        square[2] = '\0';
       -        x = y = x2 = y2 = -1;
       -        for (s = moves; *s; s++) {
       -                if (*s == ' ')
       -                        continue;
       -                if ((*s >= 'a' && *s <= 'h') &&
       -                    (*(s + 1) >= '1' && *(s + 1) <= '8') &&
       -                    (*(s + 2) >= 'a' && *(s + 2) <= 'h') &&
       -                    (*(s + 3) >= '1' && *(s + 3) <= '8')) {
       -                        square[0] = *s;
       -                        square[1] = *(s + 1);
       -
       -                        s += 2;
       -                        squaretoxy(square, &x, &y);
       -                        piece = getpiece(x, y);
       -
       -                        place(0, x, y); /* clear square */
       -
       -                        /* place piece at new location */
       -                        square[0] = *s;
       -                        square[1] = *(s + 1);
       -                        squaretoxy(square, &x2, &y2);
       -                        place(piece, x2, y2);
       -                        s += 2;
       -
       -                        /* possible promotion? (queen, knight, bishop) */
       -                        if (*s == 'q' || *s == 'n' || *s == 'b') {
       -                                if (side_to_move == 'w')
       -                                        piece = toupper(*s);
       -                                else
       -                                        piece = *s;
       -                                place(piece, x2, y2);
       -                                s++;
       -                        }
       -
       -                        /* switch which side it is to move */
       -                        side_to_move = side_to_move == 'b' ? 'w' : 'b';
       -                }
       -        }
       -        /* highlight last move */
       -        highlightmove(x, y, x2, y2);
       -
       -        showboard();
       -
       -        printf("\x1b[0m"); /* reset */
       -
       -        return 0;
       -}