11 Commits

Author SHA1 Message Date
84c3af2bb1 fully support FEN strings now
Some checks failed
pre-release / Pre Release (push) Has been cancelled
tagged-release / Tagged Release (push) Has been cancelled
2025-02-02 23:05:42 +01:00
22acfc5027 fixed slight bug 2025-02-02 23:05:26 +01:00
1ff4b6b1f4 implemented the en passant target support for FEN
strings
2025-02-02 22:52:46 +01:00
2493892b05 added algebraic support for coordinates 2025-02-02 22:39:06 +01:00
bdd8011577 now support the castling sides of the FEN string 2025-02-02 22:05:33 +01:00
5549c77177 updated testing library 2025-02-02 22:04:41 +01:00
be016dcbcc fixed type mismatch 2025-02-02 22:04:31 +01:00
efd7bf6794 gave default values to the board fields because
they were causing undefinied behaviour
2025-02-02 22:04:04 +01:00
81b24d3082 extended FEN support to include who's turn it is 2025-02-02 21:39:33 +01:00
497da2de8e updated assert equals to fail fast 2025-02-02 21:39:02 +01:00
0574a11b32 fixed minor bug 2025-02-02 21:37:43 +01:00
9 changed files with 193 additions and 24 deletions

View File

@ -1,6 +1,7 @@
#include "board.hpp" #include "board.hpp"
#include "coords.hpp" #include "coords.hpp"
#include "move.hpp"
#include "pieces/piece.hpp" #include "pieces/piece.hpp"
#include <algorithm> #include <algorithm>
@ -19,6 +20,7 @@ Board Board::setup_fen_position(std::string fen) {
{'q', Piece::Queen}, {'q', Piece::Queen},
}; };
// -- Pieces
std::string fen_board = fen.substr(0, fen.find(' ')); std::string fen_board = fen.substr(0, fen.find(' '));
int rank = 7, file = 0; int rank = 7, file = 0;
for (char symbol : fen_board) { for (char symbol : fen_board) {
@ -39,6 +41,57 @@ Board Board::setup_fen_position(std::string fen) {
file++; file++;
} }
} }
// -- Active colour
int index = fen.find(' ');
index++;
board.white_to_play = fen[index] == 'w';
// Castling Rights
index += 2;
for (char symbol : fen.substr(index, fen.find(' ', index + 1))) {
index++;
if (symbol == ' ' || symbol == '-') {
if (symbol == '-')
index++;
break;
}
switch (symbol) {
case 'K':
board.w_castle_rights |= CastleSide::KingSide;
break;
case 'Q':
board.w_castle_rights |= CastleSide::QueenSide;
break;
case 'k':
board.b_castle_rights |= CastleSide::KingSide;
break;
case 'q':
board.b_castle_rights |= CastleSide::QueenSide;
break;
}
}
// -- En passant target
if (fen[index] != '-') {
Coords c = Coords::from_algebraic(fen.substr(index, 2));
index += 2;
board.en_passant_target = c.to_index();
} else {
index++;
}
// -- Half move clock
index = fen.find(' ', index) + 1;
board.n_half_moves =
std::stoi(fen.substr(index, fen.find(' ', index + 1) - index));
// -- Full move number
index = fen.find(' ', index) + 1;
board.n_full_moves = std::stoi(fen.substr(index));
return board; return board;
} }
@ -53,15 +106,16 @@ std::string Board::to_fen() const {
}; };
std::string ret; std::string ret;
// -- Pieces
for (int rank = 7; rank >= 0; rank--) { for (int rank = 7; rank >= 0; rank--) {
int empty_cell_counter = 0; int empty_cell_counter = 0;
for (int file = 0; file < 8; file++) { for (int file = 0; file < 8; file++) {
if (this->squares[rank * 8 + file] == Piece::None) { if (squares[rank * 8 + file] == Piece::None) {
empty_cell_counter++; empty_cell_counter++;
continue; continue;
} }
int full_piece = this->squares[rank * 8 + file]; int full_piece = squares[rank * 8 + file];
char piece = p2c[full_piece & 0b111]; char piece = p2c[full_piece & 0b111];
int8_t colour = colour_at({file, rank}); int8_t colour = colour_at({file, rank});
@ -76,6 +130,41 @@ std::string Board::to_fen() const {
if (rank > 0) if (rank > 0)
ret += "/"; ret += "/";
} }
ret += " ";
// -- Active colour
ret += white_to_play ? 'w' : 'b';
ret += " ";
// -- Castling Rights
if (w_castle_rights == CastleSide::NeitherSide
&& b_castle_rights == CastleSide::NeitherSide)
ret += '-';
else {
if (w_castle_rights & CastleSide::KingSide)
ret += 'K';
if (w_castle_rights & CastleSide::QueenSide)
ret += 'Q';
if (b_castle_rights & CastleSide::KingSide)
ret += 'k';
if (b_castle_rights & CastleSide::QueenSide)
ret += 'q';
}
ret += ' ';
// -- En passant target
ret += en_passant_target == -1
? "-"
: Coords::from_index(en_passant_target).to_algebraic();
ret += ' ';
// -- Half move clock
ret += std::to_string(n_half_moves);
ret += ' ';
// -- Full moves number
ret += std::to_string(n_full_moves);
return ret; return ret;
} }

View File

@ -12,9 +12,12 @@ struct Board {
public: public:
int8_t squares[64] = {Piece::None}; int8_t squares[64] = {Piece::None};
bool white_to_play; bool white_to_play = true;
CastleSide w_castle_rights; int8_t w_castle_rights = CastleSide::NeitherSide;
CastleSide b_castle_rights; int8_t b_castle_rights = CastleSide::NeitherSide;
int8_t en_passant_target = -1;
uint8_t n_half_moves = 0;
uint8_t n_full_moves = 0;
static Board setup_fen_position(std::string fen); static Board setup_fen_position(std::string fen);

View File

@ -1,10 +1,18 @@
#pragma once #pragma once
#include <cstdint> #include <cstdint>
#include <iostream>
#include <stdexcept>
#include <string>
static std::string _FILES = "abcdefgh";
static std::string _RANKS = "12345678";
struct Coords { struct Coords {
int x, y; int x, y;
Coords(int x, int y): x(x), y(y) {}
int8_t to_index() const { int8_t to_index() const {
return this->y * 8 + this->x; return this->y * 8 + this->x;
} }
@ -13,7 +21,50 @@ struct Coords {
return {idx % 8, idx / 8}; return {idx % 8, idx / 8};
} }
static Coords from_algebraic(std::string pos) {
if (pos.size() != 2)
throw std::invalid_argument(
"An algebraic coordinate should only have two characters"
);
int x = _FILES.find(pos[0]);
if (x == std::string::npos)
throw std::invalid_argument("The first character of the given "
"algebraic coordinate is invalid");
int y = _RANKS.find(pos[1]);
if (y == std::string::npos)
throw std::invalid_argument("The second character of the given "
"algebraic coordinate is invalid");
return Coords{x, y};
}
std::string to_algebraic() const {
std::string ret;
if (x > 7 || y > 7)
throw std::invalid_argument(
"Can't give the algebraic vesion of an invalid coord"
);
ret += _FILES[x];
ret += _RANKS[y];
return ret;
}
bool is_within_bounds() const { bool is_within_bounds() const {
return this->to_index() < 64; return this->to_index() < 64;
} }
}; };
inline bool operator==(const Coords& a, const Coords& b) {
return a.x == b.x && a.y == b.y;
}
inline bool operator!=(const Coords& a, const Coords& b) {
return !(a == b);
}
inline std::ostream& operator<<(std::ostream& os, const Coords& coords) {
os << coords.to_algebraic();
return os;
}

View File

@ -6,5 +6,6 @@ int main(int argc, char* argv[]) {
std::string pos = std::string pos =
"rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"; "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
Board b = Board::setup_fen_position(pos); Board b = Board::setup_fen_position(pos);
sizeof(b);
return 0; return 0;
} }

View File

@ -49,7 +49,7 @@ std::vector<Move> king_moves(const Board& b, const Coords xy) {
return ret; return ret;
// -- Castles // -- Castles
CastleSide castling_rights = b.colour_at(xy) == Colour::White int8_t castling_rights = b.colour_at(xy) == Colour::White
? b.w_castle_rights ? b.w_castle_rights
: b.b_castle_rights; : b.b_castle_rights;

View File

@ -5,7 +5,7 @@
#include <vector> #include <vector>
std::vector<Move> rook_moves(const Board& b, const Coords xy) { std::vector<Move> queen_moves(const Board& b, const Coords xy) {
std::vector<Move> ret; std::vector<Move> ret;
auto e = look_direction(b, xy, 1, 0); auto e = look_direction(b, xy, 1, 0);
ret.insert(ret.end(), e.begin(), e.end()); ret.insert(ret.end(), e.begin(), e.end());

View File

@ -2,21 +2,22 @@
#include "lib.hpp" #include "lib.hpp"
int main() { int main() {
std::string pos = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR"; std::string pos =
ASSERT_EQUALS(pos, Board::setup_fen_position(pos)->to_fen()); "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
ASSERT_EQUALS(pos, Board::setup_fen_position(pos).to_fen());
pos = "r1bk3r/p2pBpNp/n4n2/1p1NP2P/6P1/3P4/P1P1K3/q5b1"; pos = "r1bk3r/p2pBpNp/n4n2/1p1NP2P/6P1/3P4/P1P1K3/q5b1 b Qk - 0 1";
ASSERT_EQUALS(pos, Board::setup_fen_position(pos)->to_fen()); ASSERT_EQUALS(pos, Board::setup_fen_position(pos).to_fen());
pos = "rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR"; pos = "rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1";
ASSERT_EQUALS(pos, Board::setup_fen_position(pos)->to_fen()); ASSERT_EQUALS(pos, Board::setup_fen_position(pos).to_fen());
pos = "4k2r/6r1/8/8/8/8/3R4/R3K3"; pos = "4k2r/6r1/8/8/8/8/3R4/R3K3 w Qk - 0 1";
ASSERT_EQUALS(pos, Board::setup_fen_position(pos)->to_fen()); ASSERT_EQUALS(pos, Board::setup_fen_position(pos).to_fen());
pos = "8/8/8/4p1K1/2k1P3/8/8/8"; pos = "8/8/8/4p1K1/2k1P3/8/8/8 b - - 0 1";
ASSERT_EQUALS(pos, Board::setup_fen_position(pos)->to_fen()); ASSERT_EQUALS(pos, Board::setup_fen_position(pos).to_fen());
pos = "8/5k2/3p4/1p1Pp2p/pP2Pp1P/P4P1K/8/8"; pos = "8/5k2/3p4/1p1Pp2p/pP2Pp1P/P4P1K/8/8 b - - 99 50";
ASSERT_EQUALS(pos, Board::setup_fen_position(pos)->to_fen()); ASSERT_EQUALS(pos, Board::setup_fen_position(pos).to_fen());
} }

View File

@ -2,11 +2,15 @@
#include <iostream> #include <iostream>
#define ASSERT_EQUALS(expected, actual) \ #define ASSERT_EQUALS(x, y) \
{ \ { \
if (expected != actual) \ auto expected = x; \
std::cout << "Expected: " << std::endl \ auto actual = y; \
if (expected != actual) { \
std::cerr << "Expected: " << std::endl \
<< '\t' << expected << std::endl \ << '\t' << expected << std::endl \
<< "Got: " << std::endl \ << "Got: " << std::endl \
<< '\t' << actual << std::endl; \ << '\t' << actual << std::endl; \
exit(1); \
} \
} }

20
cpp/tests/positions.cpp Normal file
View File

@ -0,0 +1,20 @@
#include "../src/coords.hpp"
#include "lib.hpp"
int main() {
ASSERT_EQUALS(Coords(0, 0).to_algebraic(), "a1");
ASSERT_EQUALS(Coords(1, 0).to_algebraic(), "b1");
ASSERT_EQUALS(Coords(2, 1).to_algebraic(), "c2");
ASSERT_EQUALS(Coords(4, 2).to_algebraic(), "e3");
ASSERT_EQUALS(Coords(7, 7).to_algebraic(), "h8");
ASSERT_EQUALS(Coords::from_algebraic("a1"), Coords(0, 0));
ASSERT_EQUALS(Coords::from_algebraic("b1"), Coords(1, 0));
ASSERT_EQUALS(Coords::from_algebraic("c2"), Coords(2, 1));
ASSERT_EQUALS(Coords::from_algebraic("e3"), Coords(4, 2));
ASSERT_EQUALS(Coords::from_algebraic("h8"), Coords(7, 7));
}