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 | |
| parent | 198bf7c46552059581fda144ec08a9114258123e (diff) | |
CC in build.c & fen strings
| -rw-r--r-- | build.c | 20 | ||||
| -rw-r--r-- | generated/tests.c | 12 | ||||
| -rw-r--r-- | src/engine.c | 1 | ||||
| -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 |
8 files changed, 190 insertions, 45 deletions
@@ -6,6 +6,8 @@ #include <time.h> #include <string.h> +#define CC "gcc", "-O3" + int status; #define RUN_CMD(...) do { \ @@ -58,9 +60,9 @@ int needs_rebuild(char* bin_file, char* source_file) { int main(int argc, char** argv) { if (needs_rebuild(argv[0], __FILE__)) { - RUN_CMD({"gcc", __FILE__, "-o", argv[0], NULL}); + RUN_CMD({CC, __FILE__, "-o", argv[0], NULL}); if (status != 0) { - // gcc error + // cc error return 0; } print_cmd(argv); @@ -75,11 +77,11 @@ int main(int argc, char** argv) { return test_mode(); } if (strcmp(argv[1], "server") == 0) { - RUN_CMD({"gcc", "src/log.c", "-o", LOG_O, NULL}); + RUN_CMD({CC, "src/log.c", "-o", LOG_O, NULL}); return server_mode(); } if (strcmp(argv[1], "clean") == 0) { - RUN_CMD({"gcc", "src/log.c", "-o", LOG_O, NULL}); + RUN_CMD({CC, "src/log.c", "-o", LOG_O, NULL}); return clean_mode(); } } @@ -94,10 +96,10 @@ int clean_mode() { } int test_mode() { - RUN_CMD({"gcc", "generate/find_tests.c", LOGGER_C, "-o", "output/find_tests.o", NULL}); + RUN_CMD({CC, "generate/find_tests.c", LOGGER_C, "-o", "output/find_tests.o", NULL}); RUN_CMD({"./output/find_tests.o", NULL}); printf("\n"); - RUN_CMD({"gcc", "tests/main.c", LOGGER_C, "-o", "output/test.o", NULL}); + RUN_CMD({CC, "tests/main.c", LOGGER_C, "-o", "output/test.o", NULL}); char* args[] = {"./output/test.o", NULL}; print_cmd(args); @@ -107,8 +109,8 @@ int test_mode() { int server_mode() { RUN_CMD({"rm", "/dev/mqueue/server_to_engine", "/dev/mqueue/engine_to_server", NULL}); - RUN_CMD({"gcc", "src/server.c", LOGGER_C, "-lcrypto", "-o", SERVER_O, NULL}); - RUN_CMD({"gcc", "src/engine.c", LOGGER_C, "-o", ENGINE_O, NULL}); + RUN_CMD({CC, "src/server.c", LOGGER_C, "-lcrypto", "-o", SERVER_O, NULL}); + RUN_CMD({CC, "src/engine.c", LOGGER_C, "-o", ENGINE_O, NULL}); char* args[] = {LOG_O, SERVER_O, ENGINE_O, NULL}; print_cmd(args); @@ -117,7 +119,7 @@ int server_mode() { } int engine_mode() { - RUN_CMD({"gcc", "src/engine.c", LOGGER_C, "-o", ENGINE_O, NULL}); + RUN_CMD({CC, "src/engine.c", LOGGER_C, "-o", ENGINE_O, NULL}); char* args[] = {LOG_O, ENGINE_O, NULL}; print_cmd(args); diff --git a/generated/tests.c b/generated/tests.c index 6136b22..7784b32 100644 --- a/generated/tests.c +++ b/generated/tests.c @@ -1,13 +1,13 @@ -#include "../src/engine/moves/king.c" +#include "../src/engine/fen.c" int total_test_count = 2; bool (*tests[2])(void) = { - test_empty_board, - test_friendly_pieces, + test_fen_no_passant, + test_fen_passant, }; -int max_test_name_size = 15; +int max_test_name_size = 14; char test_names[2][100] = { - "empty_board", - "friendly_pieces", + "fen_no_passant", + "fen_passant", }; diff --git a/src/engine.c b/src/engine.c index f34a83e..8d22d23 100644 --- a/src/engine.c +++ b/src/engine.c @@ -1,4 +1,3 @@ -#include <stdio.h> #include <assert.h> #include "engine/bitboard.h" #include "engine/moves.h" 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 |
