#include "UciParser.h" #include #include #include "ChessGame.h" #include "EngineInfo.h" using namespace std; const map UciParser::commandHandlers = { { "uci", &UciParser::uci }, { "debug", &UciParser::debug }, { "isready", &UciParser::isready }, { "setoption", &UciParser::setoption }, { "register", &UciParser::doNothing }, { "ucinewgame", &UciParser::ucinewgame }, { "position", &UciParser::position }, { "go", &UciParser::go }, { "stop", &UciParser::stop }, { "quit", &UciParser::quit }, { "getfen", &UciParser::getfen }, { "perft", &UciParser::perft }, }; #include int UciParser::parse(istream& in, ostream& out) { ofstream log{ "log.log" }; while (!in.eof() && !quitting) { string line; getline(in, line); if (!line.empty()) { executeLine(line); log << line << endl; } } log.close(); return 0; } int UciParser::executeLine(const string& line) { istringstream s{ line }; string token; string command; vector args; s >> command; while (s >> token) { args.push_back(std::move(token)); } return executeCommand(command, args); } int UciParser::executeCommand(const string& command, const vector& args) { try { CommandHandler ch = commandHandlers.at(command); (this->*ch)(args); return 0; } catch (out_of_range& oor) { // no handler for command -> invalid command out << "unknown command: " << command << endl; return 1; } catch (...) { out << "unknown error occurred" << endl; return 1; } } void UciParser::sendCommand(const std::string& command, const std::vector& args) { std::unique_lock lock { outStreamLock }; cout << command; std::for_each(args.begin(), args.end(), [] (auto& x) { cout << " " << x; }); cout << endl; } void UciParser::uci(const std::vector& args) { sendCommand("id", { "name", "Chessy", chessy::info::versionString }); sendCommand("id", { "author", "N. Winkler" }); sendCommand("uciok"); } void UciParser::debug(const vector& args) { // not yet implemented } void UciParser::isready(const vector& args) { sendCommand("readyok"); } void UciParser::setoption(const vector& args) { Option o; //optionsManager.setOption(); } void UciParser::ucinewgame(const vector& args) { return; } void UciParser::position(const vector& args) { try { size_t movesIndex = 0; if (args.at(0) == "fen") { string fenString = args.at(1) + " " + args.at(2) + " " + args.at(3) + " " + args.at(4) + " " + args.at(5) + " " + args.at(6); cg.loadFromFen(fenString); movesIndex = 6; } else if (args.at(0) == "startpos") { cg = chessy::ChessGame(); movesIndex = 1; } if (args.size() > movesIndex + 1 && args.at(movesIndex) == "moves") { for (size_t i = movesIndex + 1; i < args.size(); i++) { using chessy::Move; Move move = Move{ args[i] }; cg.move(move); } } } catch(out_of_range& oor) { out << "invalid arguments for command 'position'" << endl; } catch(runtime_error& re) { out << "" << endl; } } void UciParser::go(const vector& args) { stop({}); chessy::Move bestMove; chessy::MoveValue value; int depth = 6; tie(bestMove, value) = chessy::miniMax(this->cg, depth); write("info", "depth", depth, "score", "cp", value); sendCommand("bestmove", { bestMove.asString() }); /*fst = make_unique(cg, *this); fst->setThinkTime(std::chrono::milliseconds{ 1000 }); fst->startSearch();*/ //chessy::Move m = minimax.calculateBest(5); // TODO: hack! /*string suffix; if (cg.getBoard().getAtPosition(m.origin) == chessy::PieceType::PAWN && (m.destination.index < 8 || m.destination.index >= 56)) { suffix = "Q"; }*/ //sendCommand("bestmove", { m.asString() + suffix }); } void UciParser::stop(const vector& args) { if (fst) { fst->stop(); fst->join(); fst = nullptr; } } void UciParser::quit(const vector& args) { quitting = true; } void UciParser::getfen(const vector& args) { out << cg.generateFen() << endl; } void UciParser::perft(const vector& args) { using chessy::perft; if (!args.empty()) { int depth = 0; try { depth = std::stoi(args[0]); } catch(...) { out << "invalid argument to perft: " << args[0] << endl; return; } perft(out, cg, depth); } } void UciParser::doNothing(const vector& args) { // explicitly do nothing return; }