From ffdc517b77fdaf400ad4314bbc2e13d1f8ed7660 Mon Sep 17 00:00:00 2001 From: Fabian Fichter Date: Mon, 16 May 2022 21:46:50 +0200 Subject: [PATCH] Convert protocol option to enum Closes #477. --- src/position.cpp | 2 +- src/search.cpp | 14 ++++++------ src/uci.cpp | 58 ++++++++++++++++++++++++++++------------------------ src/uci.h | 16 +++++++++++++- src/ucioption.cpp | 14 +++++------- 5 files changed, 60 insertions(+), 44 deletions(-) diff --git a/src/position.cpp b/src/position.cpp index 7009ff6..14dc975 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -396,7 +396,7 @@ Position& Position::set(const Variant* v, const string& fenStr, bool isChess960, st->epSquare = make_square(File(col - 'a'), Rank(row - '1')); #ifdef LARGEBOARDS // Consider different rank numbering in CECP - if (max_rank() == RANK_10 && Options["Protocol"] == "xboard") + if (max_rank() == RANK_10 && CurrentProtocol == XBOARD) st->epSquare += NORTH; #endif diff --git a/src/search.cpp b/src/search.cpp index 9105577..b7947eb 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -190,14 +190,14 @@ void MainThread::search() { Eval::NNUE::verify(); - if (rootMoves.empty() || (Options["Protocol"] == "xboard" && rootPos.is_optional_game_end())) + if (rootMoves.empty() || (CurrentProtocol == XBOARD && rootPos.is_optional_game_end())) { rootMoves.emplace_back(MOVE_NONE); Value variantResult; Value result = rootPos.is_game_end(variantResult) ? variantResult : rootPos.checkers() ? rootPos.checkmate_value() : rootPos.stalemate_value(); - if (Options["Protocol"] == "xboard") + if (CurrentProtocol == XBOARD) { // rotate MOVE_NONE to front (for optional game end) std::rotate(rootMoves.rbegin(), rootMoves.rbegin() + 1, rootMoves.rend()); @@ -218,7 +218,7 @@ void MainThread::search() { } // Sit in bughouse variants if partner requested it or we are dead - if (rootPos.two_boards() && !Threads.abort && Options["Protocol"] == "xboard") + if (rootPos.two_boards() && !Threads.abort && CurrentProtocol == XBOARD) { while (!Threads.stop && (Partner.sitRequested || (Partner.weDead && !Partner.partnerDead)) && Time.elapsed() < Limits.time[us] - 1000) {} @@ -259,7 +259,7 @@ void MainThread::search() { if (bestThread != this) sync_cout << UCI::pv(bestThread->rootPos, bestThread->completedDepth, -VALUE_INFINITE, VALUE_INFINITE) << sync_endl; - if (Options["Protocol"] == "xboard") + if (CurrentProtocol == XBOARD) { Move bestMove = bestThread->rootMoves[0].pv[0]; // Wait for virtual drop to become real @@ -539,7 +539,7 @@ void Thread::search() { totalTime = std::min(500.0, totalTime); // Update partner in bughouse variants - if (completedDepth >= 8 && rootPos.two_boards() && Options["Protocol"] == "xboard") + if (completedDepth >= 8 && rootPos.two_boards() && CurrentProtocol == XBOARD) { // Communicate clock times relevant for sitting decisions if (Limits.time[us]) @@ -1112,7 +1112,7 @@ moves_loop: // When in check, search starts from here ss->moveCount = ++moveCount; - if (rootNode && thisThread == Threads.main() && Time.elapsed() > 3000 && Options["Protocol"] != "xboard") + if (rootNode && thisThread == Threads.main() && Time.elapsed() > 3000 && is_uci_dialect(CurrentProtocol)) sync_cout << "info depth " << depth << " currmove " << UCI::move(pos, move) << " currmovenumber " << moveCount + thisThread->pvIdx << sync_endl; @@ -1989,7 +1989,7 @@ string UCI::pv(const Position& pos, Depth depth, Value alpha, Value beta) { if (ss.rdbuf()->in_avail()) // Not at first line ss << "\n"; - if (Options["Protocol"] == "xboard") + if (CurrentProtocol == XBOARD) { ss << d << " " << UCI::value(v) << " " diff --git a/src/uci.cpp b/src/uci.cpp index 9a87ab7..34b7e0c 100644 --- a/src/uci.cpp +++ b/src/uci.cpp @@ -102,7 +102,7 @@ namespace { is >> token; // Consume "name" token - if (Options["Protocol"] == "ucci") + if (CurrentProtocol == UCCI) name = token; else // Read option name (can contain spaces) @@ -136,7 +136,7 @@ namespace { limits.startTime = now(); // As early as possible! limits.banmoves = banmoves; - bool isUsi = Options["Protocol"] == "usi"; + bool isUsi = CurrentProtocol == USI; int secResolution = Options["usemillisec"] ? 1 : 1000; while (is >> token) @@ -345,26 +345,29 @@ void UCI::loop(int argc, char* argv[]) { else if (token == "uci" || token == "usi" || token == "ucci" || token == "xboard") { - Options["Protocol"].set_default(token); + CurrentProtocol = token == "uci" ? UCI_GENERAL + : token == "usi" ? USI + : token == "ucci" ? UCCI + : XBOARD; string defaultVariant = string( #ifdef LARGEBOARDS - token == "usi" ? "shogi" - : token == "ucci" ? "xiangqi" + CurrentProtocol == USI ? "shogi" + : CurrentProtocol == UCCI ? "xiangqi" #else - token == "usi" ? "minishogi" - : token == "ucci" ? "minixiangqi" + CurrentProtocol == USI ? "minishogi" + : CurrentProtocol == UCCI ? "minixiangqi" #endif : "chess"); Options["UCI_Variant"].set_default(defaultVariant); std::istringstream ss("startpos"); position(pos, ss, states); - if (token == "uci" || token == "usi" || token == "ucci") + if (is_uci_dialect(CurrentProtocol)) sync_cout << "id name " << engine_info(true) << "\n" << Options << "\n" << token << "ok" << sync_endl; } - else if (Options["Protocol"] == "xboard") + else if (CurrentProtocol == XBOARD) XBoard::stateMachine->process_command(token, is); else if (token == "setoption") setoption(is); @@ -398,9 +401,9 @@ void UCI::loop(int argc, char* argv[]) { else if (token == "fen" || token == "startpos") { #ifdef LARGEBOARDS - if (Options["Protocol"] == "uci" && Options["UCI_Variant"] == "chess") + if (CurrentProtocol == UCI_GENERAL && Options["UCI_Variant"] == "chess") { - Options["Protocol"].set_default("ucicyclone"); + CurrentProtocol = UCI_CYCLONE; Options["UCI_Variant"].set_default("xiangqi"); } #endif @@ -427,7 +430,7 @@ string UCI::value(Value v) { stringstream ss; - if (Options["Protocol"] == "xboard") + if (CurrentProtocol == XBOARD) { if (abs(v) < VALUE_MATE_IN_MAX_PLY) ss << v * 100 / PawnValueEg; @@ -436,8 +439,8 @@ string UCI::value(Value v) { } else if (abs(v) < VALUE_MATE_IN_MAX_PLY) - ss << (Options["Protocol"] == "ucci" ? "" : "cp ") << v * 100 / PawnValueEg; - else if (Options["Protocol"] == "usi") + ss << (CurrentProtocol == UCCI ? "" : "cp ") << v * 100 / PawnValueEg; + else if (CurrentProtocol == USI) // In USI, mate distance is given in ply ss << "mate " << (v > 0 ? VALUE_MATE - v : -VALUE_MATE - v); else @@ -467,20 +470,20 @@ string UCI::wdl(Value v, int ply) { std::string UCI::square(const Position& pos, Square s) { #ifdef LARGEBOARDS - if (Options["Protocol"] == "usi") + if (CurrentProtocol == USI) return rank_of(s) < RANK_10 ? std::string{ char('1' + pos.max_file() - file_of(s)), char('a' + pos.max_rank() - rank_of(s)) } : std::string{ char('0' + (pos.max_file() - file_of(s) + 1) / 10), char('0' + (pos.max_file() - file_of(s) + 1) % 10), char('a' + pos.max_rank() - rank_of(s)) }; - else if (pos.max_rank() == RANK_10 && Options["Protocol"] != "uci") + else if (pos.max_rank() == RANK_10 && CurrentProtocol != UCI_GENERAL) return std::string{ char('a' + file_of(s)), char('0' + rank_of(s)) }; else return rank_of(s) < RANK_10 ? std::string{ char('a' + file_of(s)), char('1' + (rank_of(s) % 10)) } : std::string{ char('a' + file_of(s)), char('0' + ((rank_of(s) + 1) / 10)), char('0' + ((rank_of(s) + 1) % 10)) }; #else - return Options["Protocol"] == "usi" ? std::string{ char('1' + pos.max_file() - file_of(s)), char('a' + pos.max_rank() - rank_of(s)) } - : std::string{ char('a' + file_of(s)), char('1' + rank_of(s)) }; + return CurrentProtocol == USI ? std::string{ char('1' + pos.max_file() - file_of(s)), char('a' + pos.max_rank() - rank_of(s)) } + : std::string{ char('a' + file_of(s)), char('1' + rank_of(s)) }; #endif } @@ -507,12 +510,12 @@ string UCI::move(const Position& pos, Move m) { Square to = to_sq(m); if (m == MOVE_NONE) - return Options["Protocol"] == "usi" ? "resign" : "(none)"; + return CurrentProtocol == USI ? "resign" : "(none)"; if (m == MOVE_NULL) return "0000"; - if (is_pass(m) && Options["Protocol"] == "xboard") + if (is_pass(m) && CurrentProtocol == XBOARD) return "@@@@"; if (is_gating(m) && gating_square(m) == to) @@ -525,7 +528,7 @@ string UCI::move(const Position& pos, Move m) { to = to_sq(m); } - string move = (type_of(m) == DROP ? UCI::dropped_piece(pos, m) + (Options["Protocol"] == "usi" ? '*' : '@') + string move = (type_of(m) == DROP ? UCI::dropped_piece(pos, m) + (CurrentProtocol == USI ? '*' : '@') : UCI::square(pos, from)) + UCI::square(pos, to); if (type_of(m) == PROMOTION) @@ -567,26 +570,25 @@ Move UCI::to_move(const Position& pos, string& str) { return MOVE_NONE; } -std::string UCI::option_name(std::string name, std::string protocol) { - if (protocol == "ucci" && name == "Hash") +std::string UCI::option_name(std::string name) { + if (CurrentProtocol == UCCI && name == "Hash") return "hashsize"; - if (protocol == "usi") + if (CurrentProtocol == USI) { if (name == "Hash" || name == "Ponder" || name == "MultiPV") return "USI_" + name; if (name.substr(0, 4) == "UCI_") name = "USI_" + name.substr(4); } - if (protocol == "ucci" || protocol == "usi") + if (CurrentProtocol == UCCI || CurrentProtocol == USI) std::replace(name.begin(), name.end(), ' ', '_'); return name; } bool UCI::is_valid_option(UCI::OptionsMap& options, std::string& name) { - std::string protocol = options["Protocol"]; for (const auto& it : options) { - std::string optionName = option_name(it.first, protocol); + std::string optionName = option_name(it.first); if (!options.key_comp()(optionName, name) && !options.key_comp()(name, optionName)) { name = it.first; @@ -596,4 +598,6 @@ bool UCI::is_valid_option(UCI::OptionsMap& options, std::string& name) { return false; } +Protocol CurrentProtocol = UCI_GENERAL; // Global object + } // namespace Stockfish diff --git a/src/uci.h b/src/uci.h index 6c12216..ef22a53 100644 --- a/src/uci.h +++ b/src/uci.h @@ -93,13 +93,27 @@ std::string pv(const Position& pos, Depth depth, Value alpha, Value beta); std::string wdl(Value v, int ply); Move to_move(const Position& pos, std::string& str); -std::string option_name(std::string name, std::string protocol); +std::string option_name(std::string name); bool is_valid_option(UCI::OptionsMap& options, std::string& name); } // namespace UCI extern UCI::OptionsMap Options; +enum Protocol { + UCI_GENERAL, + USI, + UCCI, + UCI_CYCLONE, + XBOARD, +}; + +constexpr bool is_uci_dialect(Protocol p) { + return p != XBOARD; +} + +extern Protocol CurrentProtocol; + } // namespace Stockfish #endif // #ifndef UCI_H_INCLUDED diff --git a/src/ucioption.cpp b/src/ucioption.cpp index d87e232..782d51d 100644 --- a/src/ucioption.cpp +++ b/src/ucioption.cpp @@ -92,7 +92,7 @@ void on_variant_change(const Option &o) { if (standard_variants.find(o) != standard_variants.end()) return; int pocketsize = v->pieceDrops ? (v->pocketSize ? v->pocketSize : v->pieceTypes.size()) : 0; - if (Options["Protocol"] == "xboard") + if (CurrentProtocol == XBOARD) { // Overwrite setup command for Janggi variants auto itJanggi = variants.find("janggi"); @@ -178,7 +178,6 @@ void init(OptionsMap& o) { constexpr int MaxHashMB = Is64Bit ? 33554432 : 2048; - o["Protocol"] << Option("uci", {"uci", "usi", "ucci", "ucicyclone", "xboard"}); o["Debug Log File"] << Option("", on_logger); o["Threads"] << Option(1, 1, 512, on_threads); o["Hash"] << Option(16, 1, MaxHashMB, on_hash_size); @@ -216,12 +215,11 @@ void init(OptionsMap& o) { std::ostream& operator<<(std::ostream& os, const OptionsMap& om) { - if (Options["Protocol"] == "xboard") + if (CurrentProtocol == XBOARD) { for (size_t idx = 0; idx < om.size(); ++idx) for (const auto& it : om) - if (it.second.idx == idx && it.first != "Protocol" && it.first != "UCI_Variant" - && it.first != "Threads" && it.first != "Hash") + if (it.second.idx == idx && it.first != "UCI_Variant" && it.first != "Threads" && it.first != "Hash") { const Option& o = it.second; os << "\nfeature option=\"" << it.first << " -" << o.type; @@ -254,11 +252,11 @@ std::ostream& operator<<(std::ostream& os, const OptionsMap& om) { { const Option& o = it.second; // UCI dialects do not allow spaces - if (Options["Protocol"] == "ucci" || Options["Protocol"] == "usi") + if (CurrentProtocol == UCCI || CurrentProtocol == USI) { - string name = option_name(it.first, Options["Protocol"]); + string name = option_name(it.first); // UCCI skips "name" - os << "\noption " << (Options["Protocol"] == "ucci" ? "" : "name ") << name << " type " << o.type; + os << "\noption " << (CurrentProtocol == UCCI ? "" : "name ") << name << " type " << o.type; } else os << "\noption name " << it.first << " type " << o.type; -- 1.7.0.4