#include "fen.h" #include "bitboard.h" #include #include int get_castling(char c) { if (c == 'K') return WHITE_SHORT_CASTLE; if (c == 'Q') return WHITE_LONG_CASTLE; if (c == 'k') return BLACK_SHORT_CASTLE; if (c == 'q') return BLACK_LONG_CASTLE; assert(0); } int get_turn(char c) { if (c == 'w') return WHITE_TURN; if (c == 'b') return BLACK_TURN; assert(0); } int get_piece_enum_item(char c) { if (c == 'P') return WHITE_PAWN; if (c == 'N') return WHITE_KNIGHT; if (c == 'B') return WHITE_BISHOP; if (c == 'R') return WHITE_ROOK; if (c == 'Q') return WHITE_QUEEN; if (c == 'K') return WHITE_KING; if (c == 'p') return BLACK_PAWN; if (c == 'n') return BLACK_KNIGHT; if (c == 'b') return BLACK_BISHOP; if (c == 'r') return BLACK_ROOK; if (c == 'q') return BLACK_QUEEN; if (c == 'k') return BLACK_KING; assert(0); } /* * from Wikipedia * Piece placement data * Each rank is described, starting with rank 8 and ending with rank 1, * with a "/" between each one; within each rank, the contents of the * squares are described in order from the a-file to the h-file. * Each piece is identified by a single letter taken from the standard * English names in algebraic notation * (pawn = "P", knight = "N", bishop = "B", * rook = "R", queen = "Q", and king = "K"). * White pieces are designated using uppercase letters ("PNBRQK"), * while black pieces use lowercase letters ("pnbrqk"). * A set of one or more consecutive empty squares within a rank is denoted * by a digit from "1" to "8", corresponding to the number of squares. * Active color * "w" means that White is to move; "b" means that Black is to move. * Castling availability * If neither side has the ability to castle, this field uses the character * "-". Otherwise, this field contains one or more letters: * "K" if White can castle kingside, * "Q" if White can castle queenside, * "k" if Black can castle kingside, * and "q" if Black can castle queenside. * A situation that temporarily prevents castling does not * prevent the use of this notation. * En passant target square * This is a square over which a pawn has just passed while moving two * squares; it is given in algebraic notation. * If there is no en passant target square, this field uses the character "-". * This is recorded regardless of whether there is a pawn in position to * capture en passant. An updated version of the spec has since made it * so the target square is recorded only if a legal en passant capture is * possible, but the old version of the standard * is the one most commonly used. * Halfmove clock * The number of halfmoves since the last capture or pawn advance, * used for the fifty-move rule. * Fullmove number * The number of the full moves. * It starts at 1 and is incremented after Black's move. * * e.g. 1B6/2n5/p1N1P2R/P1K3N1/4Pk2/1Q2p2p/6nP/1B4R1 w - - 0 1 */ position_t load_fen(const char* fen) { position_t position = {0}; int square = 56; int i = -1; char c; while ((c = fen[++i]) != ' ') { if (c >= '0' && c <= '9') { assert(c != '9'); square += c - '0'; continue; } if (c == '/') { square -= 16; continue; } int piece_type = get_piece_enum_item(c); position.bitboards[piece_type] |= (bitboard_t)1 << square; } c = fen[++i]; position.turn = get_turn(c); assert(fen[++i] == ' '); while ((c = fen[++i]) != ' ') { if (c == '-') continue; position.castling |= get_castling(c); } c = fen[++i]; if (c >= 'a' && c <= 'z') { assert(c <= 'h'); position.passantable_file = c - 'a' + 1; c = fen[++i]; assert(c >= '1' && c <= '8'); } else { position.passantable_file = 0; } assert(fen[++i] == ' '); while ((c = fen[++i]) != ' ') { assert(c >= '0' && c <= '9'); position.halfmove_clock *= 10; position.halfmove_clock += c - '0'; } while ((c = fen[++i]) != 0) { assert(c >= '0' && c <= '9'); position.fullmove_clock *= 10; position.fullmove_clock += c - '0'; } assert_valid_position(position); return position; } #ifdef TEST_MOD #include "bitboard.c" #include bool test_fen_no_passant() { position_t p = load_fen("1B6/2n5/p1N1P2R/P1K3N1/4Pk2/1Q2p2p/6nP/1B4R1 w - - 0 1"); if (p.castling != 0) return false; if (p.passantable_file != 0) return false; return true; } bool test_fen_passant() { position_t p = load_fen("rnbqkbnr/ppp1p1pp/8/3pPp2/8/8/PPPP1PPP/RNBQKBNR w KQkq f6 0 3"); if ( p.castling != ( WHITE_LONG_CASTLE | WHITE_SHORT_CASTLE | BLACK_LONG_CASTLE | BLACK_SHORT_CASTLE ) ) return false; if (p.passantable_file != 6) return false; return true; } #endif