Subversion Repositories Games.Chess Giants

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
112 pmbaty 1
/*
2
    Protector -- a UCI chess engine
3
 
4
    Copyright (C) 2009-2010 Raimund Heid (Raimund_Heid@yahoo.com)
5
 
6
    This program is free software: you can redistribute it and/or modify
7
    it under the terms of the GNU General Public License as published by
8
    the Free Software Foundation, either version 3 of the License, or
9
    (at your option) any later version.
10
 
11
    This program is distributed in the hope that it will be useful,
12
    but WITHOUT ANY WARRANTY; without even the implied warranty of
13
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
    GNU General Public License for more details.
15
 
16
    You should have received a copy of the GNU General Public License
17
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18
 
19
*/
20
 
21
#include "fen.h"
22
#include <string.h>
23
#include <stdlib.h>
24
#include <ctype.h>
25
#include <stdio.h>
26
#include <assert.h>
27
 
28
static int initialized = 0;
29
static Piece pieceCode[256];
30
static char pieceToken[16];
31
 
32
static void initialize()
33
{
34
   if (!initialized)
35
   {
36
      int i;
37
 
38
      for (i = 0; i < 256; i++)
39
      {
40
         pieceCode[i] = NO_PIECE;
41
      }
42
 
43
      pieceCode['K'] = WHITE_KING;
44
      pieceCode['Q'] = WHITE_QUEEN;
45
      pieceCode['R'] = WHITE_ROOK;
46
      pieceCode['B'] = WHITE_BISHOP;
47
      pieceCode['N'] = WHITE_KNIGHT;
48
      pieceCode['P'] = WHITE_PAWN;
49
      pieceCode['k'] = BLACK_KING;
50
      pieceCode['q'] = BLACK_QUEEN;
51
      pieceCode['r'] = BLACK_ROOK;
52
      pieceCode['b'] = BLACK_BISHOP;
53
      pieceCode['n'] = BLACK_KNIGHT;
54
      pieceCode['p'] = BLACK_PAWN;
55
 
56
      pieceToken[WHITE_KING] = 'K';
57
      pieceToken[WHITE_QUEEN] = 'Q';
58
      pieceToken[WHITE_ROOK] = 'R';
59
      pieceToken[WHITE_BISHOP] = 'B';
60
      pieceToken[WHITE_KNIGHT] = 'N';
61
      pieceToken[WHITE_PAWN] = 'P';
62
      pieceToken[BLACK_KING] = 'k';
63
      pieceToken[BLACK_QUEEN] = 'q';
64
      pieceToken[BLACK_ROOK] = 'r';
65
      pieceToken[BLACK_BISHOP] = 'b';
66
      pieceToken[BLACK_KNIGHT] = 'n';
67
      pieceToken[BLACK_PAWN] = 'p';
68
 
69
      initialized = 1;
70
   }
71
}
72
 
73
static int setPieces(const char *fen, Position * position)
74
{
75
   Square square;
76
   Rank rank = RANK_8;
77
   File file = FILE_A;
78
   Piece p;
79
   int index = 0;
80
   int imax = (int) (strlen(fen)) - 1;
81
   char current = '\0';
82
 
83
   ITERATE(square)
84
   {
85
      position->piece[square] = NO_PIECE;
86
   }
87
 
88
   while (index <= imax && (current = fen[index]) != ' ')
89
   {
90
      if (current == '/')
91
      {
92
         rank--;
93
         file = FILE_A;
94
      }
95
      else if (current >= '1' && current <= '8')
96
      {
97
         file = (File) (file + current - '0');
98
      }
99
      else
100
      {
101
         p = pieceCode[(int) current];
102
 
103
         if (p != NO_PIECE)
104
         {
105
            position->piece[getSquare(file, rank)] = p;
106
            file++;
107
         }
108
         else
109
         {
110
            return -1;
111
         }
112
      }
113
 
114
      index++;
115
   }
116
 
117
   return rank == RANK_1 ? index : -1;
118
}
119
 
120
static int stringContainsChar(char *string, char c)
121
{
122
   while (*string != '\0')
123
   {
124
      if (*(string++) == c)
125
      {
126
         return 1;
127
      }
128
   }
129
 
130
   return 0;
131
}
132
 
133
int readFen(const char *fen, Position * position)
134
{
135
   int index;
136
 
137
   /*
138
    * Initialize this module.
139
    */
140
   initialize();
141
 
142
   /*
143
    * Get the piece positions.
144
    */
145
   if ((index = setPieces(fen, position)) < 0)
146
   {
147
      return -1;
148
   }
149
 
150
   /*
151
    * Get the active color.
152
    */
153
   while (fen[index] == ' ')
154
   {
155
      index++;
156
   }
157
 
158
   if (stringContainsChar("bw", fen[index]))
159
   {
160
      position->activeColor = (fen[index] == 'w' ? WHITE : BLACK);
161
      index++;
162
   }
163
   else
164
   {
165
      return -1;                /* fen format error */
166
   }
167
 
168
   /*
169
    * Get the castling rights.
170
    */
171
   while (fen[index] == ' ')
172
   {
173
      index++;
174
   }
175
 
176
   position->castlingRights = NO_CASTLINGS;
177
 
178
   while (fen[index] != ' ')
179
   {
180
      switch (fen[index++])
181
      {
182
      case 'K':
183
         position->castlingRights += WHITE_00;
184
         break;
185
      case 'Q':
186
         position->castlingRights += WHITE_000;
187
         break;
188
      case 'k':
189
         position->castlingRights += BLACK_00;
190
         break;
191
      case 'q':
192
         position->castlingRights += BLACK_000;
193
         break;
194
      case '-':
195
         position->castlingRights = NO_CASTLINGS;
196
         break;
197
      default:
198
         return -1;             /* fen format error */
199
      }
200
   }
201
 
202
   /*
203
    * Get the en passant square.
204
    */
205
   while (fen[index] == ' ')
206
   {
207
      index++;
208
   }
209
 
210
   if (fen[index] == '-')
211
   {
212
      position->enPassantSquare = NO_SQUARE;
213
      index++;
214
   }
215
   else if (fen[index] >= 'a' && fen[index] <= 'h' &&
216
            (fen[index + 1] == '3' || fen[index + 1] == '6'))
217
   {
218
      File file = (File) (fen[index++] - 'a');
219
      Rank rank = (Rank) (fen[index++] - '1');
220
 
221
      position->enPassantSquare = getSquare(file, rank);
222
   }
223
   else
224
   {
225
      return -1;                /* fen format error */
226
   }
227
 
228
   /*
229
    * Get the half move clock value.
230
    */
231
   while (fen[index] == ' ')
232
   {
233
      index++;
234
   }
235
 
236
   position->halfMoveClock = atoi(fen + index);
237
 
238
   /*
239
    * Get the move number value.
240
    */
241
   while (fen[index] != ' ')
242
   {
243
      if (!isdigit((int) fen[index]))
244
      {
245
         return -1;             /* fen format error */
246
      }
247
 
248
      index++;
249
   }
250
 
251
   while (fen[index] == ' ')
252
   {
253
      index++;
254
   }
255
 
256
   position->moveNumber = atoi(fen + index);
257
 
258
   return 0;
259
}
260
 
261
void getFen(const Position * position, char *fen)
262
{
263
   int rank, file;
264
   char buffer[16];
265
 
266
   /*
267
    * Initialize this module.
268
    */
269
   initialize();
270
 
271
   for (rank = RANK_8; rank >= RANK_1; rank--)
272
   {
273
      int emptyCount = 0;
274
 
275
      for (file = FILE_A; file <= FILE_H; file++)
276
      {
277
         Square square = getSquare(file, rank);
278
 
279
         if (position->piece[square] != NO_PIECE)
280
         {
281
            if (emptyCount > 0)
282
            {
283
               *fen++ = ((char) ('0' + emptyCount));
284
               emptyCount = 0;
285
            }
286
 
287
            *fen++ = pieceToken[position->piece[square]];
288
         }
289
         else
290
         {
291
            emptyCount++;
292
         }
293
      }
294
 
295
      if (emptyCount > 0)
296
      {
297
         *fen++ = ((char) ('0' + emptyCount));
298
      }
299
 
300
      if (rank > RANK_1)
301
      {
302
         *fen++ = '/';
303
      }
304
   }
305
 
306
   *fen++ = ' ';
307
   *fen++ = (position->activeColor == WHITE ? 'w' : 'b');
308
   *fen++ = ' ';
309
 
310
   if (position->castlingRights)
311
   {
312
      if (position->castlingRights & WHITE_00)
313
      {
314
         *fen++ = 'K';
315
      }
316
 
317
      if (position->castlingRights & WHITE_000)
318
      {
319
         *fen++ = 'Q';
320
      }
321
 
322
      if (position->castlingRights & BLACK_00)
323
      {
324
         *fen++ = 'k';
325
      }
326
 
327
      if (position->castlingRights & BLACK_000)
328
      {
329
         *fen++ = 'q';
330
      }
331
   }
332
   else
333
   {
334
      *fen++ = '-';
335
   }
336
 
337
   *fen++ = ' ';
338
 
339
   if (position->enPassantSquare != NO_SQUARE)
340
   {
341
      char file = (char) (file(position->enPassantSquare) + 'a');
342
      char rank = (char) (rank(position->enPassantSquare) + '1');
343
 
344
      *fen++ = file;
345
      *fen++ = rank;
346
   }
347
   else
348
   {
349
      *fen++ = '-';
350
   }
351
 
352
   *fen = '\0';
353
   sprintf(buffer, " %i %i", position->halfMoveClock, position->moveNumber);
354
   strcat(fen, buffer);
355
}
356
 
357
int initializeModuleFen()
358
{
359
   return 0;
360
}
361
 
362
int testModuleFen()
363
{
364
   char *fen1 = FEN_GAMESTART;
365
   char *fen2 =
366
      "rn3rk1/pbppq1pp/1p2pb2/4N2Q/3PN3/3B4/PPP2PPP/R3K2R w KQ - 4 11";
367
   char *fen3 = "8/8/1R5p/q5pk/PR3pP1/7P/8/7K b - g3 0 1";
368
   char buffer[256];
369
   Position position;
370
   Square square;
371
 
372
   readFen(fen1, &position);
373
   getFen(&position, buffer);
374
   assert(strcmp(buffer, fen1) == 0);
375
 
376
   assert(position.activeColor == WHITE);
377
   assert(position.enPassantSquare == NO_SQUARE);
378
   assert(position.halfMoveClock == 0);
379
   assert(position.moveNumber == 1);
380
   assert(position.castlingRights ==
381
          (WHITE_00 | WHITE_000 | BLACK_00 | BLACK_000));
382
   assert(position.piece[A1] == WHITE_ROOK);
383
   assert(position.piece[H1] == WHITE_ROOK);
384
   assert(position.piece[B1] == WHITE_KNIGHT);
385
   assert(position.piece[G1] == WHITE_KNIGHT);
386
   assert(position.piece[C1] == WHITE_BISHOP);
387
   assert(position.piece[F1] == WHITE_BISHOP);
388
   assert(position.piece[D1] == WHITE_QUEEN);
389
   assert(position.piece[E1] == WHITE_KING);
390
 
391
   assert(position.piece[A8] == BLACK_ROOK);
392
   assert(position.piece[H8] == BLACK_ROOK);
393
   assert(position.piece[B8] == BLACK_KNIGHT);
394
   assert(position.piece[G8] == BLACK_KNIGHT);
395
   assert(position.piece[C8] == BLACK_BISHOP);
396
   assert(position.piece[F8] == BLACK_BISHOP);
397
   assert(position.piece[D8] == BLACK_QUEEN);
398
   assert(position.piece[E8] == BLACK_KING);
399
 
400
   for (square = A2; square <= H2; square++)
401
   {
402
      assert(position.piece[square] == WHITE_PAWN);
403
      assert(position.piece[square + 8] == NO_PIECE);
404
      assert(position.piece[square + 16] == NO_PIECE);
405
      assert(position.piece[square + 24] == NO_PIECE);
406
      assert(position.piece[square + 32] == NO_PIECE);
407
      assert(position.piece[square + 40] == BLACK_PAWN);
408
   }
409
 
410
   readFen(fen2, &position);
411
   getFen(&position, buffer);
412
   assert(strcmp(buffer, fen2) == 0);
413
 
414
   readFen(fen3, &position);
415
   getFen(&position, buffer);
416
   assert(strcmp(buffer, fen3) == 0);
417
 
418
   return 0;
419
}