diff options
| author | Aargh Rai <aargh.rai+git@gmail.com> | 2026-05-31 13:07:46 +0530 |
|---|---|---|
| committer | Aargh Rai <aargh.rai+git@gmail.com> | 2026-05-31 13:07:46 +0530 |
| commit | 8671756d141292d4ec9747ec8de6e9cf3324777d (patch) | |
| tree | f14edf785f82cb6c6f3dc61c5ad1eb2689faef1f /src/engine | |
| parent | 198bf7c46552059581fda144ec08a9114258123e (diff) | |
CC in build.c & fen strings
Diffstat (limited to 'src/engine')
| -rw-r--r-- | src/engine/bitboard.c | 14 | ||||
| -rw-r--r-- | src/engine/bitboard.h | 10 | ||||
| -rw-r--r-- | src/engine/fen.c | 159 | ||||
| -rw-r--r-- | src/engine/fen.h | 3 | ||||
| -rw-r--r-- | src/engine/moves/king.c | 16 |
5 files changed, 173 insertions, 29 deletions
diff --git a/src/engine/bitboard.c b/src/engine/bitboard.c index 4746020..2d123ea 100644 --- a/src/engine/bitboard.c +++ b/src/engine/bitboard.c @@ -20,10 +20,8 @@ position_t position_starting() { 71776119061217280ULL, }, .castling = - ((bitboard_t)1 << WHITE_SHORT_CASTLE) | - ((bitboard_t)1 << WHITE_LONG_CASTLE) | - ((bitboard_t)1 << BLACK_SHORT_CASTLE) | - ((bitboard_t)1 << BLACK_LONG_CASTLE), + WHITE_SHORT_CASTLE | WHITE_LONG_CASTLE | + BLACK_SHORT_CASTLE | BLACK_LONG_CASTLE, .turn = WHITE_TURN, .passantable_file = 0, }; @@ -32,14 +30,12 @@ position_t position_starting() { void assert_valid_position(position_t position) { assert(position.castling <= ( - ((bitboard_t)1 << WHITE_SHORT_CASTLE) | - ((bitboard_t)1 << WHITE_LONG_CASTLE) | - ((bitboard_t)1 << BLACK_SHORT_CASTLE) | - ((bitboard_t)1 << BLACK_LONG_CASTLE) + WHITE_SHORT_CASTLE | WHITE_LONG_CASTLE | + BLACK_SHORT_CASTLE | BLACK_LONG_CASTLE ) ); assert(position.turn == WHITE_TURN || position.turn == BLACK_TURN); - assert(position.passantable_file <= 8); + assert(position.passantable_file <= 8); // 0 means no passant assert(position.bitboards[WHITE_KING] != 0); assert(position.bitboards[BLACK_KING] != 0); } diff --git a/src/engine/bitboard.h b/src/engine/bitboard.h index 912cad0..b137101 100644 --- a/src/engine/bitboard.h +++ b/src/engine/bitboard.h @@ -22,10 +22,10 @@ enum { }; enum { - WHITE_SHORT_CASTLE, - WHITE_LONG_CASTLE, - BLACK_SHORT_CASTLE, - BLACK_LONG_CASTLE, + WHITE_SHORT_CASTLE = 1 << 0, + WHITE_LONG_CASTLE = 1 << 1, + BLACK_SHORT_CASTLE = 1 << 2, + BLACK_LONG_CASTLE = 1 << 3, }; enum { @@ -57,6 +57,8 @@ typedef struct { u8 castling; u8 turn; u8 passantable_file; + u16 halfmove_clock; + u16 fullmove_clock; } position_t; position_t position_starting(); 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 diff --git a/src/engine/fen.h b/src/engine/fen.h new file mode 100644 index 0000000..c1444c1 --- /dev/null +++ b/src/engine/fen.h @@ -0,0 +1,3 @@ +#include "bitboard.h" + +position_t load_fen(const char* fen); diff --git a/src/engine/moves/king.c b/src/engine/moves/king.c index b2fea9e..9ce3eb8 100644 --- a/src/engine/moves/king.c +++ b/src/engine/moves/king.c @@ -34,19 +34,3 @@ void get_king_moves(moves_t* moves, position_t position) { add_move(moves, king_square, to); } } - -#ifdef TEST_MOD -#include <stdbool.h> -#include "../bitboard.c" -#include "./vec.c" - -bool test_empty_board() { - int i = 0; - while (i++ < 1000000000); - return true; -} - -bool test_friendly_pieces() { - return false; -} -#endif |
