summaryrefslogtreecommitdiff
path: root/src/engine
diff options
context:
space:
mode:
Diffstat (limited to 'src/engine')
-rw-r--r--src/engine/bitboard.c14
-rw-r--r--src/engine/bitboard.h10
-rw-r--r--src/engine/fen.c159
-rw-r--r--src/engine/fen.h3
-rw-r--r--src/engine/moves/king.c16
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