192 } |
192 } |
193 |
193 |
194 |
194 |
195 return bytes; |
195 return bytes; |
196 } |
196 } |
|
197 |
|
198 static size_t fen_pieces(char *str, GameState *gamestate) { |
|
199 size_t i = 0; |
|
200 for (int row = 7 ; row >= 0 ; row--) { |
|
201 unsigned int skip = 0; |
|
202 for (int file = 0 ; file < 8 ; file++) { |
|
203 if (gamestate->board[row][file]) { |
|
204 if (skip > 0) { |
|
205 str[i++] = '0'+skip; |
|
206 skip = 0; |
|
207 } |
|
208 switch (gamestate->board[row][file] & ~ENPASSANT_THREAT) { |
|
209 case WHITE|KING: str[i++] = 'K'; break; |
|
210 case WHITE|QUEEN: str[i++] = 'Q'; break; |
|
211 case WHITE|BISHOP: str[i++] = 'B'; break; |
|
212 case WHITE|KNIGHT: str[i++] = 'N'; break; |
|
213 case WHITE|ROOK: str[i++] = 'R'; break; |
|
214 case WHITE|PAWN: str[i++] = 'P'; break; |
|
215 case BLACK|KING: str[i++] = 'k'; break; |
|
216 case BLACK|QUEEN: str[i++] = 'q'; break; |
|
217 case BLACK|BISHOP: str[i++] = 'b'; break; |
|
218 case BLACK|KNIGHT: str[i++] = 'n'; break; |
|
219 case BLACK|ROOK: str[i++] = 'r'; break; |
|
220 case BLACK|PAWN: str[i++] = 'p'; break; |
|
221 } |
|
222 } else { |
|
223 skip++; |
|
224 } |
|
225 } |
|
226 if (skip > 0) { |
|
227 str[i++] = '0'+skip; |
|
228 } |
|
229 if (row > 0) { |
|
230 str[i++] = '/'; |
|
231 } |
|
232 } |
|
233 |
|
234 return i; |
|
235 } |
|
236 |
|
237 static size_t fen_color(char *str, GameState *gamestate) { |
|
238 uint8_t color = opponent_color(gamestate->lastmove ? |
|
239 (gamestate->lastmove->move.piece & COLOR_MASK) : BLACK); |
|
240 |
|
241 str[0] = color == WHITE ? 'w' : 'b'; |
|
242 |
|
243 return 1; |
|
244 } |
|
245 |
|
246 static _Bool fen_castling_chkmoved(GameState *gamestate, |
|
247 uint8_t row, uint8_t file) { |
|
248 |
|
249 MoveList *ml = gamestate->movelist; |
|
250 while (ml) { |
|
251 if (ml->move.fromfile == file && ml->move.fromrow == row) { |
|
252 return 1; |
|
253 } |
|
254 ml = ml->next; |
|
255 } |
|
256 |
|
257 return 0; |
|
258 } |
|
259 |
|
260 static size_t fen_castling(char *str, GameState *gamestate) { |
|
261 _Bool K, Q, k, q; |
|
262 |
|
263 if (fen_castling_chkmoved(gamestate, rowidx('1'), fileidx('e'))) { |
|
264 K = Q = 0; |
|
265 } else { |
|
266 K = !fen_castling_chkmoved(gamestate, rowidx('1'), fileidx('h')); |
|
267 Q = !fen_castling_chkmoved(gamestate, rowidx('1'), fileidx('a')); |
|
268 } |
|
269 if (fen_castling_chkmoved(gamestate, rowidx('8'), fileidx('e'))) { |
|
270 k = q = 0; |
|
271 } else { |
|
272 k = !fen_castling_chkmoved(gamestate, rowidx('8'), fileidx('h')); |
|
273 q = !fen_castling_chkmoved(gamestate, rowidx('8'), fileidx('a')); |
|
274 } |
|
275 |
|
276 size_t i = 0; |
|
277 if (K) str[i++] = 'K'; |
|
278 if (Q) str[i++] = 'Q'; |
|
279 if (k) str[i++] = 'k'; |
|
280 if (q) str[i++] = 'q'; |
|
281 if (!i) str[i++] = '-'; |
|
282 |
|
283 return i; |
|
284 } |
|
285 |
|
286 static size_t fen_enpassant(char *str, GameState *gamestate) { |
|
287 |
|
288 str[0] = '-'; str[1] = '\0'; |
|
289 |
|
290 for (int file = 0 ; file < 8 ; file++) { |
|
291 if (gamestate->board[3][file] & ENPASSANT_THREAT) { |
|
292 str[0] = filechr(file); |
|
293 str[1] = rowchr(2); |
|
294 } |
|
295 if (gamestate->board[4][file] & ENPASSANT_THREAT) { |
|
296 str[0] = filechr(file); |
|
297 str[1] = rowchr(5); |
|
298 } |
|
299 } |
|
300 |
|
301 return str[0] == '-' ? 1 : 2; |
|
302 } |
|
303 |
|
304 static size_t fen_halfmove(char *str, GameState *gamestate) { |
|
305 |
|
306 unsigned int i = 0; |
|
307 for (MoveList *move = gamestate->movelist ; move ; move = move->next) { |
|
308 if (move->move.capture || (move->move.piece & PIECE_MASK) == PAWN) { |
|
309 i = 0; |
|
310 } else { |
|
311 i++; |
|
312 } |
|
313 } |
|
314 |
|
315 char m[8]; |
|
316 size_t len = sprintf(m, "%u", i); |
|
317 memcpy(str, m, len); |
|
318 |
|
319 return len; |
|
320 } |
|
321 |
|
322 static size_t fen_movenr(char *str, GameState *gamestate) { |
|
323 |
|
324 MoveList *move = gamestate->movelist; |
|
325 unsigned int i = 1; |
|
326 while (move) { |
|
327 i++; |
|
328 move = move->next; |
|
329 } |
|
330 |
|
331 char m[8]; |
|
332 size_t len = sprintf(m, "%u", i); |
|
333 memcpy(str, m, len); |
|
334 |
|
335 return len; |
|
336 } |
|
337 |
|
338 void compute_fen(char *str, GameState *gamestate) { |
|
339 str += fen_pieces(str, gamestate); |
|
340 *str = ' '; str++; |
|
341 str += fen_color(str, gamestate); |
|
342 *str = ' '; str++; |
|
343 str += fen_castling(str, gamestate); |
|
344 *str = ' '; str++; |
|
345 str += fen_enpassant(str, gamestate); |
|
346 *str = ' '; str++; |
|
347 str += fen_halfmove(str, gamestate); |
|
348 *str = ' '; str++; |
|
349 str += fen_movenr(str, gamestate); |
|
350 str[0] = '\0'; |
|
351 } |