mirror of
https://gitlab.com/manzerbredes/chessarbiter.git
synced 2025-04-05 17:46:26 +02:00
302 lines
11 KiB
C++
302 lines
11 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(), "O-O") != 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(), "O-O") != 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(), "O-O") != 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(), "O-O") != 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(), "O-O-O") != 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(), "O-O-O") != 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(), "O-O-O") != 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(), "O-O-O") != 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 - 0 2");
|
|
CHECK_FALSE(a.Play("d7d6")); // White turn
|
|
CHECK(a.GetFEN() ==
|
|
"rnbqkbnr/pppp1ppp/8/4p3/8/4P3/PPPP1PPP/RNBQKBNR w KQkq - 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");
|
|
}
|