chessarbiter/tests/chessarbiter.cpp
2023-05-10 06:55:12 +02:00

536 lines
No EOL
19 KiB
C++

#include "ChessArbiter.hpp"
#include <catch_amalgamated.hpp>
using namespace chessarbiter;
TEST_CASE("Setup/GetBoard", "[chessarbiter/Setup/GetBoard]") {
ChessArbiter a;
a.Setup("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1");
CHECK(a.GetBoard() == "rnbqkbnr"
"pppppppp"
" "
" "
" "
" "
"PPPPPPPP"
"RNBQKBNR");
a.Setup("RnbqkbnR/pppppppp/8/8/8/8/PPPPPPPP/rNBQKBNr w KQkq - 0 1");
CHECK(a.GetBoard() == "RnbqkbnR"
"pppppppp"
" "
" "
" "
" "
"PPPPPPPP"
"rNBQKBNr");
}
TEST_CASE("GetMaterialScore", "[chessarbiter/GetMaterialScore]") {
ChessArbiter a;
a.Setup("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1");
CHECK(a.GetMaterialScore() == 0);
// White better
a.Setup("1nbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1");
CHECK(a.GetMaterialScore() == 5);
a.Setup("r1bqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1");
CHECK(a.GetMaterialScore() == 3);
a.Setup("rnbqkbnr/1ppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1");
CHECK(a.GetMaterialScore() == 1);
a.Setup("rnb1kbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1");
CHECK(a.GetMaterialScore() == 9);
a.Setup("rnbqk1nr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1");
CHECK(a.GetMaterialScore() == 3);
a.Setup("rnbq1bnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1");
CHECK(a.GetMaterialScore() == 0);
// Black better
a.Setup("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/1NBQKBNR w KQkq - 0 1");
CHECK(a.GetMaterialScore() == -5);
a.Setup("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKB1R w KQkq - 0 1");
CHECK(a.GetMaterialScore() == -3);
a.Setup("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPP1/RNBQKBNR w KQkq - 0 1");
CHECK(a.GetMaterialScore() == -1);
a.Setup("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNB1KBNR w KQkq - 0 1");
CHECK(a.GetMaterialScore() == -9);
a.Setup("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RN1QKBNR w KQkq - 0 1");
CHECK(a.GetMaterialScore() == -3);
a.Setup("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQ1BNR w KQkq - 0 1");
CHECK(a.GetMaterialScore() == 0);
}
TEST_CASE("GetCaptures", "[board/GetCaptures]") {
ChessArbiter a;
// White captures
a.Setup("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1");
CHECK(a.GetCaptures(false) == "");
a.Setup("rnbqkbnr/8/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1");
CHECK(a.GetCaptures(false) == "pppppppp");
a.Setup("1nbqkbn1/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1");
CHECK(a.GetCaptures(false) == "rr");
a.Setup("r1bqkb1r/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1");
CHECK(a.GetCaptures(false) == "nn");
a.Setup("rnbqk1nr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1");
CHECK(a.GetCaptures(false) == "b");
a.Setup("rnb1kbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1");
CHECK(a.GetCaptures(false) == "q");
a.Setup("rnbq1bnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1");
CHECK(a.GetCaptures(false) == "k"); // :D
// Black captures
a.Setup("rnbqkbnr/pppppppp/8/8/8/8/8/RNBQKBNR w KQkq - 0 1");
CHECK(a.GetCaptures(true) == "PPPPPPPP");
a.Setup("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/1NBQKBN1 w KQkq - 0 1");
CHECK(a.GetCaptures(true) == "RR");
a.Setup("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/R1BQKB1R w KQkq - 0 1");
CHECK(a.GetCaptures(true) == "NN");
a.Setup("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNbQKBNR w KQkq - 0 1");
CHECK(a.GetCaptures(true) == "B");
a.Setup("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNB1KBNR w KQkq - 0 1");
CHECK(a.GetCaptures(true) == "Q");
a.Setup("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQ1BNR w KQkq - 0 1");
CHECK(a.GetCaptures(true) == "K"); // :D
// Just because we know the order of the implementation
a.Setup("11bqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1");
CHECK(a.GetCaptures(false) == "rn");
a.Setup("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKB11 w KQkq - 0 1");
CHECK(a.GetCaptures(true) == "RN");
}
TEST_CASE("IsAttacked", "[chessarbiter/IsAttacked]") {
ChessArbiter a;
a.Setup("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1");
// White third rank attacked by white
CHECK(a.IsAttacked("a3", false));
CHECK(a.IsAttacked("b3", false));
CHECK(a.IsAttacked("c3", false));
CHECK(a.IsAttacked("d3", false));
CHECK(a.IsAttacked("e3", false));
CHECK(a.IsAttacked("f3", false));
CHECK(a.IsAttacked("g3", false));
CHECK(a.IsAttacked("h3", false));
// White third rank attacked by black
CHECK_FALSE(a.IsAttacked("a3", true));
CHECK_FALSE(a.IsAttacked("b3", true));
CHECK_FALSE(a.IsAttacked("c3", true));
CHECK_FALSE(a.IsAttacked("d3", true));
CHECK_FALSE(a.IsAttacked("e3", true));
CHECK_FALSE(a.IsAttacked("f3", true));
CHECK_FALSE(a.IsAttacked("g3", true));
CHECK_FALSE(a.IsAttacked("h3", true));
// Black sixth rank attacked by black
CHECK(a.IsAttacked("a6", true));
CHECK(a.IsAttacked("b6", true));
CHECK(a.IsAttacked("c6", true));
CHECK(a.IsAttacked("d6", true));
CHECK(a.IsAttacked("e6", true));
CHECK(a.IsAttacked("f6", true));
CHECK(a.IsAttacked("g6", true));
CHECK(a.IsAttacked("h6", true));
// Black sixth rank attacked by white
CHECK_FALSE(a.IsAttacked("a6", false));
CHECK_FALSE(a.IsAttacked("b6", false));
CHECK_FALSE(a.IsAttacked("c6", false));
CHECK_FALSE(a.IsAttacked("d6", false));
CHECK_FALSE(a.IsAttacked("e6", false));
CHECK_FALSE(a.IsAttacked("f6", false));
CHECK_FALSE(a.IsAttacked("g6", false));
CHECK_FALSE(a.IsAttacked("h6", false));
// Remove a pawn for black
a.Setup("rnbqkbnr/1ppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1");
CHECK(a.IsAttacked("a3", false));
CHECK(a.IsAttacked("a3", true));
CHECK_FALSE(a.IsAttacked("a4", false));
CHECK(a.IsAttacked("a4", true));
// Remove another pawn for black
a.Setup("rnbqkbnr/pppp1ppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1");
CHECK(a.IsAttacked("a3", true));
CHECK(a.IsAttacked("h4", true));
CHECK(a.IsAttacked("a3", false));
CHECK_FALSE(a.IsAttacked("h4", false));
// Add a crazy black knight
a.Setup("rnbqkbnr/pppppppp/8/8/8/4n3/PPPPPPPP/RNBQKBNR w KQkq - 0 1");
CHECK(a.IsAttacked("d1", true));
CHECK_FALSE(a.IsAttacked("e1", true));
CHECK(a.IsAttacked("f1", true));
CHECK_FALSE(a.IsAttacked("f2", true));
CHECK_FALSE(a.IsAttacked("d1", false)); // White can't attack is own pieces
}
TEST_CASE("ListLegalMoves", "[chessarbiter/ListLegalMoves]") {
ChessArbiter a;
a.Setup("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1");
std::vector<std::string> moves = a.ListLegalMoves(false);
REQUIRE(moves.size() == 20);
CHECK(std::find(moves.begin(), moves.end(), "e2e4") != moves.end());
CHECK(std::find(moves.begin(), moves.end(), "e2e3") != moves.end());
CHECK(std::find(moves.begin(), moves.end(), "b1c3") != moves.end());
CHECK_FALSE(std::find(moves.begin(), moves.end(), "d1d3") != moves.end());
// White Short Castle possible
a.Setup("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQK11R w KQkq - 0 1");
moves = a.ListLegalMoves(false);
REQUIRE(moves.size() == 22);
CHECK(std::find(moves.begin(), moves.end(), "e1g1") != moves.end());
// White Short Castle impossible
a.Setup("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQK11R w Qkq - 0 1");
moves = a.ListLegalMoves(false);
CHECK_FALSE(std::find(moves.begin(), moves.end(), "e1g1") != moves.end());
// White Short Castle impossible 2
a.Setup("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQK1NR w KQkq - 0 1");
moves = a.ListLegalMoves(false);
CHECK_FALSE(std::find(moves.begin(), moves.end(), "e1g1") != moves.end());
// White Short Castle impossible 3 (queen attacks by black)
a.Setup("rnbqkbnr/pppppqpp/8/8/8/8/PPPPP1PP/RNBQK11R w KQkq - 0 1");
moves = a.ListLegalMoves(false);
CHECK_FALSE(std::find(moves.begin(), moves.end(), "e1g1") != moves.end());
// White Long Castle possible
a.Setup("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/R3KNBR w KQkq - 0 1");
moves = a.ListLegalMoves(false);
REQUIRE(moves.size() == 23);
CHECK(find(moves.begin(), moves.end(), "e1c1") != moves.end());
// White Long Castle impossible
a.Setup("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/R3KBNR w Kkq - 0 1");
moves = a.ListLegalMoves(false);
CHECK_FALSE(std::find(moves.begin(), moves.end(), "e1c1") != moves.end());
// White Long Castle impossible 2
a.Setup("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RN2KBNR w KQkq - 0 1");
moves = a.ListLegalMoves(false);
CHECK_FALSE(std::find(moves.begin(), moves.end(), "e1c1") != moves.end());
// White Long Castle impossible 3 (rook attacks by black)
a.Setup("rnbqkbnr/pprppppp/8/8/8/8/PP1PPPPP/R3KBNR w KQkq - 0 1");
moves = a.ListLegalMoves(false);
CHECK_FALSE(std::find(moves.begin(), moves.end(), "e1c1") != moves.end());
}
TEST_CASE("IsPlayable", "[chessarbiter/IsPlayable]") {
ChessArbiter a;
a.Setup("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1");
CHECK(a.IsPlayable());
a.Setup("8/8/1q1k4/8/8/8/5K2/8 w - - 0 1");
CHECK(a.IsPlayable());
a.Setup("8/8/3k4/3q4/8/8/3K4/8 b - - 0 1");
CHECK_FALSE(a.IsPlayable());
a.Setup("8/8/3k4/3q4/8/8/3R4/8 b - - 0 1");
CHECK_FALSE(a.IsPlayable());
a.Setup("8/8/3k4/3q4/8/8/5K2/4K3 b - - 0 1");
CHECK_FALSE(a.IsPlayable());
a.Setup("1k6/8/3k4/3q4/8/8/5K2/8 b - - 0 1");
CHECK_FALSE(a.IsPlayable());
}
TEST_CASE("Play Basic", "[chessarbiter/Play]") {
ChessArbiter a;
a.Setup("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1");
// White turn
CHECK(a.Play("e2e3"));
CHECK(a.GetFEN() ==
"rnbqkbnr/pppppppp/8/8/8/4P3/PPPP1PPP/RNBQKBNR b KQkq - 0 1");
CHECK_FALSE(a.Play("d2d3")); // Black turn
CHECK(a.GetFEN() ==
"rnbqkbnr/pppppppp/8/8/8/4P3/PPPP1PPP/RNBQKBNR b KQkq - 0 1");
// Black turn
CHECK(a.Play("e7e5"));
CHECK(a.GetFEN() ==
"rnbqkbnr/pppp1ppp/8/4p3/8/4P3/PPPP1PPP/RNBQKBNR w KQkq e6 0 2");
CHECK_FALSE(a.Play("d7d6")); // White turn
CHECK(a.GetFEN() ==
"rnbqkbnr/pppp1ppp/8/4p3/8/4P3/PPPP1PPP/RNBQKBNR w KQkq e6 0 2");
// White turn
CHECK(a.Play("b1c3"));
CHECK(a.GetFEN() ==
"rnbqkbnr/pppp1ppp/8/4p3/8/2N1P3/PPPP1PPP/R1BQKBNR b KQkq - 1 2");
}
TEST_CASE("IsCheckmate", "[chessarbiter/IsCheckmate]") {
ChessArbiter a;
// There is no checkmate
a.Setup("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1");
CHECK_FALSE(a.IsCheckMate());
// Ensure fen did not change
CHECK(a.GetFEN() ==
"rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1");
// There is a checkmate
a.Setup("r1bqkbnr/1ppp1Qpp/p1n5/4p3/2B1P3/8/PPPP1PPP/RNB1K1NR b KQkq - 0 4");
CHECK(a.IsCheckMate());
CHECK(a.GetFEN() ==
"r1bqkbnr/1ppp1Qpp/p1n5/4p3/2B1P3/8/PPPP1PPP/RNB1K1NR b KQkq - 0 4");
// There is a checkmate
a.Setup("1nb1kbnr/1p3ppp/2p1p3/3p4/2P4B/2qP4/3RPPPP/1r2KBNR w Kk - 0 19");
CHECK(a.IsCheckMate());
CHECK(a.GetFEN() ==
"1nb1kbnr/1p3ppp/2p1p3/3p4/2P4B/2qP4/3RPPPP/1r2KBNR w Kk - 0 19");
// There is no checkmate
a.Setup("1nb1kbnr/1p3ppp/2p1p3/3p4/1QP4B/2qP4/3RPPPP/r3KBNR w Kk - 2 18");
CHECK_FALSE(a.IsCheckMate());
CHECK(a.GetFEN() ==
"1nb1kbnr/1p3ppp/2p1p3/3p4/1QP4B/2qP4/3RPPPP/r3KBNR w Kk - 2 18");
// There is a checkmate
a.Setup("r3qbr1/p1p1pkp1/1p2p1p1/8/8/8/PPPPP1PP/RNBQ1RK1 b - - 1 1");
CHECK(a.IsCheckMate());
CHECK(a.GetFEN() ==
"r3qbr1/p1p1pkp1/1p2p1p1/8/8/8/PPPPP1PP/RNBQ1RK1 b - - 1 1");
}
TEST_CASE("IsDrawByFiftyMoveRule", "[chessarbiter/IsDrawByFiftyMoveRule]") {
ChessArbiter a;
a.Setup("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1");
CHECK_FALSE(a.IsDrawByFiftyMoveRule());
a.Setup("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 99 1");
CHECK_FALSE(a.IsDrawByFiftyMoveRule());
a.Play("b1c3");
CHECK(a.IsDrawByFiftyMoveRule());
a.Setup("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 100 1");
CHECK(a.IsDrawByFiftyMoveRule());
}
TEST_CASE("IsDrawByNoMoves", "[chessarbiter/IsDrawByNoMoves]") {
ChessArbiter a;
// No move for black
a.Setup("8/8/8/8/8/8/5K1p/7k b - - 0 1");
CHECK(a.IsDrawByNoMoves());
// But move for white
a.Setup("8/8/8/8/8/8/5K1p/7k w - - 0 1");
CHECK_FALSE(a.IsDrawByNoMoves());
// No move for white
a.Setup("8/8/7r/2K5/b7/2k5/6q1/8 w - - 0 1");
CHECK(a.IsDrawByNoMoves());
// But move for black
a.Setup("8/8/7r/2K5/b7/2k5/6q1/8 b - - 0 1");
CHECK_FALSE(a.IsDrawByNoMoves());
}
TEST_CASE("IsDrawByRepetitions", "[chessarbiter/IsDrawByRepetitions]") {
ChessArbiter a;
// One time
a.Setup("8/3kp3/8/8/4P3/3K4/8/8 w - - 0 1");
a.Play("d3d4");
a.Play("d7d6");
CHECK_FALSE(a.IsDrawByRepetitions());
// Two time
a.Play("d4d3");
a.Play("d6d7");
CHECK_FALSE(a.IsDrawByRepetitions());
a.Play("d3d4");
a.Play("d7d6");
CHECK_FALSE(a.IsDrawByRepetitions());
// Three time
a.Play("d4d3");
a.Play("d6d7");
CHECK(a.IsDrawByRepetitions());
}
TEST_CASE("SimpleCapture", "[SimplePieceCapture]") {
ChessArbiter a;
a.Setup("rnbqkbnr/ppp1pppp/8/3p4/4P3/8/PPPP1PPP/RNBQKBNR w KQkq - 0 2");
// Ensure capture works
a.Play("e4d5");
CHECK(a.GetFEN() ==
"rnbqkbnr/ppp1pppp/8/3P4/8/8/PPPP1PPP/RNBQKBNR b KQkq - 0 2");
CHECK(a.GetCapture() == 'p');
CHECK_FALSE(a.WasEnPassant());
}
TEST_CASE("SimpleCastle", "[SimpleCastle]") {
ChessArbiter a;
a.Setup("rnbqkbnr/ppp1p1pp/8/3p1p2/4P3/3B1N2/PPPP1PPP/RNBQK2R w KQkq - 0 2");
// White
CHECK(a.Play("e1g1"));
CHECK(a.GetFEN() ==
"rnbqkbnr/ppp1p1pp/8/3p1p2/4P3/3B1N2/PPPP1PPP/RNBQ1RK1 b kq - 1 2");
a.Setup("rnbqkbnr/ppp1p1pp/8/3p1p2/4P3/1BNB1N2/PPPPQPPP/R3K2R w KQkq - 0 2");
CHECK(a.Play("e1c1"));
CHECK(a.GetFEN() ==
"rnbqkbnr/ppp1p1pp/8/3p1p2/4P3/1BNB1N2/PPPPQPPP/2KR3R b kq - 1 2");
// Black
a.Setup(
"r3k2r/pppnp1pp/1bq1bn2/3p1p2/4P3/1BNB1N2/PPPPQPPP/R3K2R b KQkq - 0 2");
CHECK(a.Play("e8g8"));
CHECK(a.GetFEN() ==
"r4rk1/pppnp1pp/1bq1bn2/3p1p2/4P3/1BNB1N2/PPPPQPPP/R3K2R w KQ - 1 3");
a.Setup(
"r3k2r/pppnp1pp/1bq1bn2/3p1p2/4P3/1BNB1N2/PPPPQPPP/R3K2R b KQkq - 0 2");
CHECK(a.Play("e8c8"));
CHECK(a.GetFEN() ==
"2kr3r/pppnp1pp/1bq1bn2/3p1p2/4P3/1BNB1N2/PPPPQPPP/R3K2R w KQ - 1 3");
}
TEST_CASE("SimpleEnPassant", "[SimpleEnPassant]") {
ChessArbiter a;
// White capture
a.Setup("rnbqkbnr/ppppp1pp/8/4Pp2/8/8/PPPP1PPP/RNBQKBNR w KQkq f6 0 2");
CHECK(a.Play("e5f6"));
CHECK(a.GetFEN() ==
"rnbqkbnr/ppppp1pp/5P2/8/8/8/PPPP1PPP/RNBQKBNR b KQkq - 0 2");
CHECK(a.GetCapture() == 'p');
CHECK(a.WasEnPassant());
// Black capture
a.Setup("rnbqkbnr/ppppp1pp/8/8/4Pp2/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1");
CHECK(a.Play("f4e3"));
CHECK(a.GetFEN() ==
"rnbqkbnr/ppppp1pp/8/8/8/4p3/PPPP1PPP/RNBQKBNR w KQkq - 0 2");
CHECK(a.GetCapture() == 'P');
CHECK(a.WasEnPassant());
// Check en_passant is set
a.Setup(
"r3k2r/1pqbbp1p/1nn1p1p1/p2pP3/3P1PP1/PP1B4/1B1NN2P/R2Q1RK1 b kq - 2 14");
CHECK(a.Play("f7f5"));
CHECK(a.GetFEN() == "r3k2r/1pqbb2p/1nn1p1p1/p2pPp2/3P1PP1/PP1B4/1B1NN2P/"
"R2Q1RK1 w kq f6 0 15");
CHECK_FALSE(a.WasEnPassant());
}
TEST_CASE("ParseSAN", "[ParseSAN]") {
ChessArbiter a;
// Initial position test
a.Setup("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1");
CHECK(a.ParseSAN("d4") == "d2d4");
CHECK(a.ParseSAN("e3") == "e2e3");
CHECK(a.ParseSAN("e4") == "e2e4");
CHECK(a.ParseSAN("Nc3") == "b1c3");
CHECK(a.ParseSAN("Nf3") == "g1f3");
// Check when two similar piece can go to the same square
a.Setup("rnbqkbnr/pppppppp/8/8/P6P/7R/1PPPPPP1/RNBQKBN1 w Qkq - 0 1");
CHECK(a.ParseSAN("Raa3") == "a1a3");
CHECK(a.ParseSAN("Rha3") == "h3a3");
a.Setup("rnbqkbnr/pppppppp/8/8/P6P/R7/1PPPPPP1/RNBQKBN1 w Qkq - 0 1");
CHECK(a.ParseSAN("R1a2") == "a1a2");
CHECK(a.ParseSAN("R3a2") == "a3a2");
a.Setup("r1bqkb1r/pppppppp/5n2/8/P6P/R1N5/1PPPPnP1/R1BQKBN1 b Qkq - 0 1");
CHECK(a.ParseSAN("N6e4") == "f6e4");
CHECK(a.ParseSAN("N2e4") == "f2e4");
// Castling
a.Setup("rnbqkbnr/pppppppp/8/8/8/4NB2/PPPPPPPP/RNBQK2R w KQkq - 0 1");
CHECK(a.ParseSAN("O-O") == "e1g1");
a.Setup("rnbqkbnr/pppppppp/8/8/8/2NBQ3/PPPPPPPP/R3KBNR w KQkq - 0 1");
CHECK(a.ParseSAN("O-O-O") == "e1c1");
a.Setup("rnbqk2r/pppppppp/4bn2/8/8/2NBQ3/PPPPPPPP/R3KBNR b KQkq - 0 1");
CHECK(a.ParseSAN("O-O") == "e8g8");
a.Setup("r3kb1r/pppppppp/2qnbn2/8/8/2NBQ3/PPPPPPPP/R3KBNR b KQkq - 0 1");
CHECK(a.ParseSAN("O-O-O") == "e8c8");
// Random tests
a.Setup(
"r1bq1rk1/p4ppp/2p2n2/1pbPp3/3n4/P1NB3P/1PPP1PPN/R1BQ1RK1 b - - 0 10");
CHECK(a.ParseSAN("exd5") == "c6d5");
a.Setup("rnbqkbnr/pp3ppp/4p3/2pp4/3PP3/8/PPPN1PPP/R1BQKBNR w KQkq - 0 4");
CHECK(a.ParseSAN("exd5") == "e4d5");
a.Setup("1r4k1/4pp1p/6pb/1p3b2/P1P5/5P2/2P3PP/1K1R3R w - - 0 23");
CHECK(a.ParseSAN("cxb5") == "c4b5");
}
TEST_CASE("Specific bugs found on a game", "[BugFixes]") {
ChessArbiter a;
// BUG 1
a.Setup("1k3r1r/npqbbp2/4p1p1/p2pPnNp/1P3B1P/P1PB4/5PPQ/RN2R1K1 w - - 1 19");
a.Play("e1c1");
CHECK(a.GetFEN() == "1k3r1r/npqbbp2/4p1p1/p2pPnNp/1P3B1P/P1PB4/5PPQ/RNR3K1 b - - 2 19");
CHECK(!a.WasPawnPromotion());
// BUG 2 (Promotion)
a.Setup("8/k2P4/2p1ppp1/5qBp/5P1P/8/6PK/8 w - - 0 45");
a.Play("d7d8");
CHECK(a.GetFEN() == "3Q4/k7/2p1ppp1/5qBp/5P1P/8/6PK/8 b - - 0 45");
CHECK(a.WasPawnPromotion());
CHECK(a.GetSAN()=="d8=Q");
// BUG 3 (Promotion)
a.Setup("8/k2P4/2p1ppp1/5qBp/5P1P/8/6PK/8 w - - 0 45");
a.Play("d7d8",'n');
CHECK(a.GetFEN() == "3N4/k7/2p1ppp1/5qBp/5P1P/8/6PK/8 b - - 0 45");
CHECK(a.WasPawnPromotion());
CHECK(a.GetSAN()=="d8=N");
// BUG 4 (Promotion)
char p=a.ParseSANPromotion("d8=Q");
CHECK(p == 'Q');
p=a.ParseSANPromotion("d8=N+");
CHECK(p == 'N');
p=a.ParseSANPromotion("d8=B+");
CHECK(p == 'B');
p=a.ParseSANPromotion("h1=R");
CHECK(p == 'R');
p=a.ParseSANPromotion("a1=R");
CHECK(p == 'R');
p=a.ParseSANPromotion("c1=R");
CHECK(p == 'R');
// Bug 5 (Pin piece: the Knight on c3 cannot move so the only legal move for a white Knight is g1e2)
a.Setup("r1bqk2r/pp1n1p2/3p4/1BpP2pp/1b2n2P/2N1P1B1/PP3PP1/R2QK1NR w KQkq - 3 12");
CHECK(a.ParseSAN("Ne2") == "g1e2");
a.Play("g1e2");
CHECK(a.GetFEN() == "r1bqk2r/pp1n1p2/3p4/1BpP2pp/1b2n2P/2N1P1B1/PP2NPP1/R2QK2R b KQkq - 4 12");
// Bug 6 SAN move that lead to check must have a + sign on the SAN moves
a.Setup("rnb1kbnr/pppp1ppp/3qP3/8/8/8/PPP1PPPP/RNB1KBNR b KQkq - 0 4");
a.Play("d6d1");
CHECK(a.IsCheck(false));
CHECK(!a.IsCheck(!false));
CHECK(a.GetSAN()=="Qd1+");
a.Setup("rnb1kbnr/pppp1ppp/3qP3/8/8/8/PPP1PPPP/RNB1KBNR b KQkq - 0 4");
a.Play("d6d3");
CHECK(!a.IsCheck(false));
CHECK(a.GetSAN()=="Qd3");
// Bug 7 SAN move that lead to checkmate must have a # sign on the SAN moves
a.Setup("rnb1k1nr/pppp1ppp/4P3/8/1b3B2/1Nq5/PPP1PPPP/R2KNB1R b kq - 16 12");
a.Play("c3e1");
CHECK(a.GetSAN()=="Qxe1#");
// Bug 8 Not a bug but just check if bishop cannot jump above pieces
a.Setup("rnbqkbnr/p1pp1ppp/8/1p2p3/4P3/8/PPPP1PPP/RNBQKBNR w KQkq - 0 1");
CHECK(!a.Play("f1a6"));
}