-\r
-// fen.c\r
-\r
-// includes\r
-\r
-#include <ctype.h>\r
-#include <stdio.h>\r
-#include <stdlib.h>\r
-\r
-#include "board.h"\r
-#include "colour.h"\r
-#include "fen.h"\r
-#include "option.h"\r
-#include "piece.h"\r
-#include "square.h"\r
-#include "util.h"\r
-\r
-// "constants"\r
-\r
-// const char * StartFen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w HAha - 0 1";\r
-const char * StartFen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";\r
-\r
-// variables\r
-\r
-static const bool Strict = FALSE;\r
-\r
-// macros\r
-\r
-#define skip_white_space() \\r
- c=string[pos];\\r
- if (c != ' ' && c!='\t') my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); \\r
- while(c==' ' || c=='\t') c=string[++pos];\r
-\r
-\r
-// functions\r
-\r
-// board_from_fen()\r
-\r
-bool board_from_fen(board_t * board, const char string[]) {\r
-\r
- int pos;\r
- int file, rank, sq;\r
- int c;\r
- int i, len;\r
- int piece;\r
- int king_pos[ColourNb];\r
-\r
- ASSERT(board!=NULL);\r
- ASSERT(string!=NULL);\r
-\r
- board_clear(board);\r
-\r
- king_pos[White] = SquareNone;\r
- king_pos[Black] = SquareNone;\r
-\r
- pos = 0;\r
- c = string[pos];\r
-\r
- // piece placement\r
-\r
- for (rank = 7; rank >= 0; rank--) {\r
-\r
- for (file = 0; file < 8;) {\r
-\r
- sq = square_make(file,rank);\r
-\r
- if (c >= '1' && c <= '8') { // empty square(s)\r
-\r
- len = c - '0';\r
- if (file + len > 8) my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos);\r
-\r
- for (i = 0; i < len; i++) {\r
- board->square[sq++] = Empty;\r
- file++;\r
- }\r
-\r
- } else { // piece\r
-\r
- piece = piece_from_char(c);\r
- if (piece == PieceNone256) my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos);\r
-\r
- if (piece_is_king(piece)) king_pos[piece_colour(piece)] = sq;\r
-\r
- board->square[sq++] = piece;\r
- file++;\r
- }\r
-\r
- c = string[++pos];\r
- }\r
-\r
- if (rank > 0) {\r
- if (c != '/') my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos);\r
- c = string[++pos];\r
- }\r
- }\r
-\r
- // active colour\r
-\r
- skip_white_space();\r
-\r
- switch (c) {\r
- case 'w':\r
- board->turn = White;\r
- break;\r
- case 'b':\r
- board->turn = Black;\r
- break;\r
- default:\r
- my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos);\r
- break;\r
- }\r
-\r
- c = string[++pos];\r
-\r
- // castling\r
-\r
- skip_white_space();\r
-\r
- board->castle[White][SideH] = SquareNone;\r
- board->castle[White][SideA] = SquareNone;\r
- board->castle[Black][SideH] = SquareNone;\r
- board->castle[Black][SideA] = SquareNone;\r
-\r
- if (c == '-') { // no castling rights\r
-\r
- c = string[++pos];\r
-\r
- } else {\r
-\r
- // TODO: filter out illegal rights\r
-\r
- do {\r
-\r
- if (FALSE) {\r
-\r
- } else if (c == 'K') {\r
-\r
- for (sq = H1; sq > king_pos[White]; sq--) {\r
- if (board->square[sq] == WhiteRook256) {\r
- board->castle[White][SideH] = sq;\r
- break;\r
- }\r
- }\r
-\r
- } else if (c == 'Q') {\r
-\r
- for (sq = A1; sq < king_pos[White]; sq++) {\r
- if (board->square[sq] == WhiteRook256) {\r
- board->castle[White][SideA] = sq;\r
- break;\r
- }\r
- }\r
-\r
- } else if (c == 'k') {\r
-\r
- for (sq = H8; sq > king_pos[Black]; sq--) {\r
- if (board->square[sq] == BlackRook256) {\r
- board->castle[Black][SideH] = sq;\r
- break;\r
- }\r
- }\r
-\r
- } else if (c == 'q') {\r
-\r
- for (sq = A8; sq < king_pos[Black]; sq++) {\r
- if (board->square[sq] == BlackRook256) {\r
- board->castle[Black][SideA] = sq;\r
- break;\r
- }\r
- }\r
-\r
- } else if (c >= 'A' && c <= 'H') {\r
-\r
- // white castling right\r
-\r
- sq = square_make(file_from_char(tolower(c)),Rank1);\r
-\r
- if (sq > king_pos[White]) { // h side\r
- board->castle[White][SideH] = sq;\r
- } else { // a side\r
- board->castle[White][SideA] = sq;\r
- }\r
-\r
- } else if (c >= 'a' && c <= 'h') {\r
-\r
- // black castling right\r
-\r
- sq = square_make(file_from_char(tolower(c)),Rank8);\r
-\r
- if (sq > king_pos[Black]) { // h side\r
- board->castle[Black][SideH] = sq;\r
- } else { // a side\r
- board->castle[Black][SideA] = sq;\r
- }\r
-\r
- } else {\r
-\r
- my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos);\r
- }\r
-\r
- c = string[++pos];\r
-\r
- } while (c != ' ');\r
- }\r
-\r
- // en-passant\r
-\r
- skip_white_space();\r
-\r
- if (c == '-') { // no en-passant\r
-\r
- sq = SquareNone;\r
- c = string[++pos];\r
-\r
- } else {\r
-\r
- if (c < 'a' || c > 'h') my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos);\r
- file = file_from_char(c);\r
- c = string[++pos];\r
-\r
- if (c < '1' || c > '8') my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos);\r
- rank = rank_from_char(c);\r
- c = string[++pos];\r
-\r
- sq = square_make(file,rank);\r
- }\r
-\r
- board->ep_square = sq;\r
-\r
- // halfmove clock\r
-\r
- board->ply_nb = 0;\r
- board->move_nb = 0; // HACK, in case of broken syntax\r
-\r
- if (c != ' ') {\r
- if (!Strict) goto update;\r
- my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos);\r
- }\r
- c = string[++pos];\r
-\r
- if (!isdigit(c)) {\r
- if (!Strict) goto update;\r
- my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos);\r
- }\r
-\r
- board->ply_nb = atoi(&string[pos]);\r
- do c = string[++pos]; while (isdigit(c));\r
-\r
- // fullmove number\r
-\r
- board->move_nb = 0;\r
-\r
- if (c != ' ') {\r
- if (!Strict) goto update;\r
- my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos);\r
- }\r
- c = string[++pos];\r
-\r
- if (!isdigit(c)) {\r
- if (!Strict) goto update;\r
- my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos);\r
- }\r
-\r
- board->move_nb = atoi(&string[pos]) - 1;\r
- do c = string[++pos]; while (isdigit(c));\r
-\r
- // board update\r
-\r
-update:\r
- board_init_list(board);\r
-\r
- return TRUE;\r
-}\r
-\r
-// board_to_fen()\r
-\r
-bool board_to_fen(const board_t * board, char string[], int size) {\r
-\r
- int pos;\r
- int file, rank;\r
- int sq, piece;\r
- int c;\r
- int len;\r
- int old_pos;\r
-\r
- ASSERT(board_is_ok(board));\r
- ASSERT(string!=NULL);\r
- ASSERT(size>=92);\r
-\r
- // init\r
-\r
- if (size < 92) return FALSE;\r
-\r
- pos = 0;\r
-\r
- // piece placement\r
-\r
- for (rank = 7; rank >= 0; rank--) {\r
-\r
- for (file = 0; file < 8;) {\r
-\r
- sq = square_make(file,rank);\r
- piece = board->square[sq];\r
- ASSERT(piece==Empty||piece_is_ok(piece));\r
-\r
- if (piece == Empty) {\r
-\r
- len = 0;\r
- for (; file < 8 && board->square[square_make(file,rank)] == Empty; file++) {\r
- len++;\r
- }\r
-\r
- ASSERT(len>=1&&len<=8);\r
- c = '0' + len;\r
-\r
- } else {\r
-\r
- c = piece_to_char(piece);\r
- file++;\r
- }\r
-\r
- string[pos++] = c;\r
- }\r
-\r
- string[pos++] = '/';\r
- }\r
-\r
- string[pos-1] = ' '; // HACK: remove the last '/'\r
-\r
- // active colour\r
-\r
- string[pos++] = (colour_is_white(board->turn)) ? 'w' : 'b';\r
- string[pos++] = ' ';\r
-\r
- // castling\r
-\r
- old_pos = pos;\r
-\r
- if (option_get_bool(Option,"Chess960")) {\r
-\r
- // FEN-960\r
-\r
- if (board->castle[White][SideH] != SquareNone) {\r
- string[pos++] = toupper(file_to_char(square_file(board->castle[White][SideH])));\r
- }\r
-\r
- if (board->castle[White][SideA] != SquareNone) {\r
- string[pos++] = toupper(file_to_char(square_file(board->castle[White][SideA])));\r
- }\r
-\r
- if (board->castle[Black][SideH] != SquareNone) {\r
- string[pos++] = tolower(file_to_char(square_file(board->castle[Black][SideH])));\r
- }\r
-\r
- if (board->castle[Black][SideA] != SquareNone) {\r
- string[pos++] = tolower(file_to_char(square_file(board->castle[Black][SideA])));\r
- }\r
-\r
- } else {\r
-\r
- // FEN\r
-\r
- if (board->castle[White][SideH] != SquareNone) string[pos++] = 'K';\r
- if (board->castle[White][SideA] != SquareNone) string[pos++] = 'Q';\r
- if (board->castle[Black][SideH] != SquareNone) string[pos++] = 'k';\r
- if (board->castle[Black][SideA] != SquareNone) string[pos++] = 'q';\r
- }\r
-\r
- if (pos == old_pos) string[pos++] = '-';\r
-\r
- string[pos++] = ' ';\r
-\r
- // en-passant\r
-\r
- if (board->ep_square == SquareNone) {\r
- string[pos++] = '-';\r
- } else {\r
- if (!square_to_string(board->ep_square,&string[pos],3)) return FALSE;\r
- pos += 2;\r
- }\r
-\r
- string[pos++] = ' ';\r
-\r
- // halfmove clock and fullmove number\r
-\r
- sprintf(&string[pos],"%d %d",board->ply_nb,board->move_nb+1);\r
-\r
- return TRUE;\r
-}\r
-\r
-// end of fen.cpp\r
-\r
+
+// fen.c
+
+// includes
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "board.h"
+#include "colour.h"
+#include "fen.h"
+#include "option.h"
+#include "piece.h"
+#include "square.h"
+#include "util.h"
+
+// "constants"
+
+// const char * StartFen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w HAha - 0 1";
+const char * StartFen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
+
+// variables
+
+static const bool Strict = FALSE;
+
+// macros
+
+#define skip_white_space() \
+ c=string[pos];\
+ if (c != ' ' && c!='\t') my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); \
+ while(c==' ' || c=='\t') c=string[++pos];
+
+
+// functions
+
+// board_from_fen()
+
+bool board_from_fen(board_t * board, const char string[]) {
+
+ int pos;
+ int file, rank, sq;
+ int c;
+ int i, len;
+ int piece;
+ int king_pos[ColourNb];
+
+ ASSERT(board!=NULL);
+ ASSERT(string!=NULL);
+
+ board_clear(board);
+
+ king_pos[White] = SquareNone;
+ king_pos[Black] = SquareNone;
+
+ pos = 0;
+ c = string[pos];
+
+ // piece placement
+
+ for (rank = 7; rank >= 0; rank--) {
+
+ for (file = 0; file < 8;) {
+
+ sq = square_make(file,rank);
+
+ if (c >= '1' && c <= '8') { // empty square(s)
+
+ len = c - '0';
+ if (file + len > 8) my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos);
+
+ for (i = 0; i < len; i++) {
+ board->square[sq++] = Empty;
+ file++;
+ }
+
+ } else { // piece
+
+ piece = piece_from_char(c);
+ if (piece == PieceNone256) my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos);
+
+ if (piece_is_king(piece)) king_pos[piece_colour(piece)] = sq;
+
+ board->square[sq++] = piece;
+ file++;
+ }
+
+ c = string[++pos];
+ }
+
+ if (rank > 0) {
+ if (c != '/') my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos);
+ c = string[++pos];
+ }
+ }
+
+ // active colour
+
+ skip_white_space();
+
+ switch (c) {
+ case 'w':
+ board->turn = White;
+ break;
+ case 'b':
+ board->turn = Black;
+ break;
+ default:
+ my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos);
+ break;
+ }
+
+ c = string[++pos];
+
+ // castling
+
+ skip_white_space();
+
+ board->castle[White][SideH] = SquareNone;
+ board->castle[White][SideA] = SquareNone;
+ board->castle[Black][SideH] = SquareNone;
+ board->castle[Black][SideA] = SquareNone;
+
+ if (c == '-') { // no castling rights
+
+ c = string[++pos];
+
+ } else {
+
+ // TODO: filter out illegal rights
+
+ do {
+
+ if (FALSE) {
+
+ } else if (c == 'K') {
+
+ for (sq = H1; sq > king_pos[White]; sq--) {
+ if (board->square[sq] == WhiteRook256) {
+ board->castle[White][SideH] = sq;
+ break;
+ }
+ }
+
+ } else if (c == 'Q') {
+
+ for (sq = A1; sq < king_pos[White]; sq++) {
+ if (board->square[sq] == WhiteRook256) {
+ board->castle[White][SideA] = sq;
+ break;
+ }
+ }
+
+ } else if (c == 'k') {
+
+ for (sq = H8; sq > king_pos[Black]; sq--) {
+ if (board->square[sq] == BlackRook256) {
+ board->castle[Black][SideH] = sq;
+ break;
+ }
+ }
+
+ } else if (c == 'q') {
+
+ for (sq = A8; sq < king_pos[Black]; sq++) {
+ if (board->square[sq] == BlackRook256) {
+ board->castle[Black][SideA] = sq;
+ break;
+ }
+ }
+
+ } else if (c >= 'A' && c <= 'H') {
+
+ // white castling right
+
+ sq = square_make(file_from_char(tolower(c)),Rank1);
+
+ if (sq > king_pos[White]) { // h side
+ board->castle[White][SideH] = sq;
+ } else { // a side
+ board->castle[White][SideA] = sq;
+ }
+
+ } else if (c >= 'a' && c <= 'h') {
+
+ // black castling right
+
+ sq = square_make(file_from_char(tolower(c)),Rank8);
+
+ if (sq > king_pos[Black]) { // h side
+ board->castle[Black][SideH] = sq;
+ } else { // a side
+ board->castle[Black][SideA] = sq;
+ }
+
+ } else {
+
+ my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos);
+ }
+
+ c = string[++pos];
+
+ } while (c != ' ');
+ }
+
+ // en-passant
+
+ skip_white_space();
+
+ if (c == '-') { // no en-passant
+
+ sq = SquareNone;
+ c = string[++pos];
+
+ } else {
+
+ if (c < 'a' || c > 'h') my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos);
+ file = file_from_char(c);
+ c = string[++pos];
+
+ if (c < '1' || c > '8') my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos);
+ rank = rank_from_char(c);
+ c = string[++pos];
+
+ sq = square_make(file,rank);
+ }
+
+ board->ep_square = sq;
+
+ // halfmove clock
+
+ board->ply_nb = 0;
+ board->move_nb = 0; // HACK, in case of broken syntax
+
+ if (c != ' ') {
+ if (!Strict) goto update;
+ my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos);
+ }
+ c = string[++pos];
+
+ if (!isdigit(c)) {
+ if (!Strict) goto update;
+ my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos);
+ }
+
+ board->ply_nb = atoi(&string[pos]);
+ do c = string[++pos]; while (isdigit(c));
+
+ // fullmove number
+
+ board->move_nb = 0;
+
+ if (c != ' ') {
+ if (!Strict) goto update;
+ my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos);
+ }
+ c = string[++pos];
+
+ if (!isdigit(c)) {
+ if (!Strict) goto update;
+ my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos);
+ }
+
+ board->move_nb = atoi(&string[pos]) - 1;
+ do c = string[++pos]; while (isdigit(c));
+
+ // board update
+
+update:
+ board_init_list(board);
+
+ return TRUE;
+}
+
+// board_to_fen()
+
+bool board_to_fen(const board_t * board, char string[], int size) {
+
+ int pos;
+ int file, rank;
+ int sq, piece;
+ int c;
+ int len;
+ int old_pos;
+
+ ASSERT(board_is_ok(board));
+ ASSERT(string!=NULL);
+ ASSERT(size>=92);
+
+ // init
+
+ if (size < 92) return FALSE;
+
+ pos = 0;
+
+ // piece placement
+
+ for (rank = 7; rank >= 0; rank--) {
+
+ for (file = 0; file < 8;) {
+
+ sq = square_make(file,rank);
+ piece = board->square[sq];
+ ASSERT(piece==Empty||piece_is_ok(piece));
+
+ if (piece == Empty) {
+
+ len = 0;
+ for (; file < 8 && board->square[square_make(file,rank)] == Empty; file++) {
+ len++;
+ }
+
+ ASSERT(len>=1&&len<=8);
+ c = '0' + len;
+
+ } else {
+
+ c = piece_to_char(piece);
+ file++;
+ }
+
+ string[pos++] = c;
+ }
+
+ string[pos++] = '/';
+ }
+
+ string[pos-1] = ' '; // HACK: remove the last '/'
+
+ // active colour
+
+ string[pos++] = (colour_is_white(board->turn)) ? 'w' : 'b';
+ string[pos++] = ' ';
+
+ // castling
+
+ old_pos = pos;
+
+ if (option_get_bool(Option,"Chess960")) {
+
+ // FEN-960
+
+ if (board->castle[White][SideH] != SquareNone) {
+ string[pos++] = toupper(file_to_char(square_file(board->castle[White][SideH])));
+ }
+
+ if (board->castle[White][SideA] != SquareNone) {
+ string[pos++] = toupper(file_to_char(square_file(board->castle[White][SideA])));
+ }
+
+ if (board->castle[Black][SideH] != SquareNone) {
+ string[pos++] = tolower(file_to_char(square_file(board->castle[Black][SideH])));
+ }
+
+ if (board->castle[Black][SideA] != SquareNone) {
+ string[pos++] = tolower(file_to_char(square_file(board->castle[Black][SideA])));
+ }
+
+ } else {
+
+ // FEN
+
+ if (board->castle[White][SideH] != SquareNone) string[pos++] = 'K';
+ if (board->castle[White][SideA] != SquareNone) string[pos++] = 'Q';
+ if (board->castle[Black][SideH] != SquareNone) string[pos++] = 'k';
+ if (board->castle[Black][SideA] != SquareNone) string[pos++] = 'q';
+ }
+
+ if (pos == old_pos) string[pos++] = '-';
+
+ string[pos++] = ' ';
+
+ // en-passant
+
+ if (board->ep_square == SquareNone) {
+ string[pos++] = '-';
+ } else {
+ if (!square_to_string(board->ep_square,&string[pos],3)) return FALSE;
+ pos += 2;
+ }
+
+ string[pos++] = ' ';
+
+ // halfmove clock and fullmove number
+
+ sprintf(&string[pos],"%d %d",board->ply_nb,board->move_nb+1);
+
+ return TRUE;
+}
+
+// end of fen.cpp
+