command-line parsing for formats, add OpenBSD pledge - chess-puzzles - chess pu… | |
git clone git://git.codemadness.org/chess-puzzles | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
commit b50c708ac5b44591b62aaa443022625c3fdd44cb | |
parent 3d921c8e0e2011ae994e508e89fc71086fffd598 | |
Author: Hiltjo Posthuma <[email protected]> | |
Date: Wed, 20 Dec 2023 22:31:43 +0100 | |
command-line parsing for formats, add OpenBSD pledge | |
Diffstat: | |
M Makefile | 7 ++----- | |
A fen.c | 730 +++++++++++++++++++++++++++++… | |
D fen_to_svg.c | 700 -----------------------------… | |
3 files changed, 732 insertions(+), 705 deletions(-) | |
--- | |
diff --git a/Makefile b/Makefile | |
@@ -1,8 +1,5 @@ | |
build: clean | |
- ${CC} -o fen_to_svg fen_to_svg.c ${CFLAGS} ${LDFLAGS} | |
- ln -s fen_to_svg fen_to_ascii | |
- ln -s fen_to_svg fen_to_tty | |
- ln -s fen_to_svg fen_to_fen | |
+ ${CC} -o fen fen.c ${CFLAGS} ${LDFLAGS} | |
db: | |
rm -f lichess_db_puzzle.csv.zst lichess_db_puzzle.csv | |
@@ -10,4 +7,4 @@ db: | |
zstd -d < lichess_db_puzzle.csv.zst > lichess_db_puzzle.csv | |
clean: | |
- rm -f fen_to_ascii fen_to_fen fen_to_svg fen_to_tty | |
+ rm -f fen | |
diff --git a/fen.c b/fen.c | |
@@ -0,0 +1,730 @@ | |
+#include <ctype.h> | |
+#include <stdio.h> | |
+#include <stdlib.h> | |
+#include <string.h> | |
+ | |
+#ifdef __OpenBSD__ | |
+#include <err.h> | |
+#include <unistd.h> | |
+#endif | |
+ | |
+/* macro for truecolor RGB output to tty */ | |
+#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]; | |
+ | |
+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 int enpassantsquare[2] = { -1, -1 }; | |
+static int movenumber = 1; | |
+static int halfmove = 0; | |
+ | |
+/* lichess default theme colors */ | |
+static const int border[] = { 0x70, 0x49, 0x2d }; | |
+static const int darksquare[] = { 0xb5, 0x88, 0x63 }; | |
+static const int lightsquare[] = { 0xf0, 0xd9, 0xb5 }; | |
+static const int darksquarehi[] = { 0xaa, 0xa2, 0x3a }; | |
+static const int lightsquarehi[] = { 0xcd, 0xd2, 0x6a }; | |
+ | |
+static int showcoords = 1; /* config: show board coordinates? */ | |
+static int flipboard = 0; /* config: flip board ? */ | |
+ | |
+int | |
+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) | |
+{ | |
+ 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 | |
+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'); | |
+ } | |
+ printf(" %c ", side_to_move); | |
+ if (white_can_castle[0]) | |
+ putchar('K'); | |
+ if (white_can_castle[1]) | |
+ putchar('Q'); | |
+ if (black_can_castle[0]) | |
+ putchar('k'); | |
+ if (black_can_castle[1]) | |
+ putchar('q'); | |
+ if ((white_can_castle[0] + white_can_castle[1] + | |
+ black_can_castle[0] + black_can_castle[1]) == 0) | |
+ putchar('-'); /* no castling for either side */ | |
+ putchar(' '); | |
+ | |
+ if (enpassantsquare[0] != -1 && enpassantsquare[1] != -1) { | |
+ putchar('a' + enpassantsquare[0]); | |
+ putchar('8' - enpassantsquare[1]); | |
+ } else { | |
+ putchar('-'); | |
+ } | |
+ printf(" %d %d", halfmove, movenumber); | |
+} | |
+ | |
+void | |
+showpiece_svg(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 | |
+showboard_svg(void) | |
+{ | |
+ const int *color; | |
+ int ix, iy, x, y, piece; | |
+ | |
+ fputs("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n" | |
+ "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www… | |
+ "<svg width=\"360\" height=\"360\" viewBox=\"0 0 360 360\" xml… | |
+ "<rect fill=\"#fff\" stroke=\"#000\" x=\"0\" y=\"0\" width=\"3… | |
+ | |
+ fputs("<!-- Board FEN: ", stdout); | |
+ showboardfen(); | |
+ fputs(" -->\n", stdout); | |
+ | |
+ for (iy = 0; iy < 8; iy++) { | |
+ y = flipboard ? 7 - iy : iy; | |
+ | |
+ for (ix = 0; ix < 8; ix++) { | |
+ x = flipboard ? 7 - ix : ix; | |
+ | |
+ 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… | |
+ } | |
+ | |
+ printf("<g><rect x=\"%d\" y=\"%d\" width=\"45\" height… | |
+ ix * 45, iy * 45, color[0], color[1], color[2]… | |
+ | |
+ piece = getpiece(x, y); | |
+ if (piece) { | |
+ printf("<g transform=\"translate(%d %d)\">", i… | |
+ showpiece_svg(piece); | |
+ fputs("</g>\n", stdout); | |
+ } | |
+ } | |
+ } | |
+ | |
+ if (showcoords) { | |
+ ix = 7; | |
+ x = flipboard ? 0 : 7; | |
+ for (iy = 0; iy < 8; iy++) { | |
+ y = flipboard ? 7 - iy : iy; | |
+ | |
+ /* inverse square color for text */ | |
+ if (x % 2 == 0) { | |
+ if (y % 2 == 0) | |
+ color = highlight[y][x] ? darksquarehi… | |
+ else | |
+ color = highlight[y][x] ? lightsquareh… | |
+ } else { | |
+ if (y % 2 == 0) | |
+ color = highlight[y][x] ? lightsquareh… | |
+ else | |
+ color = highlight[y][x] ? darksquarehi… | |
+ } | |
+ | |
+ printf("<text x=\"%d\" y=\"%d\" fill=\"#%02x%02x%02x\"… | |
+ (ix + 1) * 45 - 2, (iy * 45) + 10, color[0], c… | |
+ } | |
+ iy = 7; | |
+ y = flipboard ? 0 : 7; | |
+ for (ix = 0; ix < 8; ix++) { | |
+ x = flipboard ? 7 - ix : ix; | |
+ | |
+ /* inverse square color for text */ | |
+ if (x % 2 == 0) { | |
+ if (y % 2 == 0) | |
+ color = highlight[y][x] ? darksquarehi… | |
+ else | |
+ color = highlight[y][x] ? lightsquareh… | |
+ } else { | |
+ if (y % 2 == 0) | |
+ color = highlight[y][x] ? lightsquareh… | |
+ else | |
+ color = highlight[y][x] ? darksquarehi… | |
+ } | |
+ | |
+ printf("<text x=\"%d\" y=\"%d\" fill=\"#%02x%02x%02x\"… | |
+ (ix * 45) + 2, (iy + 1) * 45 - 3, color[0], co… | |
+ } | |
+ } | |
+ | |
+ fputs("</svg>\n", stdout); | |
+} | |
+ | |
+void | |
+showpiece_tty(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); | |
+} | |
+ | |
+/* show board */ | |
+void | |
+showboard_tty(void) | |
+{ | |
+ const int *color; | |
+ int ix, iy, 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 (iy = 0; iy < 8; iy++) { | |
+ y = flipboard ? 7 - iy : iy; | |
+ | |
+ color = border; | |
+ SETBGCOLOR(color[0], color[1], color[2]); | |
+ SETFGCOLOR(0xff, 0xff, 0xff); | |
+ fputs(" ", stdout); | |
+ | |
+ for (ix = 0; ix < 8; ix++) { | |
+ x = flipboard ? 7 - ix : ix; | |
+ | |
+ 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_tty(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) { | |
+ if (flipboard) | |
+ fputs(" h g f e d c b a ", stdout); | |
+ else | |
+ fputs(" a b c d e f g h ", stdout); | |
+ } else { | |
+ fputs(" ", stdout); | |
+ } | |
+ printf("\x1b[0m"); /* reset */ | |
+ printf("\n"); | |
+} | |
+ | |
+void | |
+showpiece_ascii(int c) | |
+{ | |
+ putchar(c); | |
+} | |
+ | |
+/* OnlyFENs */ | |
+void | |
+showboard_fen(void) | |
+{ | |
+ showboardfen(); | |
+ printf("\n"); | |
+} | |
+ | |
+/* show board */ | |
+void | |
+showboard_ascii(void) | |
+{ | |
+ int hi[3] = { '>', ' ', '<' }; | |
+ int dark[3] = { '.', '.', '.' }; | |
+ int light[3] = { ' ', ' ', ' ' }; | |
+ int *color, ix, iy, x, y, piece; | |
+ | |
+ printf("Board FEN:\n"); | |
+ showboardfen(); | |
+ printf("\n\n"); | |
+ | |
+ for (iy = 0; iy < 8; iy++) { | |
+ y = flipboard ? 7 - iy : iy; | |
+ | |
+ fputs("+---+---+---+---+---+---+---+---+\n", stdout); | |
+ for (ix = 0; ix < 8; ix++) { | |
+ x = flipboard ? 7 - ix : ix; | |
+ | |
+ if (x % 2 == 0) { | |
+ if (y % 2 == 0) | |
+ color = highlight[y][x] ? hi : light; | |
+ else | |
+ color = highlight[y][x] ? hi : dark; | |
+ } else { | |
+ if (y % 2 == 0) | |
+ color = highlight[y][x] ? hi : dark; | |
+ else | |
+ color = highlight[y][x] ? hi : light; | |
+ } | |
+ | |
+ if (ix == 0) | |
+ putchar('|'); | |
+ putchar(color[0]); | |
+ piece = getpiece(x, y); | |
+ if (piece) | |
+ showpiece_ascii(piece); | |
+ else | |
+ putchar(color[1]); | |
+ putchar(color[2]); | |
+ putchar('|'); | |
+ } | |
+ if (showcoords) { | |
+ putchar(' '); | |
+ putchar('8' - y); | |
+ } | |
+ putchar('\n'); | |
+ } | |
+ fputs("+---+---+---+---+---+---+---+---+\n", stdout); | |
+ if (showcoords) { | |
+ if (flipboard) | |
+ printf(" h | g | f | e | d | c | b | a |\n"); | |
+ else | |
+ printf(" a | b | c | d | e | f | g | h |\n"); | |
+ } | |
+ | |
+ fputs("\n", stdout); | |
+} | |
+ | |
+void | |
+usage(char *argv0) | |
+{ | |
+ fprintf(stderr, "usage: %s [-cCfF] [-o ascii|fen|tty|svg] [FEN] [moves… | |
+ exit(1); | |
+} | |
+ | |
+int | |
+main(int argc, char *argv[]) | |
+{ | |
+ const char *fen, *moves, *s, *output = "svg"; | |
+ int x, y, x2, y2, field, piece, takepiece; | |
+ int i, j; | |
+ char square[3]; | |
+ long l; | |
+ | |
+#ifdef __OpenBSD__ | |
+ if (pledge("stdio", NULL) = -1) | |
+ err(1, "pledge"); | |
+#endif | |
+ | |
+ fen = "startpos"; | |
+ moves = ""; | |
+ | |
+ for (i = 1; i < argc; i++) { | |
+ if (argv[i][0] != '-') | |
+ break; | |
+ | |
+ for (j = 1; argv[i][j]; j++) { | |
+ switch (argv[i][j]) { | |
+ case 'c': showcoords = 1; break; | |
+ case 'C': showcoords = 0; break; | |
+ case 'f': flipboard = 1; break; | |
+ case 'F': flipboard = 0; break; | |
+ case 'o': | |
+ if (i + 1 >= argc) | |
+ usage(argv[0]); | |
+ output = argv[++i]; | |
+ goto next; | |
+ default: | |
+ usage(argv[0]); | |
+ break; | |
+ } | |
+ } | |
+next: | |
+ } | |
+ if (i < argc) { | |
+ fen = argv[i]; | |
+ i++; | |
+ } | |
+ if (i < argc) { | |
+ moves = argv[i]; | |
+ i++; | |
+ } | |
+ | |
+ if (!strcmp(fen, "startpos")) | |
+ fen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 … | |
+ | |
+ /* initial board state, FEN format */ | |
+ x = y = field = 0; | |
+ for (s = fen; *s && field < 6; s++) { | |
+ 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 (isvalidpiece(*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: /* en passant square */ | |
+ if (*s >= 'a' && *s <= 'h' && | |
+ *(s + 1) >= '1' && *(s + 1) >= '6') { | |
+ | |
+ square[0] = *s; | |
+ square[1] = *(s + 1); | |
+ square[2] = '\0'; | |
+ squaretoxy(square, &x, &y); | |
+ | |
+ enpassantsquare[0] = x; | |
+ enpassantsquare[1] = y; | |
+ } | |
+ break; | |
+ case 4: /* halfmove */ | |
+ if (!(*s >= '0' && *s <= '9')) | |
+ continue; | |
+ | |
+ l = strtol(s, NULL, 10); | |
+ if (l >= 0 && l < 32767) { | |
+ halfmove = l; | |
+ | |
+ for (; *s && isdigit((unsigned char)*s); s++) | |
+ ; | |
+ } | |
+ break; | |
+ case 5: /* move number */ | |
+ if (!(*s >= '0' && *s <= '9')) | |
+ continue; | |
+ | |
+ l = strtol(s, NULL, 10); | |
+ if (l >= 0 && l < 32767) { | |
+ movenumber = (int)l; | |
+ for (; *s && isdigit((unsigned char)*s); s++) | |
+ ; | |
+ } | |
+ break; | |
+ } | |
+ if (!*s) | |
+ break; | |
+ | |
+ /* next field, fields are: piece placement data, active color, | |
+ Castling availability, En passant target square, | |
+ Halfmove clock, Fullmove number */ | |
+ if (*s == ' ') { | |
+ field++; | |
+ continue; | |
+ } | |
+ } | |
+ | |
+ /* 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); | |
+ takepiece = getpiece(x2, y2); | |
+ place(piece, x2, y2); | |
+ s += 2; | |
+ | |
+ /* if pawn move or taken a piece increase halfmove cou… | |
+ if (piece == 'p' || piece == 'P' || takepiece != 0) | |
+ halfmove = 0; | |
+ else | |
+ halfmove++; | |
+ | |
+ /* castling */ | |
+ if (piece == 'K' && y == 7 && y2 == 7 && x == 4) { | |
+ /* white: kingside castling: "e1g1" */ | |
+ if (x2 == 6) { | |
+ place('R', x2 - 1, y2); | |
+ x2 = 7; | |
+ y2 = 7; | |
+ place(0, x2, y2); /* clear rook square… | |
+ } else if (x2 == 2) { | |
+ /* white: queenside castling: "e1c1" */ | |
+ place('R', x2 + 1, y2); | |
+ x2 = 0; | |
+ y2 = 7; | |
+ place(0, x2, y2); | |
+ } | |
+ } else if (piece == 'k' && y == 0 && y2 == 0 && x == 4… | |
+ /* black: kingside castling: "e8g8" */ | |
+ if (x2 == 6) { | |
+ place('r', x2 - 1, y2); | |
+ x2 = 7; | |
+ y2 = 0; | |
+ place(0, x2, y2); /* clear rook square… | |
+ } else if (x2 == 2) { | |
+ /* black: queenside castling: "e8c8" */ | |
+ place('r', x2 + 1, y2); | |
+ x2 = 0; | |
+ y2 = 0; | |
+ place(0, x2, y2); /* clear rook square… | |
+ } | |
+ } | |
+ | |
+ /* remove the ability to castle */ | |
+ if (piece == 'K') { | |
+ white_can_castle[0] = white_can_castle[1] = 0; | |
+ } else if (piece == 'k') { | |
+ black_can_castle[0] = black_can_castle[1] = 0; | |
+ } else if (piece == 'R') { | |
+ if (x == 7 && y == 7) | |
+ white_can_castle[0] = 0; | |
+ else if (x == 0 && y == 7) | |
+ white_can_castle[1] = 0; | |
+ } else if (piece == 'r') { | |
+ if (x == 0 && y == 0) | |
+ black_can_castle[1] = 0; | |
+ else if (x == 7 && y == 0) | |
+ black_can_castle[0] = 0; | |
+ } | |
+ | |
+ /* the en passant square resets after a move */ | |
+ enpassantsquare[0] = -1; | |
+ enpassantsquare[1] = -1; | |
+ /* moved 2 squares and there is an opponent pawn next … | |
+ if (piece == 'P' && y == 6 && y2 == 4) { | |
+ if (getpiece(x - 1, y2) == 'p' || | |
+ getpiece(x + 1, y2) == 'p') { | |
+ enpassantsquare[0] = x; | |
+ enpassantsquare[1] = 5; | |
+ } | |
+ } else if (piece == 'p' && y == 1 && y2 == 3) { | |
+ if (getpiece(x - 1, y2) == 'P' || | |
+ getpiece(x + 1, y2) == 'P') { | |
+ enpassantsquare[0] = x; | |
+ enpassantsquare[1] = 2; | |
+ } | |
+ } | |
+ | |
+ /* possible promotion: queen, knight, bishop */ | |
+ if (*s == 'q' || *s == 'n' || *s == 'b') { | |
+ if (side_to_move == 'w') | |
+ piece = toupper((unsigned char)*s); | |
+ else | |
+ piece = *s; | |
+ place(piece, x2, y2); | |
+ s++; | |
+ } | |
+ | |
+ /* a move by black increases the move number */ | |
+ if (side_to_move == 'b') | |
+ movenumber++; | |
+ | |
+ /* switch which side it is to move */ | |
+ side_to_move = side_to_move == 'b' ? 'w' : 'b'; | |
+ } | |
+ } | |
+ /* highlight last move */ | |
+ highlightmove(x, y, x2, y2); | |
+ | |
+ if (!strcmp(output, "ascii")) | |
+ showboard_ascii(); | |
+ else if (!strcmp(output, "fen")) | |
+ showboard_fen(); | |
+ else if (!strcmp(output, "svg")) | |
+ showboard_svg(); | |
+ else if (!strcmp(output, "tty")) | |
+ showboard_tty(); | |
+ else | |
+ usage(argv[0]); | |
+ | |
+ return 0; | |
+} | |
diff --git a/fen_to_svg.c b/fen_to_svg.c | |
@@ -1,700 +0,0 @@ | |
-/* TODO: output for PGN notation for moves */ | |
- | |
-#include <ctype.h> | |
-#include <stdio.h> | |
-#include <stdlib.h> | |
-#include <string.h> | |
- | |
-/* macro for truecolor RGB output to tty */ | |
-#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]; | |
- | |
-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 int enpassantsquare[2] = { -1, -1 }; | |
-static int movenumber = 1; | |
-static int halfmove = 0; | |
- | |
-/* lichess default theme colors */ | |
-static const int border[] = { 0x70, 0x49, 0x2d }; | |
-static const int darksquare[] = { 0xb5, 0x88, 0x63 }; | |
-static const int lightsquare[] = { 0xf0, 0xd9, 0xb5 }; | |
-static const int darksquarehi[] = { 0xaa, 0xa2, 0x3a }; | |
-static const int lightsquarehi[] = { 0xcd, 0xd2, 0x6a }; | |
- | |
-static int showcoords = 1; /* config: show board coordinates? */ | |
-static int flipboard = 0; /* config: flip board ? */ | |
- | |
-int | |
-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) | |
-{ | |
- 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 | |
-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'); | |
- } | |
- printf(" %c ", side_to_move); | |
- if (white_can_castle[0]) | |
- putchar('K'); | |
- if (white_can_castle[1]) | |
- putchar('Q'); | |
- if (black_can_castle[0]) | |
- putchar('k'); | |
- if (black_can_castle[1]) | |
- putchar('q'); | |
- if ((white_can_castle[0] + white_can_castle[1] + | |
- black_can_castle[0] + black_can_castle[1]) == 0) | |
- putchar('-'); /* no castling for either side */ | |
- putchar(' '); | |
- | |
- if (enpassantsquare[0] != -1 && enpassantsquare[1] != -1) { | |
- putchar('a' + enpassantsquare[0]); | |
- putchar('8' - enpassantsquare[1]); | |
- } else { | |
- putchar('-'); | |
- } | |
- printf(" %d %d", halfmove, movenumber); | |
-} | |
- | |
-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) | |
-{ | |
- const int *color; | |
- int ix, iy, x, y, piece; | |
- | |
- fputs("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n" | |
- "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www… | |
- "<svg width=\"360\" height=\"360\" viewBox=\"0 0 360 360\" xml… | |
- "<rect fill=\"#fff\" stroke=\"#000\" x=\"0\" y=\"0\" width=\"3… | |
- | |
- fputs("<!-- Board FEN: ", stdout); | |
- showboardfen(); | |
- fputs(" -->\n", stdout); | |
- | |
- for (iy = 0; iy < 8; iy++) { | |
- y = flipboard ? 7 - iy : iy; | |
- | |
- for (ix = 0; ix < 8; ix++) { | |
- x = flipboard ? 7 - ix : ix; | |
- | |
- 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… | |
- } | |
- | |
- printf("<g><rect x=\"%d\" y=\"%d\" width=\"45\" height… | |
- ix * 45, iy * 45, color[0], color[1], color[2]… | |
- | |
- piece = getpiece(x, y); | |
- if (piece) { | |
- printf("<g transform=\"translate(%d %d)\">", i… | |
- svg_showpiece(piece); | |
- fputs("</g>\n", stdout); | |
- } | |
- } | |
- } | |
- | |
- if (showcoords) { | |
- ix = 7; | |
- x = flipboard ? 0 : 7; | |
- for (iy = 0; iy < 8; iy++) { | |
- y = flipboard ? 7 - iy : iy; | |
- | |
- /* inverse square color for text */ | |
- if (x % 2 == 0) { | |
- if (y % 2 == 0) | |
- color = highlight[y][x] ? darksquarehi… | |
- else | |
- color = highlight[y][x] ? lightsquareh… | |
- } else { | |
- if (y % 2 == 0) | |
- color = highlight[y][x] ? lightsquareh… | |
- else | |
- color = highlight[y][x] ? darksquarehi… | |
- } | |
- | |
- printf("<text x=\"%d\" y=\"%d\" fill=\"#%02x%02x%02x\"… | |
- (ix + 1) * 45 - 2, (iy * 45) + 10, color[0], c… | |
- } | |
- iy = 7; | |
- y = flipboard ? 0 : 7; | |
- for (ix = 0; ix < 8; ix++) { | |
- x = flipboard ? 7 - ix : ix; | |
- | |
- /* inverse square color for text */ | |
- if (x % 2 == 0) { | |
- if (y % 2 == 0) | |
- color = highlight[y][x] ? darksquarehi… | |
- else | |
- color = highlight[y][x] ? lightsquareh… | |
- } else { | |
- if (y % 2 == 0) | |
- color = highlight[y][x] ? lightsquareh… | |
- else | |
- color = highlight[y][x] ? darksquarehi… | |
- } | |
- | |
- printf("<text x=\"%d\" y=\"%d\" fill=\"#%02x%02x%02x\"… | |
- (ix * 45) + 2, (iy + 1) * 45 - 3, color[0], co… | |
- } | |
- } | |
- | |
- fputs("</svg>\n", stdout); | |
-} | |
- | |
-void | |
-tty_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); | |
-} | |
- | |
-/* show board */ | |
-void | |
-tty_showboard(void) | |
-{ | |
- const int *color; | |
- int ix, iy, 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 (iy = 0; iy < 8; iy++) { | |
- y = flipboard ? 7 - iy : iy; | |
- | |
- color = border; | |
- SETBGCOLOR(color[0], color[1], color[2]); | |
- SETFGCOLOR(0xff, 0xff, 0xff); | |
- fputs(" ", stdout); | |
- | |
- for (ix = 0; ix < 8; ix++) { | |
- x = flipboard ? 7 - ix : ix; | |
- | |
- 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) { | |
- if (flipboard) | |
- fputs(" h g f e d c b a ", stdout); | |
- else | |
- fputs(" a b c d e f g h ", stdout); | |
- } else { | |
- fputs(" ", stdout); | |
- } | |
- printf("\x1b[0m"); /* reset */ | |
- printf("\n"); | |
-} | |
- | |
-void | |
-ascii_showpiece(int c) | |
-{ | |
- putchar(c); | |
-} | |
- | |
-/* OnlyFENs */ | |
-void | |
-fen_showboard(void) | |
-{ | |
- showboardfen(); | |
- printf("\n"); | |
-} | |
- | |
-/* show board */ | |
-void | |
-ascii_showboard(void) | |
-{ | |
- int hi[3] = { '>', ' ', '<' }; | |
- int dark[3] = { '.', '.', '.' }; | |
- int light[3] = { ' ', ' ', ' ' }; | |
- int *color, ix, iy, x, y, piece; | |
- | |
- printf("Board FEN:\n"); | |
- showboardfen(); | |
- printf("\n\n"); | |
- | |
- for (iy = 0; iy < 8; iy++) { | |
- y = flipboard ? 7 - iy : iy; | |
- | |
- fputs("+---+---+---+---+---+---+---+---+\n", stdout); | |
- for (ix = 0; ix < 8; ix++) { | |
- x = flipboard ? 7 - ix : ix; | |
- | |
- if (x % 2 == 0) { | |
- if (y % 2 == 0) | |
- color = highlight[y][x] ? hi : light; | |
- else | |
- color = highlight[y][x] ? hi : dark; | |
- } else { | |
- if (y % 2 == 0) | |
- color = highlight[y][x] ? hi : dark; | |
- else | |
- color = highlight[y][x] ? hi : light; | |
- } | |
- | |
- if (ix == 0) | |
- putchar('|'); | |
- putchar(color[0]); | |
- piece = getpiece(x, y); | |
- if (piece) | |
- ascii_showpiece(piece); | |
- else | |
- putchar(color[1]); | |
- putchar(color[2]); | |
- putchar('|'); | |
- } | |
- if (showcoords) { | |
- putchar(' '); | |
- putchar('8' - y); | |
- } | |
- putchar('\n'); | |
- } | |
- fputs("+---+---+---+---+---+---+---+---+\n", stdout); | |
- if (showcoords) { | |
- if (flipboard) | |
- printf(" h | g | f | e | d | c | b | a |\n"); | |
- else | |
- printf(" a | b | c | d | e | f | g | h |\n"); | |
- } | |
- | |
- fputs("\n", stdout); | |
-} | |
- | |
-int | |
-main(int argc, char *argv[]) | |
-{ | |
- const char *progname, *fen, *moves, *s; | |
- int x, y, x2, y2, field, piece, takepiece; | |
- char square[3]; | |
- long l; | |
- | |
- if (argc > 3) { | |
- fprintf(stderr, "usage: %s <FEN> [moves] or\n", argv[0]); | |
- fprintf(stderr, " %s <FEN> or\n", argv[0]); | |
- fprintf(stderr, " %s\n", argv[0]); | |
- return 1; | |
- } | |
- if (argc > 1) | |
- fen = argv[1]; | |
- else | |
- fen = "startpos"; | |
- | |
- if (argc > 2) | |
- moves = argv[2]; | |
- else | |
- moves = ""; | |
- | |
- if (!strcmp(fen, "startpos")) | |
- fen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 … | |
- | |
- /* initial board state, FEN format */ | |
- x = y = field = 0; | |
- for (s = fen; *s && field < 6; s++) { | |
- 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 (isvalidpiece(*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: /* en passant square */ | |
- if (*s >= 'a' && *s <= 'h' && | |
- *(s + 1) >= '1' && *(s + 1) >= '6') { | |
- | |
- square[0] = *s; | |
- square[1] = *(s + 1); | |
- square[2] = '\0'; | |
- squaretoxy(square, &x, &y); | |
- | |
- enpassantsquare[0] = x; | |
- enpassantsquare[1] = y; | |
- } | |
- break; | |
- case 4: /* halfmove */ | |
- if (!(*s >= '0' && *s <= '9')) | |
- continue; | |
- | |
- l = strtol(s, NULL, 10); | |
- if (l >= 0 && l < 32767) { | |
- halfmove = l; | |
- | |
- for (; *s && isdigit((unsigned char)*s); s++) | |
- ; | |
- } | |
- break; | |
- case 5: /* move number */ | |
- if (!(*s >= '0' && *s <= '9')) | |
- continue; | |
- | |
- l = strtol(s, NULL, 10); | |
- if (l >= 0 && l < 32767) { | |
- movenumber = (int)l; | |
- for (; *s && isdigit((unsigned char)*s); s++) | |
- ; | |
- } | |
- break; | |
- } | |
- if (!*s) | |
- break; | |
- | |
- /* next field, fields are: piece placement data, active color, | |
- Castling availability, En passant target square, | |
- Halfmove clock, Fullmove number */ | |
- if (*s == ' ') { | |
- field++; | |
- continue; | |
- } | |
- } | |
- | |
- /* 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); | |
- takepiece = getpiece(x2, y2); | |
- place(piece, x2, y2); | |
- s += 2; | |
- | |
- /* if pawn move or taken a piece increase halfmove cou… | |
- /* TODO: taking enpassant should reset halfmove too */ | |
- if (piece == 'p' || piece == 'P' || takepiece != 0) | |
- halfmove = 0; | |
- else | |
- halfmove++; | |
- | |
- /* castling */ | |
- if (piece == 'K' && y == 7 && y2 == 7 && x == 4) { | |
- /* white: kingside castling: "e1g1" */ | |
- if (x2 == 6) { | |
- place('R', x2 - 1, y2); | |
- x2 = 7; | |
- y2 = 7; | |
- place(0, x2, y2); /* clear rook square… | |
- } else if (x2 == 2) { | |
- /* white: queenside castling: "e1c1" */ | |
- place('R', x2 + 1, y2); | |
- x2 = 0; | |
- y2 = 7; | |
- place(0, x2, y2); | |
- } | |
- } else if (piece == 'k' && y == 0 && y2 == 0 && x == 4… | |
- /* black: kingside castling: "e8g8" */ | |
- if (x2 == 6) { | |
- place('r', x2 - 1, y2); | |
- x2 = 7; | |
- y2 = 0; | |
- place(0, x2, y2); /* clear rook square… | |
- } else if (x2 == 2) { | |
- /* black: queenside castling: "e8c8" */ | |
- place('r', x2 + 1, y2); | |
- x2 = 0; | |
- y2 = 0; | |
- place(0, x2, y2); /* clear rook square… | |
- } | |
- } | |
- | |
- /* remove the ability to castle */ | |
- if (piece == 'K') { | |
- white_can_castle[0] = white_can_castle[1] = 0; | |
- } else if (piece == 'k') { | |
- black_can_castle[0] = black_can_castle[1] = 0; | |
- } else if (piece == 'R') { | |
- if (x == 7 && y == 7) | |
- white_can_castle[0] = 0; | |
- else if (x == 0 && y == 7) | |
- white_can_castle[1] = 0; | |
- } else if (piece == 'r') { | |
- if (x == 0 && y == 0) | |
- black_can_castle[1] = 0; | |
- else if (x == 7 && y == 0) | |
- black_can_castle[0] = 0; | |
- } | |
- | |
- /* the en passant square resets after a move */ | |
- enpassantsquare[0] = -1; | |
- enpassantsquare[1] = -1; | |
- /* moved 2 squares and there is an opponent pawn next … | |
- if (piece == 'P' && y == 6 && y2 == 4) { | |
- if (getpiece(x - 1, y2) == 'p' || | |
- getpiece(x + 1, y2) == 'p') { | |
- enpassantsquare[0] = x; | |
- enpassantsquare[1] = 5; | |
- } | |
- } else if (piece == 'p' && y == 1 && y2 == 3) { | |
- if (getpiece(x - 1, y2) == 'P' || | |
- getpiece(x + 1, y2) == 'P') { | |
- enpassantsquare[0] = x; | |
- enpassantsquare[1] = 2; | |
- } | |
- } | |
- | |
- /* possible promotion: queen, knight, bishop */ | |
- if (*s == 'q' || *s == 'n' || *s == 'b') { | |
- if (side_to_move == 'w') | |
- piece = toupper((unsigned char)*s); | |
- else | |
- piece = *s; | |
- place(piece, x2, y2); | |
- s++; | |
- } | |
- | |
- /* a move by black increases the move number */ | |
- if (side_to_move == 'b') | |
- movenumber++; | |
- | |
- /* switch which side it is to move */ | |
- side_to_move = side_to_move == 'b' ? 'w' : 'b'; | |
- | |
- /* TODO: reset enpassant square if applicable */ | |
- } | |
- } | |
- /* highlight last move */ | |
- highlightmove(x, y, x2, y2); | |
- | |
- 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 if (!strcmp(progname, "fen_to_fen")) | |
- fen_showboard(); | |
- else | |
- svg_showboard(); | |
- | |
- return 0; | |
-} |