#include "catch2/catch.hpp" #include "TestUtils.hpp" #include "EngineFactory.hpp" #include "Engine.hpp" #include "Fen.hpp" #include "Board.hpp" static std::unique_ptr createEngine() { return EngineFactory::createEngine(); } static void testGameEnd(const char* fen, bool isMate) { auto engine = createEngine(); REQUIRE(engine != nullptr); auto board = Fen::createBoard(fen); REQUIRE(board.has_value()); auto pv = engine->pv(board.value()); REQUIRE(pv.isMate() == isMate); REQUIRE(pv.score() == 0); REQUIRE(pv.length() == 0); } static void testMove(const char *fen, const std::vector &expectedMoves) { auto engine = createEngine(); REQUIRE(engine != nullptr); auto board = Fen::createBoard(fen); REQUIRE(board.has_value()); for (const auto &moveName : expectedMoves) { auto pv = engine->pv(board.value()); Move move = *pv.begin(); move.setScore(0); REQUIRE(move == Move::fromUci(moveName)); board->makeMove(move); } } TEST_CASE("Engine detects checkmate", "[Engine][Checkmate]") { auto fen = GENERATE( // https://lichess.org/editor/4R2k/6pp/8/8/8/8/8/K7_b_-_-_0_1 "4R2k/6pp/8/8/8/8/8/K7 b - - 0 1", // https://lichess.org/editor/7k/8/8/8/1bb5/8/r7/3BK3_w_-_-_0_1 "7k/8/8/8/1bb5/8/r7/3BK3 w - - 0 1" ); testGameEnd(fen, true); } TEST_CASE("Engine detects stalemate", "[Engine][Stalemate]") { auto fen = GENERATE( // https://lichess.org/editor/k7/p7/P7/8/8/8/8/KR6_b_-_-_0_1 "k7/p7/P7/8/8/8/8/KR6 b - - 0 1", // https://lichess.org/editor/k7/8/8/6n1/r7/4K3/2q5/8_w_-_-_0_1 "k7/8/8/6n1/r7/4K3/2q5/8 w - - 0 1" ); testGameEnd(fen, false); } TEST_CASE("Puzzles mateIn1_simple", "[Engine][Puzzle]") { auto [fen, moves] = GENERATE(table>({ {"2bQ1k1r/1p3p2/p4b1p/4pNp1/2q5/8/PPP2PPP/1K1RR3 b - - 3 23",{"f6d8", "d1d8"}}, // https://lichess.org/gQa01loO/black#46 {"5rk1/ppp5/2n4p/3b2p1/6R1/P1B1P2P/1Pq5/R2Q2K1 b - - 3 29",{"c2f2"}}, // https://lichess.org/haKJxadR#57 {"r1b1k2r/ppp2pp1/2p5/2b1q1Bp/3PP1n1/2P5/PP2BPPP/RN1Q1RK1 b kq - 0 10",{"e5h2"}}, {"r3rk2/5ppQ/b1pp1q1p/p5n1/P1P5/2N5/1PB2PP1/R3R1K1 w - - 6 24", {"h7h8"}}, })); testMove(fen, moves); }