Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
official-stockfish
GitHub Repository: official-stockfish/Stockfish
Path: blob/master/src/ucioption.cpp
376 views
1
/*
2
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
3
Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
4
5
Stockfish 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
Stockfish 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
#include "ucioption.h"
20
21
#include <algorithm>
22
#include <cassert>
23
#include <cctype>
24
#include <cstdlib>
25
#include <iostream>
26
#include <sstream>
27
#include <utility>
28
29
#include "misc.h"
30
31
namespace Stockfish {
32
33
bool CaseInsensitiveLess::operator()(const std::string& s1, const std::string& s2) const {
34
35
return std::lexicographical_compare(
36
s1.begin(), s1.end(), s2.begin(), s2.end(),
37
[](char c1, char c2) { return std::tolower(c1) < std::tolower(c2); });
38
}
39
40
void OptionsMap::add_info_listener(InfoListener&& message_func) { info = std::move(message_func); }
41
42
void OptionsMap::setoption(std::istringstream& is) {
43
std::string token, name, value;
44
45
is >> token; // Consume the "name" token
46
47
// Read the option name (can contain spaces)
48
while (is >> token && token != "value")
49
name += (name.empty() ? "" : " ") + token;
50
51
// Read the option value (can contain spaces)
52
while (is >> token)
53
value += (value.empty() ? "" : " ") + token;
54
55
if (options_map.count(name))
56
options_map[name] = value;
57
else
58
sync_cout << "No such option: " << name << sync_endl;
59
}
60
61
const Option& OptionsMap::operator[](const std::string& name) const {
62
auto it = options_map.find(name);
63
assert(it != options_map.end());
64
return it->second;
65
}
66
67
// Inits options and assigns idx in the correct printing order
68
void OptionsMap::add(const std::string& name, const Option& option) {
69
if (!options_map.count(name))
70
{
71
static size_t insert_order = 0;
72
73
options_map[name] = option;
74
75
options_map[name].parent = this;
76
options_map[name].idx = insert_order++;
77
}
78
else
79
{
80
std::cerr << "Option \"" << name << "\" was already added!" << std::endl;
81
std::exit(EXIT_FAILURE);
82
}
83
}
84
85
86
std::size_t OptionsMap::count(const std::string& name) const { return options_map.count(name); }
87
88
Option::Option(const OptionsMap* map) :
89
parent(map) {}
90
91
Option::Option(const char* v, OnChange f) :
92
type("string"),
93
min(0),
94
max(0),
95
on_change(std::move(f)) {
96
defaultValue = currentValue = v;
97
}
98
99
Option::Option(bool v, OnChange f) :
100
type("check"),
101
min(0),
102
max(0),
103
on_change(std::move(f)) {
104
defaultValue = currentValue = (v ? "true" : "false");
105
}
106
107
Option::Option(OnChange f) :
108
type("button"),
109
min(0),
110
max(0),
111
on_change(std::move(f)) {}
112
113
Option::Option(int v, int minv, int maxv, OnChange f) :
114
type("spin"),
115
min(minv),
116
max(maxv),
117
on_change(std::move(f)) {
118
defaultValue = currentValue = std::to_string(v);
119
}
120
121
Option::Option(const char* v, const char* cur, OnChange f) :
122
type("combo"),
123
min(0),
124
max(0),
125
on_change(std::move(f)) {
126
defaultValue = v;
127
currentValue = cur;
128
}
129
130
Option::operator int() const {
131
assert(type == "check" || type == "spin");
132
return (type == "spin" ? std::stoi(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) && !CaseInsensitiveLess()(s, currentValue);
143
}
144
145
bool Option::operator!=(const char* s) const { return !(*this == s); }
146
147
148
// Updates currentValue and triggers on_change() action. It's up to
149
// the GUI to check for option's limits, but we could receive the new value
150
// from the user by console window, so let's check the bounds anyway.
151
Option& Option::operator=(const std::string& v) {
152
153
assert(!type.empty());
154
155
if ((type != "button" && type != "string" && v.empty())
156
|| (type == "check" && v != "true" && v != "false")
157
|| (type == "spin" && (std::stoi(v) < min || std::stoi(v) > max)))
158
return *this;
159
160
if (type == "combo")
161
{
162
OptionsMap comboMap; // To have case insensitive compare
163
std::string token;
164
std::istringstream ss(defaultValue);
165
while (ss >> token)
166
comboMap.add(token, Option());
167
if (!comboMap.count(v) || v == "var")
168
return *this;
169
}
170
171
if (type == "string")
172
currentValue = v == "<empty>" ? "" : v;
173
else if (type != "button")
174
currentValue = v;
175
176
if (on_change)
177
{
178
const auto ret = on_change(*this);
179
180
if (ret && parent != nullptr && parent->info != nullptr)
181
parent->info(ret);
182
}
183
184
return *this;
185
}
186
187
std::ostream& operator<<(std::ostream& os, const OptionsMap& om) {
188
for (size_t idx = 0; idx < om.options_map.size(); ++idx)
189
for (const auto& it : om.options_map)
190
if (it.second.idx == idx)
191
{
192
const Option& o = it.second;
193
os << "\noption name " << it.first << " type " << o.type;
194
195
if (o.type == "check" || o.type == "combo")
196
os << " default " << o.defaultValue;
197
198
else if (o.type == "string")
199
{
200
std::string defaultValue = o.defaultValue.empty() ? "<empty>" : o.defaultValue;
201
os << " default " << defaultValue;
202
}
203
204
else if (o.type == "spin")
205
os << " default " << stoi(o.defaultValue) << " min " << o.min << " max "
206
<< o.max;
207
208
break;
209
}
210
211
return os;
212
}
213
}
214
215