]> git.sesse.net Git - stockfish/blob - src/ucioption.cpp
Rewrite ucioptions.cpp to use C++
[stockfish] / src / ucioption.cpp
1 /*
2   Glaurung, a UCI chess playing engine.
3   Copyright (C) 2004-2008 Tord Romstad
4
5   Glaurung is free software: you can redistribute it and/or modify
6   it under the terms of the GNU General Public License as published by
7   the Free Software Foundation, either version 3 of the License, or
8   (at your option) any later version.
9
10   Glaurung is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   GNU General Public License for more details.
14
15   You should have received a copy of the GNU General Public License
16   along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18
19
20 ////
21 //// Includes
22 ////
23
24 #include <cassert>
25 #include <map>
26 #include <string>
27 #include <sstream>
28 #include <vector>
29
30 #include "misc.h"
31 #include "thread.h"
32 #include "ucioption.h"
33
34
35 ////
36 //// Variables
37 ////
38
39 bool Chess960 = false;
40
41
42 ////
43 //// Local definitions
44 ////
45
46 namespace {
47
48   ///
49   /// Types
50   ///
51
52   enum OptionType { SPIN, COMBO, CHECK, STRING, BUTTON, OPTION_TYPE_NONE };
53
54   typedef std::vector<std::string> ComboValues;
55
56   struct OptionValue
57   {
58     std::string defaultValue, currentValue;
59     OptionType type;
60     int minValue, maxValue;
61     ComboValues comboValues;
62
63     // Helper to convert a bool or an int in a std::string
64     template<typename T> std::string stringify(const T& v);
65
66     OptionValue(); // this is needed to use a std::map
67     OptionValue(const char* defaultValue, OptionType = STRING);
68     OptionValue(bool defaultValue);
69     OptionValue(int defaultValue, int minValue, int maxValue);
70   };
71
72   typedef std::map<std::string, OptionValue> Options;
73
74   ///
75   /// Constants
76   ///
77
78   // load-defaults populates the options map with the hard
79   // coded options names and their default values.
80   void load_defaults(Options& options) {
81
82     options["Use Search Log"]                            = OptionValue(false);
83     options["Search Log Filename"]                       = OptionValue("SearchLog.txt");
84     options["Book File"]                                 = OptionValue("book.bin");
85     options["Mobility (Middle Game)"]                    = OptionValue(100, 0, 200);
86     options["Mobility (Endgame)"]                        = OptionValue(100, 0, 200);
87     options["Pawn Structure (Middle Game)"]              = OptionValue(100, 0, 200);
88     options["Pawn Structure (Endgame)"]                  = OptionValue(100, 0, 200);
89     options["Passed Pawns (Middle Game)"]                = OptionValue(100, 0, 200);
90     options["Passed Pawns (Endgame)"]                    = OptionValue(100, 0, 200);
91     options["Aggressiveness"]                            = OptionValue(100, 0, 200);
92     options["Cowardice"]                                 = OptionValue(100, 0, 200);
93     options["King Safety Curve"]                         = OptionValue("Quadratic", COMBO);
94
95        options["King Safety Curve"].comboValues.push_back("Quadratic");
96        options["King Safety Curve"].comboValues.push_back("Linear");  /*, "From File"*/
97
98     options["King Safety Coefficient"]                   = OptionValue(40, 1, 100);
99     options["King Safety X Intercept"]                   = OptionValue(0, 0, 20);
100     options["King Safety Max Slope"]                     = OptionValue(30, 10, 100);
101     options["King Safety Max Value"]                     = OptionValue(500, 100, 1000);
102     options["Queen Contact Check Bonus"]                 = OptionValue(4, 0, 8);
103     options["Rook Contact Check Bonus"]                  = OptionValue(2, 0, 4);
104     options["Queen Check Bonus"]                         = OptionValue(2, 0, 4);
105     options["Rook Check Bonus"]                          = OptionValue(1, 0, 4);
106     options["Bishop Check Bonus"]                        = OptionValue(1, 0, 4);
107     options["Knight Check Bonus"]                        = OptionValue(1, 0, 4);
108     options["Discovered Check Bonus"]                    = OptionValue(3, 0, 8);
109     options["Mate Threat Bonus"]                         = OptionValue(3, 0, 8);
110
111     options["Check Extension (PV nodes)"]                = OptionValue(2, 0, 2);
112     options["Check Extension (non-PV nodes)"]            = OptionValue(1, 0, 2);
113     options["Single Reply Extension (PV nodes)"]         = OptionValue(2, 0, 2);
114     options["Single Reply Extension (non-PV nodes)"]     = OptionValue(2, 0, 2);
115     options["Mate Threat Extension (PV nodes)"]          = OptionValue(2, 0, 2);
116     options["Mate Threat Extension (non-PV nodes)"]      = OptionValue(0, 0, 2);
117     options["Pawn Push to 7th Extension (PV nodes)"]     = OptionValue(1, 0, 2);
118     options["Pawn Push to 7th Extension (non-PV nodes)"] = OptionValue(1, 0, 2);
119     options["Passed Pawn Extension (PV nodes)"]          = OptionValue(1, 0, 2);
120     options["Passed Pawn Extension (non-PV nodes)"]      = OptionValue(0, 0, 2);
121     options["Pawn Endgame Extension (PV nodes)"]         = OptionValue(2, 0, 2);
122     options["Pawn Endgame Extension (non-PV nodes)"]     = OptionValue(2, 0, 2);
123     options["Full Depth Moves (PV nodes)"]               = OptionValue(14, 1, 100);
124     options["Full Depth Moves (non-PV nodes)"]           = OptionValue(3, 1, 100);
125     options["Threat Depth"]                              = OptionValue(5, 0, 100);
126     options["Selective Plies"]                           = OptionValue(7, 0, 10);
127     options["Futility Pruning (Main Search)"]            = OptionValue(true);
128     options["Futility Pruning (Quiescence Search)"]      = OptionValue(true);
129     options["Futility Margin 0"]                         = OptionValue(50, 0, 1000);
130     options["Futility Margin 1"]                         = OptionValue(100, 0, 1000);
131     options["Futility Margin 2"]                         = OptionValue(300, 0, 1000);
132     options["Maximum Razoring Depth"]                    = OptionValue(3, 0, 4);
133     options["Razoring Margin"]                           = OptionValue(300, 150, 600);
134     options["Randomness"]                                = OptionValue(0, 0, 10);
135     options["Minimum Split Depth"]                       = OptionValue(4, 4, 7);
136     options["Maximum Number of Threads per Split Point"] = OptionValue(5, 4, 8);
137     options["Threads"]                                   = OptionValue(1, 1, 8);
138     options["Hash"]                                      = OptionValue(32, 4, 4096);
139     options["Clear Hash"]                                = OptionValue(false);
140     options["Ponder"]                                    = OptionValue(true);
141     options["OwnBook"]                                   = OptionValue(true);
142     options["MultiPV"]                                   = OptionValue(1, 1, 500);
143     options["UCI_ShowCurrLine"]                          = OptionValue(false);
144     options["UCI_Chess960"]                              = OptionValue(false);
145   }
146
147
148   ///
149   /// Variables
150   ///
151
152   Options options;
153
154   // Local functions
155   template<typename T> T get_option_value(const std::string& optionName);
156
157 }
158
159 ////
160 //// Functions
161 ////
162
163 /// init_uci_options() initializes the UCI options.  Currently, the only
164 /// thing this function does is to initialize the default value of the
165 /// "Threads" parameter to the number of available CPU cores.
166
167 void init_uci_options() {
168
169   load_defaults(options);
170
171   // Limit the default value of "Threads" to 7 even if we have 8 CPU cores.
172   // According to Ken Dail's tests, Glaurung plays much better with 7 than
173   // with 8 threads.  This is weird, but it is probably difficult to find out
174   // why before I have a 8-core computer to experiment with myself.
175   assert(options.find("Threads") != options.end());
176
177   options["Threads"].defaultValue = Min(cpu_count(), 7);
178   options["Threads"].currentValue = Min(cpu_count(), 7);
179
180   // Increase the minimum split depth when the number of CPUs is big.
181   // It would probably be better to let this depend on the number of threads
182   // instead.
183   if(cpu_count() > 4)
184   {
185       assert(options.find("Minimum Split Depth") != options.end());
186
187       options["Minimum Split Depth"].defaultValue = 6;
188       options["Minimum Split Depth"].currentValue = 6;
189   }
190 }
191
192
193 /// print_uci_options() prints all the UCI options to the standard output,
194 /// in the format defined by the UCI protocol.
195
196 void print_uci_options() {
197
198   static const char optionTypeName[][16] = {
199     "spin", "combo", "check", "string", "button"
200   };
201
202   for (Options::iterator it = options.begin(); it != options.end(); ++it)
203   {
204       const OptionValue& o = it->second;
205
206       std::cout << "option name " << it->first
207                 << " type "       << optionTypeName[o.type];
208
209       if (o.type != BUTTON)
210       {
211           std::cout << " default " << o.defaultValue;
212
213           if (o.type == SPIN)
214               std::cout << " min " << o.minValue
215                         << " max " << o.maxValue;
216
217           else if (o.type == COMBO)
218               for(ComboValues::size_type i = 0; i < o.comboValues.size(); ++i)
219                   std::cout << " var " << o.comboValues[i];
220       }
221       std::cout << std::endl;
222   }
223 }
224
225 /// get_option_value_bool() returns the current value of a UCI parameter of
226 /// type "check".
227
228 bool get_option_value_bool(const std::string& optionName) {
229
230   return get_option_value<bool>(optionName);
231 }
232
233
234 /// get_option_value_int() returns the value of a UCI parameter as an integer.
235 /// Normally, this function will be used for a parameter of type "spin", but
236 /// it could also be used with a "combo" parameter, where all the available
237 /// values are integers.
238
239 int get_option_value_int(const std::string& optionName) {
240
241   return get_option_value<int>(optionName);
242 }
243
244
245 /// get_option_value_string() returns the current value of a UCI parameter as
246 /// a string.  It is used with parameters of type "combo" and "string".
247
248 const std::string get_option_value_string(const std::string& optionName) {
249
250    return get_option_value<std::string>(optionName);
251 }
252
253
254 /// button_was_pressed() tests whether a UCI parameter of type "button" has
255 /// been selected since the last time the function was called.
256
257 bool button_was_pressed(const std::string& buttonName) {
258
259   if (get_option_value<bool>(buttonName))
260   {
261     set_option_value(buttonName, "false");
262     return true;
263   }
264
265   return false;
266 }
267
268
269 /// set_option_value() inserts a new value for a UCI parameter.  Note that
270 /// the function does not check that the new value is legal for the given
271 /// parameter:  This is assumed to be the responsibility of the GUI.
272
273 void set_option_value(const std::string& optionName,
274                       const std::string& newValue) {
275
276   if (options.find(optionName) != options.end())
277       options[optionName].currentValue = newValue;
278   else
279       std::cout << "No such option: " << optionName << std::endl;
280 }
281
282
283 /// push_button() is used to tell the engine that a UCI parameter of type
284 /// "button" has been selected:
285
286 void push_button(const std::string& buttonName) {
287
288   set_option_value(buttonName, "true");
289 }
290
291
292 namespace {
293
294     // methods and c'tors of OptionValue class.
295
296     template<typename T>
297     std::string OptionValue::stringify(const T& v)
298     {
299         std::ostringstream ss;
300         ss << v;
301
302         return ss.str();
303     }
304
305     OptionValue::OptionValue() {}
306
307     OptionValue::OptionValue(const char* def, OptionType t)
308     : defaultValue(def), currentValue(def), type(t), minValue(0), maxValue(0) {}
309
310     OptionValue::OptionValue(bool def)
311     : defaultValue(stringify(def)), currentValue(stringify(def)), type(CHECK), minValue(0), maxValue(0) {}
312
313     OptionValue::OptionValue(int def, int minv, int maxv)
314     : defaultValue(stringify(def)), currentValue(stringify(def)), type(SPIN), minValue(minv), maxValue(maxv) {}
315
316     // get_option_value is the implementation of the various
317     // get_option_value_<type>, because only the option value
318     // type changes a template is the proper solution.
319
320     template<typename T>
321     T get_option_value(const std::string& optionName) {
322
323         T ret;
324
325         if (options.find(optionName) != options.end())
326         {
327             std::istringstream ss(options[optionName].currentValue);
328             ss >> ret;
329         }
330         return ret;
331     }
332
333 }