Subversion Repositories Games.Chess Giants

Rev

Blame | Last modification | View Log | Download | RSS feed

  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. }
  420.