diff options
Diffstat (limited to 'src/engine/fen.c')
| -rw-r--r-- | src/engine/fen.c | 159 |
1 files changed, 159 insertions, 0 deletions
diff --git a/src/engine/fen.c b/src/engine/fen.c new file mode 100644 index 0000000..187271e --- /dev/null +++ b/src/engine/fen.c @@ -0,0 +1,159 @@ +#include "fen.h" +#include "bitboard.h" +#include <assert.h> +#include <stdio.h> + +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 <stdbool.h> + +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 |
