1 | /* |
2 | Stockfish, a UCI chess playing engine derived from Glaurung 2.1 |
3 | Copyright (C) 2004-2008 Tord Romstad (Glaurung author) |
4 | Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad |
5 | Copyright (C) 2015-2019 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad |
6 | |
7 | Stockfish is free software: you can redistribute it and/or modify |
8 | it under the terms of the GNU General Public License as published by |
9 | the Free Software Foundation, either version 3 of the License, or |
10 | (at your option) any later version. |
11 | |
12 | Stockfish is distributed in the hope that it will be useful, |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 | GNU General Public License for more details. |
16 | |
17 | You should have received a copy of the GNU General Public License |
18 | along with this program. If not, see <http://www.gnu.org/licenses/>. |
19 | */ |
20 | |
21 | #include <algorithm> |
22 | #include <cassert> |
23 | #include <ostream> |
24 | #include <sstream> |
25 | |
26 | #include "misc.h" |
27 | #include "search.h" |
28 | #include "thread.h" |
29 | #include "tt.h" |
30 | #include "uci.h" |
31 | #include "syzygy/tbprobe.h" |
32 | |
33 | using std::string; |
34 | |
35 | UCI::OptionsMap Options; // Global object |
36 | |
37 | namespace UCI { |
38 | |
39 | /// 'On change' actions, triggered by an option's value change |
40 | void on_clear_hash(const Option&) { Search::clear(); } |
41 | void on_hash_size(const Option& o) { TT.resize(o); } |
42 | void on_logger(const Option& o) { start_logger(o); } |
43 | void on_threads(const Option& o) { Threads.set(o); } |
44 | void on_tb_path(const Option& o) { Tablebases::init(o); } |
45 | |
46 | |
47 | /// Our case insensitive less() function as required by UCI protocol |
48 | bool CaseInsensitiveLess::operator() (const string& s1, const string& s2) const { |
49 | |
50 | return std::lexicographical_compare(s1.begin(), s1.end(), s2.begin(), s2.end(), |
51 | [](char c1, char c2) { return tolower(c1) < tolower(c2); }); |
52 | } |
53 | |
54 | |
55 | /// init() initializes the UCI options to their hard-coded default values |
56 | |
57 | void init(OptionsMap& o) { |
58 | |
59 | // at most 2^32 clusters. |
60 | constexpr int MaxHashMB = Is64Bit ? 131072 : 2048; |
61 | |
62 | o["Debug Log File" ] << Option("" , on_logger); |
63 | o["Contempt" ] << Option(24, -100, 100); |
64 | o["Analysis Contempt" ] << Option("Both var Off var White var Black var Both" , "Both" ); |
65 | o["Threads" ] << Option(1, 1, 512, on_threads); |
66 | o["Hash" ] << Option(16, 1, MaxHashMB, on_hash_size); |
67 | o["Clear Hash" ] << Option(on_clear_hash); |
68 | o["Ponder" ] << Option(false); |
69 | o["MultiPV" ] << Option(1, 1, 500); |
70 | o["Skill Level" ] << Option(20, 0, 20); |
71 | o["Move Overhead" ] << Option(30, 0, 5000); |
72 | o["Minimum Thinking Time" ] << Option(20, 0, 5000); |
73 | o["Slow Mover" ] << Option(84, 10, 1000); |
74 | o["nodestime" ] << Option(0, 0, 10000); |
75 | o["UCI_Chess960" ] << Option(false); |
76 | o["UCI_AnalyseMode" ] << Option(false); |
77 | o["UCI_LimitStrength" ] << Option(false); |
78 | o["UCI_Elo" ] << Option(1350, 1350, 2850); |
79 | o["SyzygyPath" ] << Option("<empty>" , on_tb_path); |
80 | o["SyzygyProbeDepth" ] << Option(1, 1, 100); |
81 | o["Syzygy50MoveRule" ] << Option(true); |
82 | o["SyzygyProbeLimit" ] << Option(7, 0, 7); |
83 | } |
84 | |
85 | |
86 | /// operator<<() is used to print all the options default values in chronological |
87 | /// insertion order (the idx field) and in the format defined by the UCI protocol. |
88 | |
89 | std::ostream& operator<<(std::ostream& os, const OptionsMap& om) { |
90 | |
91 | for (size_t idx = 0; idx < om.size(); ++idx) |
92 | for (const auto& it : om) |
93 | if (it.second.idx == idx) |
94 | { |
95 | const Option& o = it.second; |
96 | os << "\noption name " << it.first << " type " << o.type; |
97 | |
98 | if (o.type == "string" || o.type == "check" || o.type == "combo" ) |
99 | os << " default " << o.defaultValue; |
100 | |
101 | if (o.type == "spin" ) |
102 | os << " default " << int(stof(o.defaultValue)) |
103 | << " min " << o.min |
104 | << " max " << o.max; |
105 | |
106 | break; |
107 | } |
108 | |
109 | return os; |
110 | } |
111 | |
112 | |
113 | /// Option class constructors and conversion operators |
114 | |
115 | Option::Option(const char* v, OnChange f) : type("string" ), min(0), max(0), on_change(f) |
116 | { defaultValue = currentValue = v; } |
117 | |
118 | Option::Option(bool v, OnChange f) : type("check" ), min(0), max(0), on_change(f) |
119 | { defaultValue = currentValue = (v ? "true" : "false" ); } |
120 | |
121 | Option::Option(OnChange f) : type("button" ), min(0), max(0), on_change(f) |
122 | {} |
123 | |
124 | Option::Option(double v, int minv, int maxv, OnChange f) : type("spin" ), min(minv), max(maxv), on_change(f) |
125 | { defaultValue = currentValue = std::to_string(v); } |
126 | |
127 | Option::Option(const char* v, const char* cur, OnChange f) : type("combo" ), min(0), max(0), on_change(f) |
128 | { defaultValue = v; currentValue = cur; } |
129 | |
130 | Option::operator double() const { |
131 | assert(type == "check" || type == "spin" ); |
132 | return (type == "spin" ? stof(currentValue) : currentValue == "true" ); |
133 | } |
134 | |
135 | Option::operator std::string() const { |
136 | assert(type == "string" ); |
137 | return currentValue; |
138 | } |
139 | |
140 | bool Option::operator==(const char* s) const { |
141 | assert(type == "combo" ); |
142 | return !CaseInsensitiveLess()(currentValue, s) |
143 | && !CaseInsensitiveLess()(s, currentValue); |
144 | } |
145 | |
146 | |
147 | /// operator<<() inits options and assigns idx in the correct printing order |
148 | |
149 | void Option::operator<<(const Option& o) { |
150 | |
151 | static size_t insert_order = 0; |
152 | |
153 | *this = o; |
154 | idx = insert_order++; |
155 | } |
156 | |
157 | |
158 | /// operator=() updates currentValue and triggers on_change() action. It's up to |
159 | /// the GUI to check for option's limits, but we could receive the new value |
160 | /// from the user by console window, so let's check the bounds anyway. |
161 | |
162 | Option& Option::operator=(const string& v) { |
163 | |
164 | assert(!type.empty()); |
165 | |
166 | if ( (type != "button" && v.empty()) |
167 | || (type == "check" && v != "true" && v != "false" ) |
168 | || (type == "spin" && (stof(v) < min || stof(v) > max))) |
169 | return *this; |
170 | |
171 | if (type == "combo" ) |
172 | { |
173 | OptionsMap comboMap; // To have case insensitive compare |
174 | string token; |
175 | std::istringstream ss(defaultValue); |
176 | while (ss >> token) |
177 | comboMap[token] << Option(); |
178 | if (!comboMap.count(v) || v == "var" ) |
179 | return *this; |
180 | } |
181 | |
182 | if (type != "button" ) |
183 | currentValue = v; |
184 | |
185 | if (on_change) |
186 | on_change(*this); |
187 | |
188 | return *this; |
189 | } |
190 | |
191 | } // namespace UCI |
192 | |