mirror of
https://gitlab.com/manzerbredes/chessarbiter.git
synced 2025-04-07 02:26:26 +02:00
206 lines
No EOL
4.1 KiB
C++
206 lines
No EOL
4.1 KiB
C++
#include "Fen.hpp"
|
|
|
|
namespace chessarbiter {
|
|
|
|
std::string FENParser::normalize_rank(std::string fen_rank) {
|
|
std::string normalized;
|
|
for (char &c : fen_rank) {
|
|
if (IS_DIGIT(c)) {
|
|
for (char i = 0; i < (c - '0'); i++) {
|
|
normalized += ' ';
|
|
}
|
|
} else {
|
|
// Check validity
|
|
char c2 = std::tolower(c);
|
|
if (!(c2 == 'p' || c2 == 'r' || c2 == 'n' || c2 == 'b' || c2 == 'q' ||
|
|
c2 == 'k' || c2 == ' ')) {
|
|
throw InvalidFEN();
|
|
}
|
|
// Add
|
|
normalized += c;
|
|
}
|
|
}
|
|
// Check validity
|
|
if (normalized.size() != 8) {
|
|
throw InvalidFEN();
|
|
}
|
|
return (normalized);
|
|
}
|
|
|
|
char FENParser::NextToken(std::string fen, char loc) {
|
|
while (loc < fen.size() && IS_BLANK(fen[loc])) {
|
|
loc++;
|
|
}
|
|
return (loc);
|
|
}
|
|
|
|
char FENParser::NextRank(std::string fen, char loc) {
|
|
loc++;
|
|
while (loc < fen.size() && fen[loc] != '/' && fen[loc] != ' ') {
|
|
loc++;
|
|
}
|
|
return (loc);
|
|
}
|
|
|
|
std::string FENParser::Serialize(FEN fen) {
|
|
std::string s;
|
|
char skip = 0;
|
|
char rank = 0;
|
|
for (char &c : fen.board) {
|
|
rank++;
|
|
if (c == ' ') {
|
|
skip++;
|
|
} else {
|
|
if (skip > 0) {
|
|
s += std::to_string(skip);
|
|
skip = 0;
|
|
}
|
|
s += c;
|
|
}
|
|
if (rank == 8) {
|
|
if (skip != 0) {
|
|
s += std::to_string(skip);
|
|
skip = 0;
|
|
}
|
|
s += '/';
|
|
rank = 0;
|
|
}
|
|
}
|
|
|
|
// Remove last /
|
|
s = s.substr(0, s.size() - 1);
|
|
s += " ";
|
|
|
|
// Player
|
|
if (fen.player) {
|
|
s += "b ";
|
|
} else {
|
|
s += "w ";
|
|
}
|
|
|
|
// Castle
|
|
if (!(fen.white_castle_short || fen.white_castle_long ||
|
|
fen.black_castle_short || fen.black_castle_long)) {
|
|
s += "-";
|
|
} else {
|
|
if (fen.white_castle_short) {
|
|
s += "K";
|
|
}
|
|
if (fen.white_castle_long) {
|
|
s += "Q";
|
|
}
|
|
if (fen.black_castle_short) {
|
|
s += "k";
|
|
}
|
|
if (fen.black_castle_long) {
|
|
s += "q";
|
|
}
|
|
}
|
|
|
|
// Remaining
|
|
s += " " + fen.en_passant + " " + std::to_string(fen.halfmove) + " " +
|
|
std::to_string(fen.move);
|
|
|
|
return (s);
|
|
}
|
|
|
|
FEN FENParser::Parse(std::string fen) {
|
|
FEN parsed;
|
|
|
|
// Parse board
|
|
char loc = 0;
|
|
for (char rank = 0; rank < 8; rank++) {
|
|
CHECK_LOC();
|
|
char newloc = NextRank(fen, loc);
|
|
parsed.board += normalize_rank(fen.substr(loc, newloc - loc));
|
|
loc = newloc + 1;
|
|
}
|
|
|
|
// Parse player to move
|
|
loc = NextToken(fen, loc);
|
|
if (!(fen[loc] == 'w' || fen[loc] == 'b')) {
|
|
throw InvalidFEN();
|
|
}
|
|
parsed.player = fen[loc] == 'b';
|
|
CHECK_LOC();
|
|
|
|
// Parse castling
|
|
loc = NextToken(fen, loc + 1);
|
|
char length = 0;
|
|
char cur_loc = loc;
|
|
while (!IS_BLANK(fen[cur_loc])) {
|
|
length++;
|
|
cur_loc++;
|
|
CHECK_LOC();
|
|
}
|
|
parsed.white_castle_short = false;
|
|
parsed.white_castle_long = false;
|
|
parsed.black_castle_short = false;
|
|
parsed.black_castle_long = false;
|
|
std::string castle = fen.substr(loc, length);
|
|
for (char i = 0; i < length; i++) {
|
|
switch (fen[loc + i]) {
|
|
case 'K':
|
|
parsed.white_castle_short = true;
|
|
break;
|
|
case 'Q':
|
|
parsed.white_castle_long = true;
|
|
break;
|
|
case 'k':
|
|
parsed.black_castle_short = true;
|
|
break;
|
|
case 'q':
|
|
parsed.black_castle_long = true;
|
|
break;
|
|
case '-':
|
|
break;
|
|
default:
|
|
throw InvalidFEN();
|
|
}
|
|
}
|
|
|
|
// Parse en passant
|
|
loc = NextToken(fen, loc + length);
|
|
if (fen[loc] != '-') {
|
|
parsed.en_passant = fen.substr(loc, 2);
|
|
loc++;
|
|
// Check format
|
|
char f = parsed.en_passant[0];
|
|
char r = parsed.en_passant[1];
|
|
if (!((f >= 'a' && f <= 'h') && (r >= '1' && r <= '8'))) {
|
|
throw InvalidFEN();
|
|
}
|
|
}
|
|
loc++;
|
|
CHECK_LOC();
|
|
|
|
// Parse half move counter
|
|
loc = NextToken(fen, loc);
|
|
std::string halfmove;
|
|
while (!IS_BLANK(fen[loc])) {
|
|
if (!IS_DIGIT(fen[loc])) {
|
|
throw InvalidFEN();
|
|
}
|
|
halfmove += fen[loc];
|
|
loc++;
|
|
CHECK_LOC();
|
|
}
|
|
parsed.halfmove = stoi(halfmove);
|
|
|
|
// Parse move counter
|
|
loc = NextToken(fen, loc);
|
|
std::string move;
|
|
while (loc < fen.size() && !IS_BLANK(fen[loc])) {
|
|
if (!IS_DIGIT(fen[loc])) {
|
|
throw InvalidFEN();
|
|
}
|
|
CHECK_LOC();
|
|
move += fen[loc];
|
|
loc++;
|
|
}
|
|
parsed.move = stoi(move);
|
|
|
|
return (parsed);
|
|
}
|
|
|
|
} // namespace chessarbiter
|