Check in polyglot-1.4w10UCIb15
[polyglot.git] / fen.cpp
1 \r
2 // fen.cpp\r
3 \r
4 // includes\r
5 \r
6 #include <cctype>\r
7 #include <cstdio>\r
8 #include <cstdlib>\r
9 \r
10 #include "board.h"\r
11 #include "colour.h"\r
12 #include "fen.h"\r
13 #include "option.h"\r
14 #include "piece.h"\r
15 #include "square.h"\r
16 #include "util.h"\r
17 \r
18 // "constants"\r
19 \r
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
22 \r
23 // variables\r
24 \r
25 static const bool Strict = false;\r
26 \r
27 // macros\r
28 \r
29 #define skip_white_space() \\r
30         c=string[pos];\\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
33 \r
34 \r
35 // functions\r
36 \r
37 // board_from_fen()\r
38 \r
39 bool board_from_fen(board_t * board, const char string[]) {\r
40 \r
41    int pos;\r
42    int file, rank, sq;\r
43    int c;\r
44    int i, len;\r
45    int piece;\r
46    int king_pos[ColourNb];\r
47 \r
48    ASSERT(board!=NULL);\r
49    ASSERT(string!=NULL);\r
50 \r
51    board_clear(board);\r
52 \r
53    king_pos[White] = SquareNone;\r
54    king_pos[Black] = SquareNone;\r
55 \r
56    pos = 0;\r
57    c = string[pos];\r
58 \r
59    // piece placement\r
60 \r
61    for (rank = 7; rank >= 0; rank--) {\r
62 \r
63       for (file = 0; file < 8;) {\r
64 \r
65          sq = square_make(file,rank);\r
66 \r
67          if (c >= '1' && c <= '8') { // empty square(s)\r
68 \r
69             len = c - '0';\r
70             if (file + len > 8) my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos);\r
71 \r
72             for (i = 0; i < len; i++) {\r
73                board->square[sq++] = Empty;\r
74                file++;\r
75             }\r
76 \r
77          } else { // piece\r
78 \r
79             piece = piece_from_char(c);\r
80             if (piece == PieceNone256) my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos);\r
81 \r
82             if (piece_is_king(piece)) king_pos[piece_colour(piece)] = sq;\r
83 \r
84             board->square[sq++] = piece;\r
85             file++;\r
86          }\r
87 \r
88          c = string[++pos];\r
89       }\r
90 \r
91       if (rank > 0) {\r
92          if (c != '/') my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos);\r
93          c = string[++pos];\r
94      }\r
95    }\r
96 \r
97    // active colour\r
98 \r
99    skip_white_space();\r
100 \r
101    switch (c) {\r
102    case 'w':\r
103       board->turn = White;\r
104       break;\r
105    case 'b':\r
106       board->turn = Black;\r
107       break;\r
108    default:\r
109       my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos);\r
110       break;\r
111    }\r
112 \r
113    c = string[++pos];\r
114 \r
115    // castling\r
116 \r
117    skip_white_space();\r
118 \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
123 \r
124    if (c == '-') { // no castling rights\r
125 \r
126       c = string[++pos];\r
127 \r
128    } else {\r
129 \r
130       // TODO: filter out illegal rights\r
131 \r
132       do {\r
133 \r
134          if (false) {\r
135 \r
136          } else if (c == 'K') {\r
137 \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
141                   break;\r
142                }\r
143             }\r
144 \r
145          } else if (c == 'Q') {\r
146 \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
150                   break;\r
151                }\r
152             }\r
153 \r
154          } else if (c == 'k') {\r
155 \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
159                   break;\r
160                }\r
161             }\r
162 \r
163          } else if (c == 'q') {\r
164 \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
168                   break;\r
169                }\r
170             }\r
171 \r
172          } else if (c >= 'A' && c <= 'H') {\r
173 \r
174             // white castling right\r
175 \r
176             sq = square_make(file_from_char(tolower(c)),Rank1);\r
177 \r
178             if (sq > king_pos[White]) { // h side\r
179                board->castle[White][SideH] = sq;\r
180             } else { // a side\r
181                board->castle[White][SideA] = sq;\r
182             }\r
183 \r
184          } else if (c >= 'a' && c <= 'h') {\r
185 \r
186             // black castling right\r
187 \r
188             sq = square_make(file_from_char(tolower(c)),Rank8);\r
189 \r
190             if (sq > king_pos[Black]) { // h side\r
191                board->castle[Black][SideH] = sq;\r
192             } else { // a side\r
193                board->castle[Black][SideA] = sq;\r
194             }\r
195 \r
196          } else {\r
197 \r
198             my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos);\r
199          }\r
200 \r
201          c = string[++pos];\r
202 \r
203       } while (c != ' ');\r
204    }\r
205 \r
206    // en-passant\r
207 \r
208    skip_white_space();\r
209 \r
210    if (c == '-') { // no en-passant\r
211 \r
212       sq = SquareNone;\r
213       c = string[++pos];\r
214 \r
215    } else {\r
216 \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
219       c = string[++pos];\r
220 \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
223       c = string[++pos];\r
224 \r
225       sq = square_make(file,rank);\r
226    }\r
227 \r
228    board->ep_square = sq;\r
229 \r
230    // halfmove clock\r
231 \r
232    board->ply_nb = 0;\r
233    board->move_nb = 0; // HACK, in case of broken syntax\r
234 \r
235    if (c != ' ') {\r
236       if (!Strict) goto update;\r
237       my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos);\r
238    }\r
239    c = string[++pos];\r
240 \r
241    if (!isdigit(c)) {\r
242       if (!Strict) goto update;\r
243       my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos);\r
244    }\r
245 \r
246    board->ply_nb = atoi(&string[pos]);\r
247    do c = string[++pos]; while (isdigit(c));\r
248 \r
249    // fullmove number\r
250 \r
251    board->move_nb = 0;\r
252 \r
253    if (c != ' ') {\r
254       if (!Strict) goto update;\r
255       my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos);\r
256    }\r
257    c = string[++pos];\r
258 \r
259    if (!isdigit(c)) {\r
260       if (!Strict) goto update;\r
261       my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos);\r
262    }\r
263 \r
264    board->move_nb = atoi(&string[pos]) - 1;\r
265    do c = string[++pos]; while (isdigit(c));\r
266 \r
267    // board update\r
268 \r
269 update:\r
270    board_init_list(board);\r
271 \r
272    return true;\r
273 }\r
274 \r
275 // board_to_fen()\r
276 \r
277 bool board_to_fen(const board_t * board, char string[], int size) {\r
278 \r
279    int pos;\r
280    int file, rank;\r
281    int sq, piece;\r
282    int c;\r
283    int len;\r
284    int old_pos;\r
285 \r
286    ASSERT(board_is_ok(board));\r
287    ASSERT(string!=NULL);\r
288    ASSERT(size>=92);\r
289 \r
290    // init\r
291 \r
292    if (size < 92) return false;\r
293 \r
294    pos = 0;\r
295 \r
296    // piece placement\r
297 \r
298    for (rank = 7; rank >= 0; rank--) {\r
299 \r
300       for (file = 0; file < 8;) {\r
301 \r
302          sq = square_make(file,rank);\r
303          piece = board->square[sq];\r
304          ASSERT(piece==Empty||piece_is_ok(piece));\r
305 \r
306          if (piece == Empty) {\r
307 \r
308             len = 0;\r
309             for (; file < 8 && board->square[square_make(file,rank)] == Empty; file++) {\r
310                len++;\r
311             }\r
312 \r
313             ASSERT(len>=1&&len<=8);\r
314             c = '0' + len;\r
315 \r
316          } else {\r
317 \r
318             c = piece_to_char(piece);\r
319             file++;\r
320          }\r
321 \r
322          string[pos++] = c;\r
323       }\r
324 \r
325       string[pos++] = '/';\r
326    }\r
327 \r
328    string[pos-1] = ' '; // HACK: remove the last '/'\r
329 \r
330    // active colour\r
331 \r
332    string[pos++] = (colour_is_white(board->turn)) ? 'w' : 'b';\r
333    string[pos++] = ' ';\r
334 \r
335    // castling\r
336 \r
337    old_pos = pos;\r
338 \r
339    if (option_get_bool("Chess960")) {\r
340 \r
341       // FEN-960\r
342 \r
343       if (board->castle[White][SideH] != SquareNone) {\r
344          string[pos++] = toupper(file_to_char(square_file(board->castle[White][SideH])));\r
345       }\r
346 \r
347       if (board->castle[White][SideA] != SquareNone) {\r
348          string[pos++] = toupper(file_to_char(square_file(board->castle[White][SideA])));\r
349       }\r
350 \r
351       if (board->castle[Black][SideH] != SquareNone) {\r
352          string[pos++] = tolower(file_to_char(square_file(board->castle[Black][SideH])));\r
353       }\r
354 \r
355       if (board->castle[Black][SideA] != SquareNone) {\r
356          string[pos++] = tolower(file_to_char(square_file(board->castle[Black][SideA])));\r
357       }\r
358 \r
359    } else {\r
360 \r
361       // FEN\r
362 \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
367    }\r
368 \r
369    if (pos == old_pos) string[pos++] = '-';\r
370 \r
371    string[pos++] = ' ';\r
372 \r
373    // en-passant\r
374 \r
375    if (board->ep_square == SquareNone) {\r
376       string[pos++] = '-';\r
377    } else {\r
378       if (!square_to_string(board->ep_square,&string[pos],3)) return false;\r
379       pos += 2;\r
380    }\r
381 \r
382    string[pos++] = ' ';\r
383 \r
384    // halfmove clock and fullmove number\r
385 \r
386    sprintf(&string[pos],"%d %d",board->ply_nb,board->move_nb+1);\r
387 \r
388    return true;\r
389 }\r
390 \r
391 // end of fen.cpp\r
392 \r