#include "uci.hpp" #include "board.hpp" #include "bot.hpp" #include "fen.hpp" #include "moves.hpp" #include #include #include #include #include #include #include #include #include #include #include #include std::ofstream uciLog("uci_log.txt", std::ios::app); void LogUci(const std::string &message) { if (!uciLog.is_open()) return; auto now = std::chrono::system_clock::now(); auto time = std::chrono::system_clock::to_time_t(now); uciLog << "[" << std::put_time(std::localtime(&time), "%H:%M:%S") << "] " << message << "\n"; uciLog.flush(); } 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; } } Move UciToMove(string uci) { Position from; Position to; from.file = uci[0] - 'a'; from.rank = '8' - uci[1]; to.file = uci[2] - 'a'; to.rank = '8' - uci[3]; return {from, to}; } 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 Uci() { Game game = initBoard("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"); string line; while (getline(cin, line)) { string cmd = line; LogUci("GUI -> ENGINE: " + line); transform(cmd.begin(), cmd.end(), cmd.begin(), ::tolower); if (cmd == "quit") { break; } if (cmd == "uci") { cout << "uciok\n"; cout.flush(); } else if (cmd == "ucinewgame") { game = initBoard("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"); } 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; if (best.promotion != NONE) { switch (best.promotion) { case QUEEN: cout << "q"; break; case ROOK: cout << "r"; break; case KNIGHT: cout << "n"; break; case BISHOP: cout << "b"; break; default: assert(false && "Unexepted promotion type"); } } println(); cout.flush(); } else if (cmd.starts_with("position")) { stringstream ss(line); string token; ss >> token; // position ss >> token; if (token == "startpos") { game = initBoard( "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"); } else if (token == "fen") { string fen; string part; // FEN has spaces, need 6 parts for (int i = 0; i < 6; i++) { ss >> part; if (i) fen += " "; fen += part; } game = initBoard(fen); } // check for moves while (ss >> token) { if (token == "moves") break; } while (ss >> token) { Move move = UciToMove(token); PlayMove(move, &game); } } } } 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"; } }