From 69790345c5c7554dfa87476fa740e23965b7d4ad Mon Sep 17 00:00:00 2001 From: MrGeorgen Date: Wed, 20 Mar 2024 22:11:22 +0100 Subject: [PATCH] move gen test --- .gitignore | 1 + CMakeLists.txt | 6 ++++- include/chess/move.h | 3 ++- src/chess/main.c | 6 ++--- src/chess/move.c | 10 ++++---- src/common/bitboard.c | 7 +++--- src/generateCode/moveConsts.c | 12 ++++----- test/moveGen.c | 46 +++++++++++++++++++++++++++++++++++ 8 files changed, 71 insertions(+), 20 deletions(-) create mode 100644 test/moveGen.c diff --git a/.gitignore b/.gitignore index b251f7b..28fd64d 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ !.gitkeep !/include !/.gitignore +!/test diff --git a/CMakeLists.txt b/CMakeLists.txt index 6f99eb1..346a63a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,10 +19,10 @@ pkg_check_modules(GTK4 REQUIRED IMPORTED_TARGET gtk4) pkg_check_modules(LIBRSVG REQUIRED IMPORTED_TARGET librsvg-2.0) add_executable(findMagicNumber src/findMagicNumber.c ${LIB_SOURCES}) +set_property(TARGET findMagicNumber PROPERTY C_STANDARD 99) add_dependencies(findMagicNumber generateCode) add_executable(${PROJECT_NAME} ${SOURCES} ${LIB_SOURCES}) -set_property(TARGET findMagicNumber PROPERTY C_STANDARD 99) set_property(TARGET ${PROJECT_NAME} PROPERTY C_STANDARD 99) target_link_libraries(${PROJECT_NAME} PRIVATE PkgConfig::GTK4 PkgConfig::LIBRSVG) add_dependencies(${PROJECT_NAME} generateCode) @@ -43,3 +43,7 @@ set_property(TARGET chessNoComputer PROPERTY C_STANDARD 99) target_link_libraries(chessNoComputer PRIVATE PkgConfig::GTK4 PkgConfig::LIBRSVG) add_dependencies(chessNoComputer generateCode) target_compile_definitions(chessNoComputer PUBLIC NO_COMPUTER) + +add_executable(moveGenTest test/moveGen.c src/chess/move.c ${LIB_SOURCES}) +set_property(TARGET moveGenTest PROPERTY C_STANDARD 99) +add_test(NAME moveGen COMMAND moveGenTest) diff --git a/include/chess/move.h b/include/chess/move.h index 5eeb935..a251430 100644 --- a/include/chess/move.h +++ b/include/chess/move.h @@ -20,10 +20,11 @@ struct move_t { }; void genDirectionConsts(); -uint_least8_t validMoves(struct gameState_t gameState, bool color, struct move_t *moves); +uint_least8_t validMoves(struct gameState_t gameState, struct move_t *moves); uint_least8_t pieceValidMoves(struct gameState_t gameState, struct piece_t piece, uint_least8_t src, struct move_t *moves, bool promotion); +void undoMove(uint_least64_t *board, struct move_t move, bool color); struct gameState_t makeMove(struct gameState_t gameState, struct move_t move); struct gameState_t computerMove(struct gameState_t gameState); void initMagicTable(); diff --git a/src/chess/main.c b/src/chess/main.c index ae220df..b2aa665 100644 --- a/src/chess/main.c +++ b/src/chess/main.c @@ -176,9 +176,9 @@ static void on_click(GtkGestureClick *gesture, int n_press, double x, double y, static void app_activate(GApplication *app, gpointer data) { GtkWindow *window = GTK_WINDOW(gtk_window_new()); static RsvgHandle *piecesSvg[16]; - static uint_least64_t board[2 * PIECES_LENGTH] = {}; - static struct gameState_t gameState = {board, WHITE, {{true, true}, {true, true}}, 0, NOT_SELECTED}; - + static uint_least64_t board[BITBOARD_LENGTH]; + static struct gameState_t gameState; + gameState = newGameState(board, "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"); { static struct move_t moves[TOTAL_BOARD_SIZE]; static struct drawData_t drawData = {piecesSvg, &gameState, NOT_SELECTED, moves, 0, NOT_SELECTED}; diff --git a/src/chess/move.c b/src/chess/move.c index 0e6bb04..5e02696 100644 --- a/src/chess/move.c +++ b/src/chess/move.c @@ -1,7 +1,7 @@ #include #include #include -#include "move.h" +#include #include #include #include @@ -132,7 +132,7 @@ static void castleMoveRook(uint_least64_t *board, uint_least8_t spezialMove, boo } } -static void undoMove(uint_least64_t *board, struct move_t move, bool color) { +void undoMove(uint_least64_t *board, struct move_t move, bool color) { const struct piece_t srcPiece = {move.srcPiece, color}; const struct piece_t dstPiece = {move.dstPiece, color}; bitboardSet(board, srcPiece, move.src); @@ -300,10 +300,10 @@ uint_least8_t pieceValidMoves(struct gameState_t gameState, struct piece_t piece return movesLength; } -uint_least8_t validMoves(struct gameState_t gameState, bool color, struct move_t *moves) { +uint_least8_t validMoves(struct gameState_t gameState, struct move_t *moves) { uint_least8_t movesLength = 0; for(uint_least8_t pieceType = KING; pieceType < PIECES_LENGTH; ++pieceType) { - const struct piece_t piece = {pieceType, color}; + const struct piece_t piece = {pieceType, gameState.color}; uint_least8_t field; for(uint_least64_t pieceMask = bitboardGetMask(gameState.board, piece); pieceMask != 0; pieceMask = bitsetClear(pieceMask, field)) { @@ -367,6 +367,6 @@ struct gameState_t makeMove(struct gameState_t gameState, struct move_t move) { struct gameState_t computerMove(struct gameState_t gameState) { struct move_t moves[MAX_VALID_MOVES]; - validMoves(gameState, false, moves); + validMoves(gameState, moves); return makeMove(gameState, moves[0]); } diff --git a/src/common/bitboard.c b/src/common/bitboard.c index 48efa69..a21f3f0 100644 --- a/src/common/bitboard.c +++ b/src/common/bitboard.c @@ -76,12 +76,11 @@ struct piece_t pieceAtField(const uint_least64_t *board, uint_least8_t i) { } struct gameState_t newGameState(uint_least64_t *board, char *FEN) { - const char startFEN[] = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"; struct gameState_t gameState = {board}; for(uint_least8_t i = 0; i < BITBOARD_LENGTH; ++i) { board[i] = 0; } - for(uint_least8_t field = 0; *FEN != ' '; ++FEN, ++field) { + for(uint_least8_t field = 0; *FEN != ' '; ++FEN) { struct piece_t piece; switch(tolower(*FEN)) { case 'k': @@ -112,14 +111,14 @@ struct gameState_t newGameState(uint_least64_t *board, char *FEN) { } if(isalpha(*FEN)) piece.color = isupper(*FEN); bitboardSet(board, piece, field); + ++field; } gameState.color = *++FEN == 'w' ? WHITE : BLACK; - struct castle_t canCastle[2] = {}; FEN += 2; if(*FEN == '-') ++FEN; else { for(; *FEN != ' '; ++FEN) { - struct castle_t *playerCastle = canCastle + (isupper(*FEN) ? WHITE : BLACK); + struct castle_t *playerCastle = gameState.canCastle + (isupper(*FEN) ? WHITE : BLACK); if(tolower(*FEN) == 'k') playerCastle->shortCastle = true; else playerCastle->longCastle = true; } diff --git a/src/generateCode/moveConsts.c b/src/generateCode/moveConsts.c index 5659b3b..e0e6f68 100644 --- a/src/generateCode/moveConsts.c +++ b/src/generateCode/moveConsts.c @@ -48,7 +48,7 @@ int main() { offsetField[SOUTHWEST] = min(offsetField[SOUTH], file); offsetField[NORTHEAST] = min(rank, offsetField[EAST]); } - defineArray("#define defineDirectionOffset const uint_least8_t DIRECTION_OFFSET", printerull, directionOffset); + defineArray("#define defineDirectionOffset const static uint_least8_t DIRECTION_OFFSET", printerull, directionOffset); int_least8_t directionModifier[DIRECTION_LENGTH]; directionModifier[NORTH] = -BOARD_SIZE; directionModifier[SOUTH] = BOARD_SIZE; @@ -86,8 +86,8 @@ int main() { } } genCheckMask(knightMoves, knightCheck); - defineArray("#define defineKnightCheck const uint_least64_t KNIGHT_CHECK", printerull, knightCheck); - defineArray("#define defineKnightMoves const struct moveDst_t KNIGHT_MOVES", printerMoveDst, knightMoves); + defineArray("#define defineKnightCheck const static uint_least64_t KNIGHT_CHECK", printerull, knightCheck); + defineArray("#define defineKnightMoves const static struct moveDst_t KNIGHT_MOVES", printerMoveDst, knightMoves); } { uint_least64_t kingCheck[TOTAL_BOARD_SIZE]; @@ -101,8 +101,8 @@ int main() { } } genCheckMask(kingMoves, kingCheck); - defineArray("#define defineKingCheck const uint_least64_t KING_CHECK", printerull, kingCheck); - defineArray("#define defineKingMoves const struct moveDst_t KING_MOVES", printerMoveDst, kingMoves); + defineArray("#define defineKingCheck const static uint_least64_t KING_CHECK", printerull, kingCheck); + defineArray("#define defineKingMoves const static struct moveDst_t KING_MOVES", printerMoveDst, kingMoves); } { uint_least64_t pawnCheck[2 * TOTAL_BOARD_SIZE]; @@ -122,7 +122,7 @@ int main() { pawnCheck[2 * field + color] = checkMask; } } - defineArray("#define definePawnCheck const uint_least64_t PAWN_CHECK", printerull, pawnCheck); + defineArray("#define definePawnCheck const static uint_least64_t PAWN_CHECK", printerull, pawnCheck); } printf("#endif\n"); } diff --git a/test/moveGen.c b/test/moveGen.c new file mode 100644 index 0000000..926b228 --- /dev/null +++ b/test/moveGen.c @@ -0,0 +1,46 @@ +#include "chess/types.h" +#include +#include +#include +#include +#include + +struct perf_t { + char FEN[256]; + uint_least8_t depth; + uint_least64_t nodes; +}; + +uint_least64_t perft(const struct gameState_t gameState, const uint_least8_t depth) { + struct move_t moves[MAX_VALID_MOVES]; + uint_least64_t nodes = 0; + const uint_least8_t movesLength = validMoves(gameState, moves); + if(depth == 1) return movesLength; + for(uint_least8_t i = 0; i < movesLength; ++i) { + const struct gameState_t newGameState = makeMove(gameState, moves[i]); + nodes += perft(newGameState, depth - 1); + undoMove(gameState.board, moves[i], gameState.color); + } + return nodes; +} + +int main() { + struct perf_t testPos[] = { + {"rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1", 5, 4865609}, // start Position 0 + {"r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq 0 1", 4, 4085603}, // 1 + {"8/2p5/3p4/KP5r/1R3p1k/8/4P1P1/8 w - 0 1", 5, 674624}, // 2 + {"r3k2r/Pppp1ppp/1b3nbN/nP6/BBP1P3/q4N2/Pp1P2PP/R2Q1RK1 w kq - 0 1", 4, 422333}, // 3 + {"rnbq1k1r/pp1Pbppp/2p5/8/2B5/8/PPP1NnPP/RNBQK2R w KQ - 1 8", 4, 2103487}, // 4 + {"r4rk1/1pp1qppp/p1np1n2/2b1p1B1/2B1P1b1/P1NP1N2/1PP1QPPP/R4RK1 w - - 0 10", 4, 3894594}, // 5 + }; + initMagicTable(); + for(uint_least16_t i = 0; i < LENGTH(testPos); ++i) { + uint_least64_t board[BITBOARD_LENGTH]; + const struct gameState_t gameState = newGameState(board, testPos[i].FEN); + const uint_least64_t nodes = perft(gameState, testPos[i].depth); + if(testPos[i].nodes != nodes) { + printf("Test %" PRIuLEAST16 " failed: FEN: %s, depth: %" PRIuLEAST8 " calculated nodes: %" PRIuLEAST64 + ", expected nodes: %" PRIuLEAST64 "\n", i, testPos[i].FEN, testPos[i].depth, nodes, testPos[i].nodes); + } + } +}