From 51d27e1ab9058c9e0fafb399e22edf7b38470510 Mon Sep 17 00:00:00 2001 From: Adam Date: Mon, 27 Jul 2026 20:14:54 +0200 Subject: adding uci --- src/board.cpp | 4 +- src/board.hpp | 6 +- src/bot.cpp | 12 ++-- src/bot.hpp | 6 +- src/fen.cpp | 2 +- src/fen.hpp | 2 +- src/main.cpp | 31 +++------ src/moves.cpp | 16 ++--- src/moves.hpp | 12 ++-- src/repl.cpp | 162 -------------------------------------------- src/repl.hpp | 12 ---- src/uci.cpp | 213 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/uci.hpp | 13 ++++ 13 files changed, 264 insertions(+), 227 deletions(-) delete mode 100644 src/repl.cpp delete mode 100644 src/repl.hpp create mode 100644 src/uci.cpp create mode 100644 src/uci.hpp (limited to 'src') diff --git a/src/board.cpp b/src/board.cpp index 3c5f5ec..0698571 100644 --- a/src/board.cpp +++ b/src/board.cpp @@ -35,7 +35,7 @@ Piece createPiece(PieceType type, bool color, bool moved) { piece.moved = moved; return piece; } -void printBoard(Board *b) { +void printBoard(Game *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"; @@ -100,7 +100,7 @@ void printBoard(Board *b) { std::printf("Board Eval: %f\n", EvaluateBoardForWhite(b)); } -void PlayMove(Move move, Board *b) { +void PlayMove(Move move, Game *b) { // TODO: add all fide behavior Piece piece = b->pieces[PositionToIndex(move.From)]; Piece piece2 = b->pieces[PositionToIndex(move.To)]; diff --git a/src/board.hpp b/src/board.hpp index e782be5..5e4e777 100644 --- a/src/board.hpp +++ b/src/board.hpp @@ -35,7 +35,7 @@ struct Position { bool operator==(const Position &) const = default; }; -struct Board { +struct Game { Piece pieces[64]; bool turn; // 1 white; 0 black std::string castle; @@ -52,9 +52,9 @@ struct Move { bool operator==(const Move &) const = default; }; -void printBoard(Board *b); +void printBoard(Game *b); Piece createPiece(PieceType type, bool color, bool moved = false); -void PlayMove(Move move, Board *b); +void PlayMove(Move move, Game *b); int PositionToIndex(Position i); #endif /* SRC_BOARD_H_ */ diff --git a/src/bot.cpp b/src/bot.cpp index e3a39f2..d0730d8 100644 --- a/src/bot.cpp +++ b/src/bot.cpp @@ -17,7 +17,7 @@ const int SEARCH_DEPTH = 3; int positions_consider = 0; -Move EngineGetBestMove(Board *b) { +Move EngineGetBestMove(Game *b) { auto moves = GetLegalMoves(b); if (moves.size() == 0) { assert(false && "Unhanled error zero legal moves for bot"); @@ -25,7 +25,7 @@ Move EngineGetBestMove(Board *b) { Move bestMove = moves[0]; float BestEval = (b->turn ? -INFINITY : INFINITY); for (Move move : moves) { - Board TestBoard = *b; + Game TestBoard = *b; PlayMove(move, &TestBoard); float alpha = -INFINITY; float beta = INFINITY; @@ -46,7 +46,7 @@ Move EngineGetBestMove(Board *b) { std::cout << "\nConsider: " << positions_consider << "\n"; return bestMove; } -float minimax(int depth, Board *b, float alpha, float beta) { +float minimax(int depth, Game *b, float alpha, float beta) { if (depth == 0) { return EvaluateBoardForWhite(b); } @@ -58,7 +58,7 @@ float minimax(int depth, Board *b, float alpha, float beta) { float bestEval = -INFINITY; for (Move move : moves) { - Board next = *b; + Game next = *b; PlayMove(move, &next); float eval = minimax(depth - 1, &next, alpha, beta); @@ -76,7 +76,7 @@ float minimax(int depth, Board *b, float alpha, float beta) { float BestEval = INFINITY; for (Move move : moves) { - Board next = *b; + Game next = *b; PlayMove(move, &next); float eval = minimax(depth - 1, &next, alpha, beta); @@ -92,7 +92,7 @@ float minimax(int depth, Board *b, float alpha, float beta) { } } -float EvaluateBoardForWhite(Board *b) { +float EvaluateBoardForWhite(Game *b) { positions_consider++; float score = 0; diff --git a/src/bot.hpp b/src/bot.hpp index 1403bc4..242fdfe 100644 --- a/src/bot.hpp +++ b/src/bot.hpp @@ -2,8 +2,8 @@ #define SRC_BOT_H_ #include "board.hpp" -Move EngineGetBestMove(Board *b); -float EvaluateBoardForWhite(Board *b); -float minimax(int depth, Board *b, float alpha, float beta); +Move EngineGetBestMove(Game *b); +float EvaluateBoardForWhite(Game *b); +float minimax(int depth, Game *b, float alpha, float beta); #endif /* SRC_BOT_H_ */ diff --git a/src/fen.cpp b/src/fen.cpp index fa8f289..21ea778 100644 --- a/src/fen.cpp +++ b/src/fen.cpp @@ -9,7 +9,7 @@ bool WHITE = true; bool BLACK = false; -void setBoardFen(std::string fen, Board *b) { +void setBoardFen(std::string fen, Game *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 1bd7f80..406f5fe 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, Game *b); #endif /* SRC_FEN_H_ */ diff --git a/src/main.cpp b/src/main.cpp index 555e728..7b7e6fe 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,7 +1,7 @@ #include "board.hpp" #include "fen.hpp" #include "moves.hpp" -#include "repl.hpp" +#include "uci.hpp" #include #include #include @@ -14,7 +14,7 @@ enum Mode { REPL, }; -void setAllPiecesToEmpty(Board *b) { +void setAllPiecesToEmpty(Game *b) { Piece EmptyPiece = { false, NONE, @@ -24,8 +24,8 @@ void setAllPiecesToEmpty(Board *b) { b->pieces[i] = EmptyPiece; }; }; -Board initBoard(string startingFEN) { - Board b; +Game initBoard(string startingFEN) { + Game b; b.enPassant = IndexToPosition(0); // default value b.canEnpassant = false; b.state = TURN; @@ -36,31 +36,16 @@ Board initBoard(string startingFEN) { setBoardFen(startingFEN, &b); return b; }; -#define askMode = false int main(int argc, char **argv) { srand(time(0)); - std::string startingFen = - "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"; if (argc < 1 || argc > 2) { - printf("wrong arg count, use: ./chess [optinal starting fen]\n"); + printf("wrong arg count, use: ./chess [--repl for debugging]\n"); return 1; } - printf("arg count: %d\n", argc); - if (argc == 2) { - startingFen = argv[1]; - } - - Mode mode = REPL; - // ADD support for other modes here + if (argc > 1 && std::string(argv[1]) == "--repl") + return startREPL(); - Board b = initBoard(startingFen); - if (mode == REPL) { - int replExitCode = startREPL(&b); - return replExitCode; - } - if (mode == EXIT) { - return 0; - } + UciInit(); return 0; } diff --git a/src/moves.cpp b/src/moves.cpp index 9c7991a..5401e8b 100644 --- a/src/moves.cpp +++ b/src/moves.cpp @@ -6,7 +6,7 @@ #include "board.hpp" #include "moves.hpp" -void GenerateKnightMoves(Board *b, int from, std::vector &moves) { +void GenerateKnightMoves(Game *b, int from, std::vector &moves) { Piece knight = b->pieces[from]; if (knight.type != KNIGHT) { @@ -34,7 +34,7 @@ void GenerateKnightMoves(Board *b, int from, std::vector &moves) { moves.push_back({IndexToPosition(from), IndexToPosition(next)}); } }; -void GeneratePawnMoves(Board *b, int from, std::vector &moves) { +void GeneratePawnMoves(Game *b, int from, std::vector &moves) { Piece pawn = b->pieces[from]; if (pawn.type != PAWN) { assert(false && "Calling generate pawn moves on non pawn"); @@ -83,7 +83,7 @@ void GeneratePawnMoves(Board *b, int from, std::vector &moves) { // the end } -std::vector GetPseudoLegalMoves(Board *b) { +std::vector GetPseudoLegalMoves(Game *b) { std::vector moves; moves.reserve(50); // almost all position dont have that many moves @@ -123,12 +123,12 @@ std::vector GetPseudoLegalMoves(Board *b) { return moves; } -std::vector GetLegalMoves(Board *b) { +std::vector GetLegalMoves(Game *b) { std::vector moves = GetPseudoLegalMoves(b); std::vector legalMove; for (Move move : moves) { bool isLegal = true; - Board testBoard = *b; + Game testBoard = *b; PlayMove(move, &testBoard); auto opponentResponse = GetPseudoLegalMoves(&testBoard); for (Move move : opponentResponse) { @@ -143,7 +143,7 @@ std::vector GetLegalMoves(Board *b) { if (legalMove.size() == 0) { bool isCheck = false; - Board testBoard = *b; + Game testBoard = *b; auto opponentResponse = GetPseudoLegalMoves(&testBoard); for (Move move : opponentResponse) { if (testBoard.pieces[PositionToIndex(move.To)].type == KING) { @@ -170,7 +170,7 @@ Position IndexToPosition(int i) { return {rank, file}; } -void GenerateSlidingMoves(Board *b, int from, +void GenerateSlidingMoves(Game *b, int from, const std::array &directions, std::vector &moves) { for (uint i = 0; i < directions.size(); i++) { @@ -205,7 +205,7 @@ void GenerateSlidingMoves(Board *b, int from, }; }; -void GenerateKingMoves(Board *b, int from, std::vector &moves) { +void GenerateKingMoves(Game *b, int from, std::vector &moves) { if (b->pieces[from].type != KING) { assert(false && "calling generate king moves on non king"); return; diff --git a/src/moves.hpp b/src/moves.hpp index a957d3a..4c6716e 100644 --- a/src/moves.hpp +++ b/src/moves.hpp @@ -4,14 +4,14 @@ #include "board.hpp" #include -std::vector GetLegalMoves(Board *b); -std::vector GetPseudoLegalMoves(Board *b); +std::vector GetLegalMoves(Game *b); +std::vector GetPseudoLegalMoves(Game *b); Position IndexToPosition(int i); -void GenerateSlidingMoves(Board *b, int from, +void GenerateSlidingMoves(Game *b, int from, const std::array &directions, std::vector &moves); -void GenerateKingMoves(Board *b, int from, std::vector &moves); -void GenerateKningtMoves(Board *b, int from, std::vector &moves); -void GeneratePawnMoves(Board *b, int from, std::vector &moves); +void GenerateKingMoves(Game *b, int from, std::vector &moves); +void GenerateKningtMoves(Game *b, int from, std::vector &moves); +void GeneratePawnMoves(Game *b, int from, std::vector &moves); #endif /* SRC_MOVES_H_ */ diff --git a/src/repl.cpp b/src/repl.cpp deleted file mode 100644 index b936af0..0000000 --- a/src/repl.cpp +++ /dev/null @@ -1,162 +0,0 @@ -#include "repl.hpp" -#include "board.hpp" -#include "bot.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) { - GetLegalMoves(b); - if (b->state == STALEMATE) { - printBoard(b); - std::println(); - std::cout << "\033[1mStalemate\033[0m" << "\n"; - std::println(); - return 0; - } - if (b->state == DRAW) { - printBoard(b); - std::println(); - std::cout << "\033[1mDraw\033[0m" << "\n"; - std::println(); - return 0; - } - if (b->state == WHITE_WON) { - printBoard(b); - std::cout << "\033[1mChechmate White won\033[0m" << "\n"; - return 0; - } - if (b->state == BLACK_WON) { - printBoard(b); - std::cout << "\033[1mCheckmate Black won\033[0m" << "\n"; - return 0; - } - if (b->state == TURN) { - if (true) { - Move move = EngineGetBestMove(b); - PlayMove(move, b); - printBoard(b); - continue; - } - } - std::cout << "> "; - std::string command; - if (!(std::cin >> command)) { - std::println(); - std::cout << "Exiting...\n"; - return EXIT_SUCCESS; - } - - std::transform(command.begin(), command.end(), command.begin(), ::toupper); - - std::cout << command << "\n"; - if (command == "EXIT") { - std::println(); - std::cout << "Exiting...\n"; - return EXIT_SUCCESS; - } - if (command == "RESING") { - std::cout << "\033[1mOK\033[0m" << "\n"; - if (b->turn) { - b->state = BLACK_WON; - } else { - b->state = WHITE_WON; - } - continue; - } - if (command == "BOARD") { - printBoard(b); - continue; - } - if (command == "MOVES" || command == "MOVE") { - auto moves = GetLegalMoves(b); - PrintMoves(moves); - continue; - } - if (command.length() != 4) { - std::cout << "Unknown Command, use EXIT to exit"; - std::println(); - continue; - } - if (b->state == TURN) { - 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); - printBoard(b); - } - } -} - -void PrintMoves(const std::vector &moves) { - std::cout << "Moves (" << moves.size() << "):\n"; - - for (const Move &move : moves) { - std::cout << (char)((int)move.From.file + 'A') << 8 - (int)move.From.rank - << " -> " << (char)((int)move.To.file + 'A') - << 8 - (int)move.To.rank << "\n"; - } -} diff --git a/src/repl.hpp b/src/repl.hpp deleted file mode 100644 index 5f457c4..0000000 --- a/src/repl.hpp +++ /dev/null @@ -1,12 +0,0 @@ -#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_ */ diff --git a/src/uci.cpp b/src/uci.cpp new file mode 100644 index 0000000..debf886 --- /dev/null +++ b/src/uci.cpp @@ -0,0 +1,213 @@ +#include "uci.hpp" +#include "board.hpp" +#include "bot.hpp" +#include "fen.hpp" +#include "moves.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; + } +} +static Game initBoard(string startingFEN) { + Game b; + b.enPassant = IndexToPosition(0); // default value + b.canEnpassant = false; + b.state = TURN; + b.turn = true; + b.castle = ""; + b.halfMoveClock = 0; + b.MoveClock = 0; + setBoardFen(startingFEN, &b); + return b; +}; +void UciInit() { + Game game = + initBoard("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"); + + string line; + + while (getline(cin, line)) { + string cmd = line; + + transform(cmd.begin(), cmd.end(), cmd.begin(), ::toupper); + + if (cmd == "QUIT") { + break; + } + if (cmd == "UCI") { + cout << "uciok\n"; + cout.flush(); + } else if (cmd == "ISREADY") { + cout << "readyok\n"; + cout.flush(); + } else if (cmd.starts_with("GO")) { + Move best = EngineGetBestMove(&game); + + cout << "bestmove "; + cout << (char)(best.From.file + 'a') + << 8 - best.From.rank + << (char)(best.To.file + 'a') << 8 - best.To.rank; + println(); + + cout.flush(); + } + } +} +int startREPL() { + + Game g = + initBoard("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"); + Game *b = &g; + printBoard(b); + while (true) { + GetLegalMoves(b); + if (b->state == STALEMATE) { + printBoard(b); + std::println(); + std::cout << "\033[1mStalemate\033[0m" << "\n"; + std::println(); + return 0; + } + if (b->state == DRAW) { + printBoard(b); + std::println(); + std::cout << "\033[1mDraw\033[0m" << "\n"; + std::println(); + return 0; + } + if (b->state == WHITE_WON) { + printBoard(b); + std::cout << "\033[1mChechmate White won\033[0m" << "\n"; + return 0; + } + if (b->state == BLACK_WON) { + printBoard(b); + std::cout << "\033[1mCheckmate Black won\033[0m" << "\n"; + return 0; + } + if (b->state == TURN) { + if (true) { + Move move = EngineGetBestMove(b); + PlayMove(move, b); + printBoard(b); + continue; + } + } + std::cout << "> "; + std::string command; + if (!(std::cin >> command)) { + std::println(); + std::cout << "Exiting...\n"; + return EXIT_SUCCESS; + } + + std::transform(command.begin(), command.end(), command.begin(), ::toupper); + + std::cout << command << "\n"; + if (command == "EXIT") { + std::println(); + std::cout << "Exiting...\n"; + return EXIT_SUCCESS; + } + if (command == "RESING") { + std::cout << "\033[1mOK\033[0m" << "\n"; + if (b->turn) { + b->state = BLACK_WON; + } else { + b->state = WHITE_WON; + } + continue; + } + if (command == "BOARD") { + printBoard(b); + continue; + } + if (command == "MOVES" || command == "MOVE") { + auto moves = GetLegalMoves(b); + PrintMoves(moves); + continue; + } + if (command.length() != 4) { + std::cout << "Unknown Command, use EXIT to exit"; + std::println(); + continue; + } + if (b->state == TURN) { + 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); + printBoard(b); + } + } +} + +void PrintMoves(const std::vector &moves) { + std::cout << "Moves (" << moves.size() << "):\n"; + + for (const Move &move : moves) { + std::cout << (char)((int)move.From.file + 'A') << 8 - (int)move.From.rank + << " -> " << (char)((int)move.To.file + 'A') + << 8 - (int)move.To.rank << "\n"; + } +} diff --git a/src/uci.hpp b/src/uci.hpp new file mode 100644 index 0000000..9ef939d --- /dev/null +++ b/src/uci.hpp @@ -0,0 +1,13 @@ +#ifndef SRC_UCI_H_ +#define SRC_UCI_H_ + +#include "board.hpp" +#include + +int startREPL(); +void PrintMoves(const std::vector &moves); +bool isValidChessRank(char rank); +bool isValidChessFile(char rank); + +void UciInit(); +#endif /* SRC_UCI_H_ */ -- cgit v1.2.3