| 184 /* Result */ |
184 /* Result */ |
| 185 char *result; |
185 char *result; |
| 186 if (gamestate->stalemate || gamestate->remis) { |
186 if (gamestate->stalemate || gamestate->remis) { |
| 187 result = "1/2-1/2"; |
187 result = "1/2-1/2"; |
| 188 } else if (gamestate->checkmate || gamestate->resign) { |
188 } else if (gamestate->checkmate || gamestate->resign) { |
| 189 if (gamestate->lastmove) { |
189 if (gamestate->movecount > 0) { |
| 190 result = (gamestate->lastmove->move.piece & COLOR_MASK) == WHITE ? |
190 result = (last_move(gamestate).piece & COLOR_MASK) == WHITE ? |
| 191 "1-0" : "0-1"; |
191 "1-0" : "0-1"; |
| 192 } else { |
192 } else { |
| 193 result = "0-1"; |
193 result = "0-1"; |
| 194 } |
194 } |
| 195 } else { |
195 } else { |
| 196 result = "*"; |
196 result = "*"; |
| 197 } |
197 } |
| 198 fprintf(stream, "[Result \"%s\"]\n\n", result); |
198 fprintf(stream, "[Result \"%s\"]\n\n", result); |
| 199 |
199 |
| 200 /* moves */ |
200 /* moves */ |
| 201 int i = 1; |
201 for (unsigned i = 0 ; i < gamestate->movecount ; i++) { |
| 202 for (MoveList *movelist = gamestate->movelist ; |
202 |
| 203 movelist ; movelist = movelist->next) { |
203 if (i % 2 == 0) { |
| 204 |
204 fprintf(stream, "%d. %s", 1+i/2, gamestate->moves[i].string); |
| 205 if (++i % 2 == 0) { |
|
| 206 fprintf(stream, "%d. %s", i/2, movelist->move.string); |
|
| 207 } else { |
205 } else { |
| 208 fprintf(stream, " %s", movelist->move.string); |
206 fprintf(stream, "%s", gamestate->moves[i].string); |
| 209 } |
207 } |
| 210 |
208 |
| 211 // TODO: move time and maybe other comments |
209 // TODO: move time and maybe other comments |
| 212 |
210 |
| 213 /* line break every 10 moves */ |
211 /* line break every 10 half-moves */ |
| 214 if ((i-1) % 20) { |
212 if ((i+1) % 10) { |
| 215 fputc(' ', stream); |
213 fputc(' ', stream); |
| 216 } else { |
214 } else { |
| 217 fputc('\n', stream); |
215 fputc('\n', stream); |
| 218 } |
216 } |
| 219 } |
217 } |
| 266 |
264 |
| 267 return i; |
265 return i; |
| 268 } |
266 } |
| 269 |
267 |
| 270 static size_t fen_color(char *str, GameState *gamestate) { |
268 static size_t fen_color(char *str, GameState *gamestate) { |
| 271 uint8_t color = opponent_color(gamestate->lastmove ? |
269 uint8_t color = opponent_color(gamestate->movecount > 0 ? |
| 272 (gamestate->lastmove->move.piece & COLOR_MASK) : BLACK); |
270 (last_move(gamestate).piece & COLOR_MASK) : BLACK); |
| 273 |
271 |
| 274 str[0] = color == WHITE ? 'w' : 'b'; |
272 str[0] = color == WHITE ? 'w' : 'b'; |
| 275 |
273 |
| 276 return 1; |
274 return 1; |
| 277 } |
275 } |
| 278 |
276 |
| 279 static bool fen_castling_chkmoved(GameState *gamestate, |
277 static bool fen_castling_chkmoved(GameState *gamestate, |
| 280 uint8_t row, uint8_t file) { |
278 uint8_t row, uint8_t file) { |
| 281 |
279 |
| 282 MoveList *ml = gamestate->movelist; |
280 for (unsigned i = 0 ; i < gamestate->movecount ; i++) { |
| 283 while (ml) { |
281 if (gamestate->moves[i].fromfile == file |
| 284 if (ml->move.fromfile == file && ml->move.fromrow == row) { |
282 && gamestate->moves[i].fromrow == row) { |
| 285 return true; |
283 return true; |
| 286 } |
284 } |
| 287 ml = ml->next; |
|
| 288 } |
285 } |
| 289 |
286 |
| 290 return false; |
287 return false; |
| 291 } |
288 } |
| 292 |
289 |
| 333 |
330 |
| 334 return str[0] == '-' ? 1 : 2; |
331 return str[0] == '-' ? 1 : 2; |
| 335 } |
332 } |
| 336 |
333 |
| 337 static size_t fen_halfmove(char *str, GameState *gamestate) { |
334 static size_t fen_halfmove(char *str, GameState *gamestate) { |
| 338 |
335 unsigned int hm = 0; |
| 339 unsigned int i = 0; |
336 for (unsigned int i = 0; i < gamestate->movecount; i++) { |
| 340 for (MoveList *move = gamestate->movelist ; move ; move = move->next) { |
337 if (gamestate->moves[i].capture |
| 341 if (move->move.capture || (move->move.piece & PIECE_MASK) == PAWN) { |
338 || (gamestate->moves[i].piece & PIECE_MASK) == PAWN) { |
| 342 i = 0; |
339 hm = 0; |
| 343 } else { |
340 } else { |
| 344 i++; |
341 hm++; |
| 345 } |
342 } |
| 346 } |
343 } |
| 347 |
344 |
| 348 char m[8]; |
345 return sprintf(str, "%u", hm); |
| 349 size_t len = sprintf(m, "%u", i); |
|
| 350 memcpy(str, m, len); |
|
| 351 |
|
| 352 return len; |
|
| 353 } |
346 } |
| 354 |
347 |
| 355 static size_t fen_movenr(char *str, GameState *gamestate) { |
348 static size_t fen_movenr(char *str, GameState *gamestate) { |
| 356 |
349 return sprintf(str, "%u", gamestate->movecount); |
| 357 MoveList *move = gamestate->movelist; |
|
| 358 unsigned int i = 1; |
|
| 359 while (move) { |
|
| 360 i++; |
|
| 361 move = move->next; |
|
| 362 } |
|
| 363 |
|
| 364 char m[8]; |
|
| 365 size_t len = sprintf(m, "%u", i); |
|
| 366 memcpy(str, m, len); |
|
| 367 |
|
| 368 return len; |
|
| 369 } |
350 } |
| 370 |
351 |
| 371 void compute_fen(char *str, GameState *gamestate) { |
352 void compute_fen(char *str, GameState *gamestate) { |
| 372 str += fen_pieces(str, gamestate); |
353 str += fen_pieces(str, gamestate); |
| 373 *str = ' '; str++; |
354 *str = ' '; str++; |