From 7e8d89f357aaf8d8a6148ef051752dd53eb0285f Mon Sep 17 00:00:00 2001 From: Adam Date: Sun, 26 Jul 2026 19:16:57 +0200 Subject: adding repl --- CMakeLists.txt | 4 +- src/board.cpp | 17 ++++++- src/board.hpp | 9 ++-- src/fen.cpp | 2 +- src/fen.hpp | 2 +- src/main.cpp | 146 +++++++++++++++------------------------------------------ src/moves.cpp | 16 ++++--- src/moves.hpp | 8 ++-- src/repl.cpp | 109 ++++++++++++++++++++++++++++++++++++++++++ src/repl.hpp | 12 +++++ 10 files changed, 197 insertions(+), 128 deletions(-) create mode 100644 src/repl.cpp create mode 100644 src/repl.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 3f5a42f..ec93cc0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,9 +16,9 @@ add_executable(${PROJECT_NAME} ${SOURCE_FILES}) target_include_directories(${PROJECT_NAME} PRIVATE src) if (MSVC) - target_compile_options(${PROJECT_NAME} PRIVATE /W4 /WX) + target_compile_options(${PROJECT_NAME} PRIVATE /W4 /WX) else() - target_compile_options(${PROJECT_NAME} PRIVATE + target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Wextra -Wpedantic diff --git a/src/board.cpp b/src/board.cpp index 172a9be..54df662 100644 --- a/src/board.cpp +++ b/src/board.cpp @@ -36,7 +36,7 @@ Piece createPiece(pieceType type, bool color, bool moved) { piece.moved = moved; return piece; }; -void printBoard(board *b) { +void printBoard(Board *b) { std::string line = " +-----------------+\n"; std::string whiteLetters = " a b c d e f g h\n"; std::string blackLetters = " h g f e d c b a\n"; @@ -89,4 +89,17 @@ void printBoard(board *b) { std::println("Castling: {}", b->castle); } -// void PlayMove(Move move, board *b) { return; } +void PlayMove(Move move, Board *b) { + // TODO: add all fide behavior + Piece piece = b->pieces[PositionToIndex(move.From)]; + Piece piece2 = b->pieces[PositionToIndex(move.To)]; + if (piece2.type != NONE) { + if (piece2.color == b->turn) { + assert(false && "capturing friendly piece error"); + } + } + b->pieces[PositionToIndex(move.To)] = piece; + b->pieces[PositionToIndex(move.From)] = {false, NONE, false}; + return; +} +int PositionToIndex(Position i) { return i.rank * 8 + i.file; } diff --git a/src/board.hpp b/src/board.hpp index afdb938..9e80025 100644 --- a/src/board.hpp +++ b/src/board.hpp @@ -21,7 +21,7 @@ struct Piece { bool moved; }; -struct board { +struct Board { Piece pieces[64]; bool turn; // 1 white; 0 black std::string castle; @@ -42,8 +42,9 @@ struct Move { bool operator==(const Move &) const = default; }; -void printBoard(board *b); +void printBoard(Board *b); Piece createPiece(pieceType type, bool color, bool moved = false); -void PlayMove(Move move, board *b); // TODO implement -#endif /* SRC_BOARD_H_ */ +void PlayMove(Move move, Board *b); +int PositionToIndex(Position i); +#endif /* SRC_BOARD_H_ */ diff --git a/src/fen.cpp b/src/fen.cpp index 9c3154c..9ddc795 100644 --- a/src/fen.cpp +++ b/src/fen.cpp @@ -8,7 +8,7 @@ bool WHITE = true; bool BLACK = false; -void setBoardFen(std::string fen, board *b) { +void setBoardFen(std::string fen, Board *b) { // example fen rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1 int file = 0; int rank = 0; diff --git a/src/fen.hpp b/src/fen.hpp index 19f88e2..1bd7f80 100644 --- a/src/fen.hpp +++ b/src/fen.hpp @@ -5,5 +5,5 @@ #include "board.hpp" -void setBoardFen(std::string fen, board *b); +void setBoardFen(std::string fen, Board *b); #endif /* SRC_FEN_H_ */ diff --git a/src/main.cpp b/src/main.cpp index 261c19d..4b9e965 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,50 +1,38 @@ #include "board.hpp" #include "fen.hpp" -#include "moves.hpp" -#include -#include -#include +#include "repl.hpp" #include -#include +#include #include #include -#include -#include +using namespace std; -bool isValidChessRank(char rank) { - if (rank >= '1' && rank <= '8') { - return true; - } else { - return false; - } -} -bool isValidChessFile(char rank) { - if (rank >= 'A' && rank <= 'H') { - return true; - } else { - return false; - } -} -void setAllPiecesToEmpty(board *b) { - Piece NonePiece = { +enum Mode { + EXIT, + REPL, +}; + +void setAllPiecesToEmpty(Board *b) { + Piece EmptyPiece = { false, NONE, false, }; for (int i = 0; i < 64; i++) { - b->pieces[i] = NonePiece; + b->pieces[i] = EmptyPiece; }; -} -void PrintMoves(const std::vector &moves) { - std::cout << "Moves (" << moves.size() << "):\n"; +}; +Board initBoard(string startingFEN) { + Board b; + b.turn = true; + b.castle = ""; + b.halfMoveClock = 0; + b.MoveClock = 0; + setBoardFen(startingFEN, &b); + return b; +}; - for (const Move &move : moves) { - std::cout << "(" << (int)move.From.file << ", " << (int)move.From.rank - << ") -> (" << (int)move.To.file << ", " << (int)move.To.rank - << ")\n"; - } -} int main(int argc, char **argv) { std::string startingFen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"; @@ -56,81 +44,25 @@ int main(int argc, char **argv) { if (argc == 2) { startingFen = argv[1]; } - board b; - b.turn = true; - b.castle = ""; - b.halfMoveClock = 0; - b.MoveClock = 0; - setBoardFen(startingFen, &b); - printBoard(&b); - while (true) { - std::cout << "> "; - std::string command; - std::cin >> command; - std::cout << command << "\n"; - - transform(command.begin(), command.end(), command.begin(), ::toupper); - if (command == "EXIT") { - std::println(); - std::cout << "Exiting...\n"; - return 0; - } + println("ENTER which mode you want (REPL)"); + Mode mode = EXIT; + string modeString; + cin >> modeString; + std::transform(modeString.begin(), modeString.end(), modeString.begin(), + ::toupper); - if (command.length() != 4) { - std::cout << "Unknown Command, use EXIT to exit"; - std::println(); - continue; - } - if (!isValidChessFile(command[0])) { - std::cout << "ERROR: Expected valid file at first place"; - std::println(); - continue; - } - - if (!isValidChessRank(command[1])) { - std::cout << "ERROR: Expected valid rank at second place"; - std::println(); - continue; - } - - if (!isValidChessFile(command[2])) { - std::cout << "ERROR: Expected valid file at third place"; - std::println(); - continue; - } - - if (!isValidChessRank(command[3])) { - std::cout << "ERROR: Expected valid rank at four place"; - std::println(); - continue; - } - - // we know its a valid chess pos - int fromFile = command[0] - 'A'; - int fromRank = '8' - command[1]; - int toFile = command[2] - 'A'; - int toRank = '8' - command[3]; - std::cout << fromFile << "\n"; - std::cout << fromRank << "\n"; - std::cout << toFile << "\n"; - std::cout << toRank << "\n"; - Move move = { - {static_cast(fromRank), static_cast(fromFile)}, - {static_cast(toRank), static_cast(toFile)}}; + if (modeString == "REPL") { + mode = REPL; + } + // ADD support for other modes here - auto moves = GetLegalMoves(&b); - if (std::ranges::find(moves, move) != moves.end()) { - std::cout << "Move is legal!\n"; - } else { - std::cout << "Move is not legal!\n"; - PrintMoves(moves); - continue; - } - std::println(); - // PlayMove(move, &b); // todo implement - b.MoveClock++; - b.turn = !b.turn; - printBoard(&b); + Board b = initBoard(startingFen); + if (mode == REPL) { + int replExitCode = startREPL(&b); + return replExitCode; + } + if (mode == EXIT) { + return 0; } - return EXIT_SUCCESS; + return 0; } diff --git a/src/moves.cpp b/src/moves.cpp index 5c8c07e..0059039 100644 --- a/src/moves.cpp +++ b/src/moves.cpp @@ -5,7 +5,7 @@ #include "board.hpp" #include "moves.hpp" -void GeneratePawnMoves(board *b, int from, std::vector &moves) { +void GeneratePawnMoves(Board *b, int from, std::vector &moves) { Piece pawn = b->pieces[from]; if (pawn.type != PAWN) { assert(false && "Calling generate pawn moves on non pawn"); @@ -49,7 +49,7 @@ void GeneratePawnMoves(board *b, int from, std::vector &moves) { // the end } -std::vector GetLegalMoves(board *b) { +std::vector GetLegalMoves(Board *b) { std::vector moves; moves.reserve(50); // almost all position dont have that many moves @@ -93,7 +93,7 @@ Position IndexToPosition(int i) { return {rank, file}; } -void GenerateSlidingMoves(board *b, int from, +void GenerateSlidingMoves(Board *b, int from, const std::array &directions, std::vector &moves) { for (uint i = 0; i < directions.size(); i++) { @@ -128,7 +128,7 @@ void GenerateSlidingMoves(board *b, int from, }; }; -void GenerateKingMoves(board *b, int from, std::vector &moves) { +void GenerateKingMoves(Board *b, int from, std::vector &moves) { if (b->pieces[from].type != KING) { assert(false && "calling generate king moves on non king"); return; @@ -146,9 +146,11 @@ void GenerateKingMoves(board *b, int from, std::vector &moves) { if (std::abs((next % 8) - (from % 8)) > 1) { continue; }; - if (b->pieces[next].color == b->turn) { - continue; - }; + if (b->pieces[next].type != NONE) { + if (b->pieces[next].color == b->turn) { + continue; + }; + } moves.push_back({IndexToPosition(from), IndexToPosition(next)}); } diff --git a/src/moves.hpp b/src/moves.hpp index 2cede49..ae26e29 100644 --- a/src/moves.hpp +++ b/src/moves.hpp @@ -4,12 +4,12 @@ #include "board.hpp" #include -std::vector GetLegalMoves(board *b); +std::vector GetLegalMoves(Board *b); Position IndexToPosition(int i); -void GenerateSlidingMoves(board *b, int from, +void GenerateSlidingMoves(Board *b, int from, const std::array &directions, std::vector &moves); -void GenerateKingMoves(board *b, int from, std::vector &moves); -void GeneratePawnMoves(board *b, int from, std::vector &moves); +void GenerateKingMoves(Board *b, int from, std::vector &moves); +void GeneratePawnMoves(Board *b, int from, std::vector &moves); #endif /* SRC_MOVES_H_ */ diff --git a/src/repl.cpp b/src/repl.cpp new file mode 100644 index 0000000..642419a --- /dev/null +++ b/src/repl.cpp @@ -0,0 +1,109 @@ +#include "repl.hpp" +#include "board.hpp" +#include "moves.hpp" +#include +#include +#include +#include +#include +#include +#include + +bool isValidChessRank(char rank) { + if (rank >= '1' && rank <= '8') { + return true; + } else { + return false; + } +} +bool isValidChessFile(char rank) { + if (rank >= 'A' && rank <= 'H') { + return true; + } else { + return false; + } +} +int startREPL(Board *b) { + printBoard(b); + while (true) { + std::cout << "> "; + std::string command; + std::cin >> command; + + std::transform(command.begin(), command.end(), command.begin(), ::toupper); + if (command == "EXIT") { + std::println(); + std::cout << "Exiting...\n"; + return EXIT_SUCCESS; + } + if (command == "BOARD") { + printBoard(b); + continue; + } + + if (command.length() != 4) { + std::cout << "Unknown Command, use EXIT to exit"; + std::println(); + continue; + } + if (!isValidChessFile(command[0])) { + std::cout << "ERROR: Expected valid file at first place"; + std::println(); + continue; + } + + if (!isValidChessRank(command[1])) { + std::cout << "ERROR: Expected valid rank at second place"; + std::println(); + continue; + } + + if (!isValidChessFile(command[2])) { + std::cout << "ERROR: Expected valid file at third place"; + std::println(); + continue; + } + + if (!isValidChessRank(command[3])) { + std::cout << "ERROR: Expected valid rank at four place"; + std::println(); + continue; + } + + // we know its a valid chess pos + int fromFile = command[0] - 'A'; + int fromRank = '8' - command[1]; + int toFile = command[2] - 'A'; + int toRank = '8' - command[3]; + std::cout << fromFile << "\n"; + std::cout << fromRank << "\n"; + std::cout << toFile << "\n"; + std::cout << toRank << "\n"; + Move move = { + {static_cast(fromRank), static_cast(fromFile)}, + {static_cast(toRank), static_cast(toFile)}}; + + auto moves = GetLegalMoves(b); + if (!(std::ranges::find(moves, move) != moves.end())) { + std::cout << "Invalid move!"; + std::println(); + PrintMoves(moves); + continue; + } + std::println(); + PlayMove(move, b); + b->MoveClock++; + b->turn = !b->turn; + printBoard(b); + } +} + +void PrintMoves(const std::vector &moves) { + std::cout << "Moves (" << moves.size() << "):\n"; + + for (const Move &move : moves) { + std::cout << "(" << (int)move.From.file << ", " << (int)move.From.rank + << ") -> (" << (int)move.To.file << ", " << (int)move.To.rank + << ")\n"; + } +} diff --git a/src/repl.hpp b/src/repl.hpp new file mode 100644 index 0000000..5f457c4 --- /dev/null +++ b/src/repl.hpp @@ -0,0 +1,12 @@ +#ifndef SRC_REPL_H_ +#define SRC_REPL_H_ + +#include "board.hpp" +#include + +int startREPL(Board *b); +void PrintMoves(const std::vector &moves); +bool isValidChessRank(char rank); +bool isValidChessFile(char rank); + +#endif /* SRC_REPL_H_ */ -- cgit v1.2.3