merge code together, symlink binaries - chess-puzzles - chess puzzle book gener… | |
git clone git://git.codemadness.org/chess-puzzles | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
commit d7273cde403340578a406a58fc419ae03277a84f | |
parent 318de62766d2fd0caa0594f939cd1b2d9d143e0a | |
Author: Hiltjo Posthuma <[email protected]> | |
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(-) | |
--- | |
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 | |
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 sid… | |
-static int black_can_castle[2] = { 0, 0 }; /* allow king side, allow queen sid… | |
- | |
-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; | |
-} | |
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/publ… | |
- switch (c) { | |
- case 'K': s = "<g fill=\"none\" fill-rule=\"evenodd\" stroke=\"#000\" … | |
- case 'Q': s = "<g fill=\"#fff\" fill-rule=\"evenodd\" stroke=\"#000\" … | |
- case 'R': s = "<g fill=\"#fff\" fill-rule=\"evenodd\" stroke=\"#000\" … | |
- case 'B': s = "<g fill=\"none\" fill-rule=\"evenodd\" stroke=\"#000\" … | |
- case 'N': s = "<g fill=\"none\" fill-rule=\"evenodd\" stroke=\"#000\" … | |
- case 'P': s = "<path d=\"M22.5 9c-2.21 0-4 1.79-4 4 0 .89.29 1.71.78 2… | |
- case 'k': s = "<g fill=\"none\" fill-rule=\"evenodd\" stroke=\"#000\" … | |
- case 'q': s = "<g fill-rule=\"evenodd\" stroke=\"#000\" stroke-width=\… | |
- case 'r': s = "<g fill-rule=\"evenodd\" stroke=\"#000\" stroke-width=\… | |
- case 'b': s = "<g fill=\"none\" fill-rule=\"evenodd\" stroke=\"#000\" … | |
- case 'n': s = "<g fill=\"none\" fill-rule=\"evenodd\" stroke=\"#000\" … | |
- case 'p': s = "<path d=\"M22.5 9c-2.21 0-4 1.79-4 4 0 .89.29 1.71.78 2… | |
- } | |
- | |
- 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/publ… | |
+ switch (c) { | |
+ case 'K': s = "<g fill=\"none\" fill-rule=\"evenodd\" stroke=\"#000\" … | |
+ case 'Q': s = "<g fill=\"#fff\" fill-rule=\"evenodd\" stroke=\"#000\" … | |
+ case 'R': s = "<g fill=\"#fff\" fill-rule=\"evenodd\" stroke=\"#000\" … | |
+ case 'B': s = "<g fill=\"none\" fill-rule=\"evenodd\" stroke=\"#000\" … | |
+ case 'N': s = "<g fill=\"none\" fill-rule=\"evenodd\" stroke=\"#000\" … | |
+ case 'P': s = "<path d=\"M22.5 9c-2.21 0-4 1.79-4 4 0 .89.29 1.71.78 2… | |
+ case 'k': s = "<g fill=\"none\" fill-rule=\"evenodd\" stroke=\"#000\" … | |
+ case 'q': s = "<g fill-rule=\"evenodd\" stroke=\"#000\" stroke-width=\… | |
+ case 'r': s = "<g fill-rule=\"evenodd\" stroke=\"#000\" stroke-width=\… | |
+ case 'b': s = "<g fill=\"none\" fill-rule=\"evenodd\" stroke=\"#000\" … | |
+ case 'n': s = "<g fill=\"none\" fill-rule=\"evenodd\" stroke=\"#000\" … | |
+ case 'p': s = "<path d=\"M22.5 9c-2.21 0-4 1.79-4 4 0 .89.29 1.71.78 2… | |
+ } | |
+ | |
+ 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… | |
- 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] ? lightsquareh… | |
+ else | |
+ color = highlight[y][x] ? darksquarehi… | |
+ } else { | |
+ if (y % 2 == 0) | |
+ color = highlight[y][x] ? darksquarehi… | |
+ else | |
+ color = highlight[y][x] ? lightsquareh… | |
+ } | |
+ 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… | |
+ 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; | |
} | |
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 sid… | |
-static int black_can_castle[2] = { 0, 0 }; /* allow king side, allow queen sid… | |
- | |
-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] ? lightsquareh… | |
- else | |
- color = highlight[y][x] ? darksquarehi… | |
- } else { | |
- if (y % 2 == 0) | |
- color = highlight[y][x] ? darksquarehi… | |
- else | |
- color = highlight[y][x] ? lightsquareh… | |
- } | |
- 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… | |
- 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; | |
-} |