src/chess/pgn.c

changeset 132
5762f2b5f87a
parent 130
3fc6b1d6cbe9
equal deleted inserted replaced
131:c33567d61ba7 132:5762f2b5f87a
360 pgn_insert_newlines(moveblk); 360 pgn_insert_newlines(moveblk);
361 fputs(moveblk, stream); 361 fputs(moveblk, stream);
362 362
363 free(moveblk); 363 free(moveblk);
364 } 364 }
365
366 static size_t fen_pieces(char *str, GameState *gamestate) {
367 size_t i = 0;
368 for (int row = 7 ; row >= 0 ; row--) {
369 unsigned int skip = 0;
370 for (int file = 0 ; file < 8 ; file++) {
371 if (gamestate->board[row][file]) {
372 if (skip > 0) {
373 str[i++] = '0'+skip;
374 skip = 0;
375 }
376 switch (gamestate->board[row][file] & ~ENPASSANT_THREAT) {
377 case WHITE|KING: str[i++] = 'K'; break;
378 case WHITE|QUEEN: str[i++] = 'Q'; break;
379 case WHITE|BISHOP: str[i++] = 'B'; break;
380 case WHITE|KNIGHT: str[i++] = 'N'; break;
381 case WHITE|ROOK: str[i++] = 'R'; break;
382 case WHITE|PAWN: str[i++] = 'P'; break;
383 case BLACK|KING: str[i++] = 'k'; break;
384 case BLACK|QUEEN: str[i++] = 'q'; break;
385 case BLACK|BISHOP: str[i++] = 'b'; break;
386 case BLACK|KNIGHT: str[i++] = 'n'; break;
387 case BLACK|ROOK: str[i++] = 'r'; break;
388 case BLACK|PAWN: str[i++] = 'p'; break;
389 }
390 } else {
391 skip++;
392 }
393 }
394 if (skip > 0) {
395 str[i++] = '0'+skip;
396 }
397 if (row > 0) {
398 str[i++] = '/';
399 }
400 }
401
402 return i;
403 }
404
405 static size_t fen_color(char *str, GameState *gamestate) {
406 uint8_t color = opponent_color(gamestate->movecount > 0 ?
407 (last_move(gamestate).piece & COLOR_MASK) : BLACK);
408
409 str[0] = color == WHITE ? 'w' : 'b';
410
411 return 1;
412 }
413
414 static bool fen_castling_chkmoved(GameState *gamestate,
415 uint8_t row, uint8_t file) {
416
417 for (unsigned i = 0 ; i < gamestate->movecount ; i++) {
418 if (gamestate->moves[i].fromfile == file
419 && gamestate->moves[i].fromrow == row) {
420 return true;
421 }
422 }
423
424 return false;
425 }
426
427 static size_t fen_castling(char *str, GameState *gamestate) {
428 bool K, Q, k, q;
429
430 if (fen_castling_chkmoved(gamestate, rowidx('1'), fileidx('e'))) {
431 K = Q = false;
432 } else {
433 K = !fen_castling_chkmoved(gamestate, rowidx('1'), fileidx('h'));
434 Q = !fen_castling_chkmoved(gamestate, rowidx('1'), fileidx('a'));
435 }
436 if (fen_castling_chkmoved(gamestate, rowidx('8'), fileidx('e'))) {
437 k = q = false;
438 } else {
439 k = !fen_castling_chkmoved(gamestate, rowidx('8'), fileidx('h'));
440 q = !fen_castling_chkmoved(gamestate, rowidx('8'), fileidx('a'));
441 }
442
443 size_t i = 0;
444 if (K) str[i++] = 'K';
445 if (Q) str[i++] = 'Q';
446 if (k) str[i++] = 'k';
447 if (q) str[i++] = 'q';
448 if (!i) str[i++] = '-';
449
450 return i;
451 }
452
453 static size_t fen_enpassant(char *str, GameState *gamestate) {
454
455 str[0] = '-'; str[1] = '\0';
456
457 for (int file = 0 ; file < 8 ; file++) {
458 if (gamestate->board[3][file] & ENPASSANT_THREAT) {
459 str[0] = filechr(file);
460 str[1] = rowchr(2);
461 }
462 if (gamestate->board[4][file] & ENPASSANT_THREAT) {
463 str[0] = filechr(file);
464 str[1] = rowchr(5);
465 }
466 }
467
468 return str[0] == '-' ? 1 : 2;
469 }
470
471 static size_t fen_halfmove(char *str, GameState *gamestate) {
472 unsigned int hm = 0;
473 for (unsigned int i = 0; i < gamestate->movecount; i++) {
474 if (gamestate->moves[i].capture
475 || (gamestate->moves[i].piece & PIECE_MASK) == PAWN) {
476 hm = 0;
477 } else {
478 hm++;
479 }
480 }
481
482 return sprintf(str, "%u", hm);
483 }
484
485 static size_t fen_movenr(char *str, GameState *gamestate) {
486 return sprintf(str, "%u", gamestate->movecount);
487 }
488
489 void compute_fen(char *str, GameState *gamestate) {
490 str += fen_pieces(str, gamestate);
491 *str = ' '; str++;
492 str += fen_color(str, gamestate);
493 *str = ' '; str++;
494 str += fen_castling(str, gamestate);
495 *str = ' '; str++;
496 str += fen_enpassant(str, gamestate);
497 *str = ' '; str++;
498 str += fen_halfmove(str, gamestate);
499 *str = ' '; str++;
500 str += fen_movenr(str, gamestate);
501 str[0] = '\0';
502 }

mercurial