From 87b483f99922c493d20b40d9dd16beeb9ee443c1 Mon Sep 17 00:00:00 2001 From: Marco Costalba Date: Mon, 26 Dec 2011 16:21:13 +0100 Subject: [PATCH] Reformat UCI option code Make a better use of C++ operators overloading to streamline the APIs. Also sync polyglot.ini file while there. No functional change. Signed-off-by: Marco Costalba --- polyglot.ini | 20 ++++--- src/benchmark.cpp | 6 +- src/search.cpp | 2 +- src/thread.cpp | 4 +- src/uci.cpp | 6 +- src/ucioption.cpp | 139 ++++++++++++++++++---------------------------- src/ucioption.h | 50 +++++++++-------- 7 files changed, 103 insertions(+), 124 deletions(-) diff --git a/polyglot.ini b/polyglot.ini index 4af11dd8..2b6f577f 100644 --- a/polyglot.ini +++ b/polyglot.ini @@ -15,13 +15,10 @@ ResignScore = 600 [Engine] -Hash = 128 -Threads = 1 -OwnBook = false -Book File = book.bin -Best Book Move = false Use Search Log = false Search Log Filename = SearchLog.txt +Book File = book.bin +Best Book Move = false Mobility (Middle Game) = 100 Mobility (Endgame) = 100 Passed Pawns (Middle Game) = 100 @@ -29,11 +26,18 @@ Passed Pawns (Endgame) = 100 Space = 100 Aggressiveness = 100 Cowardice = 100 -Minimum Split Depth = 4 -Maximum Number of Threads per Split Point = 5 -Use Sleeping Threads = false +Min Split Depth = 4 +Max Threads per Split Point = 5 +Threads = 1 +Use Sleeping Threads = true +Hash = 128 +Ponder = true +OwnBook = false +MultiPV = 1 Skill Level = 20 Emergency Move Horizon = 40 Emergency Base Time = 200 Emergency Move Time = 70 Minimum Thinking Time = 20 +UCI_Chess960 = false +UCI_AnalyseMode = false diff --git a/src/benchmark.cpp b/src/benchmark.cpp index 876b270f..464bab78 100644 --- a/src/benchmark.cpp +++ b/src/benchmark.cpp @@ -71,9 +71,9 @@ void benchmark(int argc, char* argv[]) { string fenFile = argc > 5 ? argv[5] : "default"; string valType = argc > 6 ? argv[6] : "depth"; - Options["Hash"].set_value(ttSize); - Options["Threads"].set_value(threads); - Options["OwnBook"].set_value("false"); + Options["Hash"] = ttSize; + Options["Threads"] = threads; + Options["OwnBook"] = false; // Search should be limited by nodes, time or depth ? if (valType == "nodes") diff --git a/src/search.cpp b/src/search.cpp index 4cf8f471..b70409b8 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -318,7 +318,7 @@ void Search::think() { TT.set_size(Options["Hash"].value()); if (Options["Clear Hash"].value()) { - Options["Clear Hash"].set_value("false"); + Options["Clear Hash"] = false; TT.clear(); } diff --git a/src/thread.cpp b/src/thread.cpp index e1c1f8a9..18e35fb0 100644 --- a/src/thread.cpp +++ b/src/thread.cpp @@ -112,8 +112,8 @@ bool Thread::is_available_to(int master) const { void ThreadsManager::read_uci_options() { - maxThreadsPerSplitPoint = Options["Maximum Number of Threads per Split Point"].value(); - minimumSplitDepth = Options["Minimum Split Depth"].value() * ONE_PLY; + maxThreadsPerSplitPoint = Options["Max Threads per Split Point"].value(); + minimumSplitDepth = Options["Min Split Depth"].value() * ONE_PLY; useSleepingThreads = Options["Use Sleeping Threads"].value(); set_size(Options["Threads"].value()); diff --git a/src/uci.cpp b/src/uci.cpp index b875eaf7..c4d01fa1 100644 --- a/src/uci.cpp +++ b/src/uci.cpp @@ -124,7 +124,7 @@ void uci_loop() { else if (token == "uci") cout << "id name " << engine_name() << "\nid author " << engine_authors() - << "\n" << Options.print_all() + << "\n" << Options << "\nuciok" << endl; else cout << "Unknown command: " << cmd << endl; @@ -188,8 +188,8 @@ namespace { while (is >> token) value += string(" ", !value.empty()) + token; - if (Options.find(name) != Options.end()) - Options[name].set_value(value.empty() ? "true" : value); // UCI buttons don't have "value" + if (Options.count(name)) + Options[name] = (value.empty() ? "true" : value); // UCI buttons don't have "value" else cout << "No such option: " << name << endl; } diff --git a/src/ucioption.cpp b/src/ucioption.cpp index 7b8799c4..aad801b8 100644 --- a/src/ucioption.cpp +++ b/src/ucioption.cpp @@ -29,7 +29,7 @@ using std::string; OptionsMap Options; // Global object -// Our case insensitive less() function as required by UCI protocol +/// Our case insensitive less() function as required by UCI protocol static bool ci_less(char c1, char c2) { return tolower(c1) < tolower(c2); } bool CaseInsensitiveLess::operator() (const string& s1, const string& s2) const { @@ -37,120 +37,91 @@ bool CaseInsensitiveLess::operator() (const string& s1, const string& s2) const } -// An helper to convert an integer value to a std::string -static string int_to_string(int v) { - - std::ostringstream ss; - ss << v; - return ss.str(); -} - - /// OptionsMap c'tor initializes the UCI options to their hard coded default /// values and initializes the default value of "Threads" and "Minimum Split Depth" -/// parameters according to the number of CPU cores. +/// parameters according to the number of CPU cores detected. OptionsMap::OptionsMap() { + int cpus = std::min(cpu_count(), MAX_THREADS); + int msd = cpus < 8 ? 4 : 7; OptionsMap& o = *this; - o["Use Search Log"] = UCIOption(false); - o["Search Log Filename"] = UCIOption("SearchLog.txt"); - o["Book File"] = UCIOption("book.bin"); - o["Best Book Move"] = UCIOption(false); - o["Mobility (Middle Game)"] = UCIOption(100, 0, 200); - o["Mobility (Endgame)"] = UCIOption(100, 0, 200); - o["Passed Pawns (Middle Game)"] = UCIOption(100, 0, 200); - o["Passed Pawns (Endgame)"] = UCIOption(100, 0, 200); - o["Space"] = UCIOption(100, 0, 200); - o["Aggressiveness"] = UCIOption(100, 0, 200); - o["Cowardice"] = UCIOption(100, 0, 200); - o["Minimum Split Depth"] = UCIOption(4, 4, 7); - o["Maximum Number of Threads per Split Point"] = UCIOption(5, 4, 8); - o["Threads"] = UCIOption(1, 1, MAX_THREADS); - o["Use Sleeping Threads"] = UCIOption(true); - o["Hash"] = UCIOption(32, 4, 8192); - o["Clear Hash"] = UCIOption(false, "button"); - o["Ponder"] = UCIOption(true); - o["OwnBook"] = UCIOption(true); - o["MultiPV"] = UCIOption(1, 1, 500); - o["Skill Level"] = UCIOption(20, 0, 20); - o["Emergency Move Horizon"] = UCIOption(40, 0, 50); - o["Emergency Base Time"] = UCIOption(200, 0, 30000); - o["Emergency Move Time"] = UCIOption(70, 0, 5000); - o["Minimum Thinking Time"] = UCIOption(20, 0, 5000); - o["UCI_Chess960"] = UCIOption(false); - o["UCI_AnalyseMode"] = UCIOption(false); - - // Set some SMP parameters accordingly to the detected CPU count - UCIOption& thr = o["Threads"]; - UCIOption& msd = o["Minimum Split Depth"]; - - thr.defaultValue = thr.currentValue = int_to_string(cpu_count()); - - if (cpu_count() >= 8) - msd.defaultValue = msd.currentValue = int_to_string(7); + o["Use Search Log"] = UCIOption(false); + o["Search Log Filename"] = UCIOption("SearchLog.txt"); + o["Book File"] = UCIOption("book.bin"); + o["Best Book Move"] = UCIOption(false); + o["Mobility (Middle Game)"] = UCIOption(100, 0, 200); + o["Mobility (Endgame)"] = UCIOption(100, 0, 200); + o["Passed Pawns (Middle Game)"] = UCIOption(100, 0, 200); + o["Passed Pawns (Endgame)"] = UCIOption(100, 0, 200); + o["Space"] = UCIOption(100, 0, 200); + o["Aggressiveness"] = UCIOption(100, 0, 200); + o["Cowardice"] = UCIOption(100, 0, 200); + o["Min Split Depth"] = UCIOption(msd, 4, 7); + o["Max Threads per Split Point"] = UCIOption(5, 4, 8); + o["Threads"] = UCIOption(cpus, 1, MAX_THREADS); + o["Use Sleeping Threads"] = UCIOption(true); + o["Hash"] = UCIOption(32, 4, 8192); + o["Clear Hash"] = UCIOption(false, "button"); + o["Ponder"] = UCIOption(true); + o["OwnBook"] = UCIOption(true); + o["MultiPV"] = UCIOption(1, 1, 500); + o["Skill Level"] = UCIOption(20, 0, 20); + o["Emergency Move Horizon"] = UCIOption(40, 0, 50); + o["Emergency Base Time"] = UCIOption(200, 0, 30000); + o["Emergency Move Time"] = UCIOption(70, 0, 5000); + o["Minimum Thinking Time"] = UCIOption(20, 0, 5000); + o["UCI_Chess960"] = UCIOption(false); + o["UCI_AnalyseMode"] = UCIOption(false); } -/// OptionsMap::print_all() returns a string with all the UCI options in chronological -/// insertion order (the idx field) and in the format defined by the UCI protocol. - -string OptionsMap::print_all() const { +/// operator<<() is used to output all the UCI options in chronological insertion +/// order (the idx field) and in the format defined by the UCI protocol. +std::ostream& operator<<(std::ostream& os, const OptionsMap& om) { - std::stringstream s; - - for (size_t i = 0; i <= size(); i++) - for (OptionsMap::const_iterator it = begin(); it != end(); ++it) + for (size_t i = 0; i <= om.size(); i++) + for (OptionsMap::const_iterator it = om.begin(); it != om.end(); ++it) if (it->second.idx == i) { const UCIOption& o = it->second; - s << "\noption name " << it->first << " type " << o.type; + os << "\noption name " << it->first << " type " << o.type; if (o.type != "button") - s << " default " << o.defaultValue; + os << " default " << o.defaultValue; if (o.type == "spin") - s << " min " << o.minValue << " max " << o.maxValue; + os << " min " << o.min << " max " << o.max; break; } - return s.str(); + return os; } -/// Option class c'tors +/// UCIOption class c'tors -UCIOption::UCIOption(const char* def) : type("string"), minValue(0), maxValue(0), idx(Options.size()) -{ defaultValue = currentValue = def; } +UCIOption::UCIOption(const char* v) : type("string"), min(0), max(0), idx(Options.size()) +{ defaultValue = currentValue = v; } -UCIOption::UCIOption(bool def, string t) : type(t), minValue(0), maxValue(0), idx(Options.size()) -{ defaultValue = currentValue = (def ? "true" : "false"); } +UCIOption::UCIOption(bool v, string t) : type(t), min(0), max(0), idx(Options.size()) +{ defaultValue = currentValue = (v ? "true" : "false"); } -UCIOption::UCIOption(int def, int minv, int maxv) : type("spin"), minValue(minv), maxValue(maxv), idx(Options.size()) -{ defaultValue = currentValue = int_to_string(def); } +UCIOption::UCIOption(int v, int minv, int maxv) : type("spin"), min(minv), max(maxv), idx(Options.size()) +{ std::ostringstream ss; ss << v; defaultValue = currentValue = ss.str(); } -/// set_value() updates currentValue of the Option object. Normally it's up to -/// the GUI to check for option's limits, but we could receive the new value -/// directly from the user by teminal window. So let's check the bounds anyway. +/// UCIOption::operator=() updates currentValue. Normally it's up to the GUI to +/// check for option's limits, but we could receive the new value directly from +/// the user by teminal window, so let's check the bounds anyway. -void UCIOption::set_value(const string& v) { +void UCIOption::operator=(const string& v) { assert(!type.empty()); - if (v.empty()) - return; - - if ((type == "check" || type == "button") != (v == "true" || v == "false")) - return; - - if (type == "spin") - { - int val = atoi(v.c_str()); - if (val < minValue || val > maxValue) - return; - } - - currentValue = v; + if ( !v.empty() + && (type == "check" || type == "button") == (v == "true" || v == "false") + && (type != "spin" || (atoi(v.c_str()) >= min && atoi(v.c_str()) <= max))) + currentValue = v; } diff --git a/src/ucioption.h b/src/ucioption.h index d0d655cd..b8622e51 100644 --- a/src/ucioption.h +++ b/src/ucioption.h @@ -25,41 +25,30 @@ #include #include +struct OptionsMap; + +/// UCIOption class implements an option as defined by UCI protocol class UCIOption { public: - UCIOption() {} // To be used in a std::map - UCIOption(const char* defaultValue); - UCIOption(bool defaultValue, std::string type = "check"); - UCIOption(int defaultValue, int minValue, int maxValue); + UCIOption() {} // Required by std::map::operator[] + UCIOption(const char* v); + UCIOption(bool v, std::string type = "check"); + UCIOption(int v, int min, int max); - void set_value(const std::string& v); template T value() const; + void operator=(const std::string& v); + void operator=(bool v) { *this = std::string(v ? "true" : "false"); } private: - friend struct OptionsMap; + friend std::ostream& operator<<(std::ostream&, const OptionsMap&); std::string defaultValue, currentValue, type; - int minValue, maxValue; + int min, max; size_t idx; }; -/// Custom comparator because UCI options should be case insensitive -struct CaseInsensitiveLess { - bool operator() (const std::string&, const std::string&) const; -}; - - -/// Our options container is actually a map with a customized c'tor -struct OptionsMap : public std::map { - OptionsMap(); - std::string print_all() const; -}; - -extern OptionsMap Options; - - -/// Option::value() definition and specializations +/// UCIOption::value() definition and specializations template T UCIOption::value() const { @@ -81,4 +70,19 @@ inline bool UCIOption::value() const { return currentValue == "true"; } + +/// Custom comparator because UCI options should be case insensitive +struct CaseInsensitiveLess { + bool operator() (const std::string&, const std::string&) const; +}; + + +/// Our options container is actually a map with a customized c'tor +struct OptionsMap : public std::map { + OptionsMap(); +}; + +extern std::ostream& operator<<(std::ostream&, const OptionsMap&); +extern OptionsMap Options; + #endif // !defined(UCIOPTION_H_INCLUDED) -- 2.39.2