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