20 // const char * StartFen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w HAha - 0 1";
\r
21 const char * StartFen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
\r
25 static const bool Strict = FALSE;
\r
29 #define skip_white_space() \
\r
31 if (c != ' ' && c!='\t') my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); \
\r
32 while(c==' ' || c=='\t') c=string[++pos];
\r
39 bool board_from_fen(board_t * board, const char string[]) {
\r
46 int king_pos[ColourNb];
\r
48 ASSERT(board!=NULL);
\r
49 ASSERT(string!=NULL);
\r
53 king_pos[White] = SquareNone;
\r
54 king_pos[Black] = SquareNone;
\r
61 for (rank = 7; rank >= 0; rank--) {
\r
63 for (file = 0; file < 8;) {
\r
65 sq = square_make(file,rank);
\r
67 if (c >= '1' && c <= '8') { // empty square(s)
\r
70 if (file + len > 8) my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos);
\r
72 for (i = 0; i < len; i++) {
\r
73 board->square[sq++] = Empty;
\r
79 piece = piece_from_char(c);
\r
80 if (piece == PieceNone256) my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos);
\r
82 if (piece_is_king(piece)) king_pos[piece_colour(piece)] = sq;
\r
84 board->square[sq++] = piece;
\r
92 if (c != '/') my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos);
\r
103 board->turn = White;
\r
106 board->turn = Black;
\r
109 my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos);
\r
117 skip_white_space();
\r
119 board->castle[White][SideH] = SquareNone;
\r
120 board->castle[White][SideA] = SquareNone;
\r
121 board->castle[Black][SideH] = SquareNone;
\r
122 board->castle[Black][SideA] = SquareNone;
\r
124 if (c == '-') { // no castling rights
\r
130 // TODO: filter out illegal rights
\r
136 } else if (c == 'K') {
\r
138 for (sq = H1; sq > king_pos[White]; sq--) {
\r
139 if (board->square[sq] == WhiteRook256) {
\r
140 board->castle[White][SideH] = sq;
\r
145 } else if (c == 'Q') {
\r
147 for (sq = A1; sq < king_pos[White]; sq++) {
\r
148 if (board->square[sq] == WhiteRook256) {
\r
149 board->castle[White][SideA] = sq;
\r
154 } else if (c == 'k') {
\r
156 for (sq = H8; sq > king_pos[Black]; sq--) {
\r
157 if (board->square[sq] == BlackRook256) {
\r
158 board->castle[Black][SideH] = sq;
\r
163 } else if (c == 'q') {
\r
165 for (sq = A8; sq < king_pos[Black]; sq++) {
\r
166 if (board->square[sq] == BlackRook256) {
\r
167 board->castle[Black][SideA] = sq;
\r
172 } else if (c >= 'A' && c <= 'H') {
\r
174 // white castling right
\r
176 sq = square_make(file_from_char(tolower(c)),Rank1);
\r
178 if (sq > king_pos[White]) { // h side
\r
179 board->castle[White][SideH] = sq;
\r
181 board->castle[White][SideA] = sq;
\r
184 } else if (c >= 'a' && c <= 'h') {
\r
186 // black castling right
\r
188 sq = square_make(file_from_char(tolower(c)),Rank8);
\r
190 if (sq > king_pos[Black]) { // h side
\r
191 board->castle[Black][SideH] = sq;
\r
193 board->castle[Black][SideA] = sq;
\r
198 my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos);
\r
203 } while (c != ' ');
\r
208 skip_white_space();
\r
210 if (c == '-') { // no en-passant
\r
217 if (c < 'a' || c > 'h') my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos);
\r
218 file = file_from_char(c);
\r
221 if (c < '1' || c > '8') my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos);
\r
222 rank = rank_from_char(c);
\r
225 sq = square_make(file,rank);
\r
228 board->ep_square = sq;
\r
233 board->move_nb = 0; // HACK, in case of broken syntax
\r
236 if (!Strict) goto update;
\r
237 my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos);
\r
242 if (!Strict) goto update;
\r
243 my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos);
\r
246 board->ply_nb = atoi(&string[pos]);
\r
247 do c = string[++pos]; while (isdigit(c));
\r
251 board->move_nb = 0;
\r
254 if (!Strict) goto update;
\r
255 my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos);
\r
260 if (!Strict) goto update;
\r
261 my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos);
\r
264 board->move_nb = atoi(&string[pos]) - 1;
\r
265 do c = string[++pos]; while (isdigit(c));
\r
270 board_init_list(board);
\r
277 bool board_to_fen(const board_t * board, char string[], int size) {
\r
286 ASSERT(board_is_ok(board));
\r
287 ASSERT(string!=NULL);
\r
292 if (size < 92) return FALSE;
\r
298 for (rank = 7; rank >= 0; rank--) {
\r
300 for (file = 0; file < 8;) {
\r
302 sq = square_make(file,rank);
\r
303 piece = board->square[sq];
\r
304 ASSERT(piece==Empty||piece_is_ok(piece));
\r
306 if (piece == Empty) {
\r
309 for (; file < 8 && board->square[square_make(file,rank)] == Empty; file++) {
\r
313 ASSERT(len>=1&&len<=8);
\r
318 c = piece_to_char(piece);
\r
325 string[pos++] = '/';
\r
328 string[pos-1] = ' '; // HACK: remove the last '/'
\r
332 string[pos++] = (colour_is_white(board->turn)) ? 'w' : 'b';
\r
333 string[pos++] = ' ';
\r
339 if (option_get_bool(Option,"Chess960")) {
\r
343 if (board->castle[White][SideH] != SquareNone) {
\r
344 string[pos++] = toupper(file_to_char(square_file(board->castle[White][SideH])));
\r
347 if (board->castle[White][SideA] != SquareNone) {
\r
348 string[pos++] = toupper(file_to_char(square_file(board->castle[White][SideA])));
\r
351 if (board->castle[Black][SideH] != SquareNone) {
\r
352 string[pos++] = tolower(file_to_char(square_file(board->castle[Black][SideH])));
\r
355 if (board->castle[Black][SideA] != SquareNone) {
\r
356 string[pos++] = tolower(file_to_char(square_file(board->castle[Black][SideA])));
\r
363 if (board->castle[White][SideH] != SquareNone) string[pos++] = 'K';
\r
364 if (board->castle[White][SideA] != SquareNone) string[pos++] = 'Q';
\r
365 if (board->castle[Black][SideH] != SquareNone) string[pos++] = 'k';
\r
366 if (board->castle[Black][SideA] != SquareNone) string[pos++] = 'q';
\r
369 if (pos == old_pos) string[pos++] = '-';
\r
371 string[pos++] = ' ';
\r
375 if (board->ep_square == SquareNone) {
\r
376 string[pos++] = '-';
\r
378 if (!square_to_string(board->ep_square,&string[pos],3)) return FALSE;
\r
382 string[pos++] = ' ';
\r
384 // halfmove clock and fullmove number
\r
386 sprintf(&string[pos],"%d %d",board->ply_nb,board->move_nb+1);
\r