chess-puzzles

chess puzzle book generator
git clone git://git.codemadness.org/chess-puzzles
Log | Files | Refs | README | LICENSE

fen_to_ascii.c (5802B)


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