mirror of
https://github.com/opelly27/Stockfish.git
synced 2026-05-20 13:17:44 +00:00
a08b8d4e97
The old parameterization (https://github.com/official-stockfish/Stockfish/pull/2225/files) has now become quite inaccurate. This updates the formula based on updated results with master. The formula is based on a fit of the Elo results for games played between master at various skill levels, and various versions of the Stash engine, which have been ranked at CCRL. ``` # PLAYER : RATING ERROR POINTS PLAYED (%) 1 master-skill-19 : 3191.1 40.4 940.0 1707 55 2 master-skill-18 : 3170.3 39.3 1343.0 2519 53 3 master-skill-17 : 3141.3 37.8 2282.0 4422 52 4 master-skill-16 : 3111.2 37.1 2773.0 5423 51 5 master-skill-15 : 3069.5 37.2 2728.5 5386 51 6 master-skill-14 : 3024.8 36.1 2702.0 5339 51 7 master-skill-13 : 2972.9 35.4 2645.5 5263 50 8 master-skill-12 : 2923.1 35.0 2653.5 5165 51 9 master-skill-11 : 2855.5 33.6 2524.0 5081 50 10 master-skill-10 : 2788.3 32.0 2724.5 5511 49 11 stash-bot-v25.0 : 2744.0 31.5 1952.5 3840 51 12 master-skill-9 : 2702.8 30.5 2670.0 5018 53 13 master-skill-8 : 2596.2 28.5 2669.5 4975 54 14 stash-bot-v21.0 : 2561.2 30.0 1338.0 3366 40 15 master-skill-7 : 2499.5 28.5 1934.0 4178 46 16 stash-bot-v20.0 : 2452.6 27.7 1606.5 3378 48 17 stash-bot-v19.0 : 2425.3 26.7 1787.0 3365 53 18 master-skill-6 : 2363.2 26.4 2510.5 4379 57 19 stash-bot-v17.0 : 2280.7 25.4 2209.0 4378 50 20 master-skill-5 : 2203.7 25.3 2859.5 5422 53 21 stash-bot-v15.3 : 2200.0 25.4 1757.0 4383 40 22 stash-bot-v14 : 2145.9 25.5 2890.0 5167 56 23 stash-bot-v13 : 2042.7 25.8 2263.5 4363 52 24 stash-bot-v12 : 1963.4 25.8 1769.5 4210 42 25 master-skill-4 : 1922.9 25.9 2690.0 5399 50 26 stash-bot-v11 : 1873.0 26.3 2203.5 4335 51 27 stash-bot-v10 : 1783.8 27.8 2568.5 4301 60 28 master-skill-3 : 1742.3 27.8 1909.5 4439 43 29 master-skill-2 : 1608.4 29.4 2064.5 4389 47 30 stash-bot-v9 : 1582.6 30.2 2130.0 4230 50 31 master-skill-1 : 1467.6 31.3 2015.5 4244 47 32 stash-bot-v8 : 1452.8 31.5 1953.5 3780 52 33 master-skill-0 : 1320.1 32.9 651.5 2083 31 ``` Skill 0 .. 19, now covers CCRL Blitz Elo from 1320 to 3190, approximately. Indeed, the Elo of stash in this analysis is only to within +- 100 Elo of CCRL, probably because it depends quite a bit on the opponent pool. To obtain a skill level for a given Elo number, the above data is fit as a 3rd degree polynomial Skill(Elo). A quick test confirms the correspondence to the above table: ``` Score of master-elo-2721 vs stash-bot-v21.0: 51 - 16 - 19 [0.703] 86 Elo difference: 150.1 +/- 70.2, LOS: 100.0 %, DrawRatio: 22.1 % ``` closes https://github.com/official-stockfish/Stockfish/pull/4341 No functional change.
195 lines
6.2 KiB
C++
195 lines
6.2 KiB
C++
/*
|
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
|
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file)
|
|
|
|
Stockfish is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
Stockfish is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include <algorithm>
|
|
#include <cassert>
|
|
#include <ostream>
|
|
#include <sstream>
|
|
|
|
#include "evaluate.h"
|
|
#include "misc.h"
|
|
#include "search.h"
|
|
#include "thread.h"
|
|
#include "tt.h"
|
|
#include "uci.h"
|
|
#include "syzygy/tbprobe.h"
|
|
|
|
using std::string;
|
|
|
|
namespace Stockfish {
|
|
|
|
UCI::OptionsMap Options; // Global object
|
|
|
|
namespace UCI {
|
|
|
|
/// 'On change' actions, triggered by an option's value change
|
|
static void on_clear_hash(const Option&) { Search::clear(); }
|
|
static void on_hash_size(const Option& o) { TT.resize(size_t(o)); }
|
|
static void on_logger(const Option& o) { start_logger(o); }
|
|
static void on_threads(const Option& o) { Threads.set(size_t(o)); }
|
|
static void on_tb_path(const Option& o) { Tablebases::init(o); }
|
|
static void on_use_NNUE(const Option&) { Eval::NNUE::init(); }
|
|
static void on_eval_file(const Option&) { Eval::NNUE::init(); }
|
|
|
|
/// Our case insensitive less() function as required by UCI protocol
|
|
bool CaseInsensitiveLess::operator() (const string& s1, const string& s2) const {
|
|
|
|
return std::lexicographical_compare(s1.begin(), s1.end(), s2.begin(), s2.end(),
|
|
[](char c1, char c2) { return tolower(c1) < tolower(c2); });
|
|
}
|
|
|
|
|
|
/// UCI::init() initializes the UCI options to their hard-coded default values
|
|
|
|
void init(OptionsMap& o) {
|
|
|
|
constexpr int MaxHashMB = Is64Bit ? 33554432 : 2048;
|
|
|
|
o["Debug Log File"] << Option("", on_logger);
|
|
o["Threads"] << Option(1, 1, 1024, on_threads);
|
|
o["Hash"] << Option(16, 1, MaxHashMB, on_hash_size);
|
|
o["Clear Hash"] << Option(on_clear_hash);
|
|
o["Ponder"] << Option(false);
|
|
o["MultiPV"] << Option(1, 1, 500);
|
|
o["Skill Level"] << Option(20, 0, 20);
|
|
o["Move Overhead"] << Option(10, 0, 5000);
|
|
o["Slow Mover"] << Option(100, 10, 1000);
|
|
o["nodestime"] << Option(0, 0, 10000);
|
|
o["UCI_Chess960"] << Option(false);
|
|
o["UCI_AnalyseMode"] << Option(false);
|
|
o["UCI_LimitStrength"] << Option(false);
|
|
o["UCI_Elo"] << Option(1320, 1320, 3190);
|
|
o["UCI_ShowWDL"] << Option(false);
|
|
o["SyzygyPath"] << Option("<empty>", on_tb_path);
|
|
o["SyzygyProbeDepth"] << Option(1, 1, 100);
|
|
o["Syzygy50MoveRule"] << Option(true);
|
|
o["SyzygyProbeLimit"] << Option(7, 0, 7);
|
|
o["Use NNUE"] << Option(true, on_use_NNUE);
|
|
o["EvalFile"] << Option(EvalFileDefaultName, on_eval_file);
|
|
}
|
|
|
|
|
|
/// operator<<() is used to print all the options default values 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) {
|
|
|
|
for (size_t idx = 0; idx < om.size(); ++idx)
|
|
for (const auto& it : om)
|
|
if (it.second.idx == idx)
|
|
{
|
|
const Option& o = it.second;
|
|
os << "\noption name " << it.first << " type " << o.type;
|
|
|
|
if (o.type == "string" || o.type == "check" || o.type == "combo")
|
|
os << " default " << o.defaultValue;
|
|
|
|
if (o.type == "spin")
|
|
os << " default " << int(stof(o.defaultValue))
|
|
<< " min " << o.min
|
|
<< " max " << o.max;
|
|
|
|
break;
|
|
}
|
|
|
|
return os;
|
|
}
|
|
|
|
|
|
/// Option class constructors and conversion operators
|
|
|
|
Option::Option(const char* v, OnChange f) : type("string"), min(0), max(0), on_change(f)
|
|
{ defaultValue = currentValue = v; }
|
|
|
|
Option::Option(bool v, OnChange f) : type("check"), min(0), max(0), on_change(f)
|
|
{ defaultValue = currentValue = (v ? "true" : "false"); }
|
|
|
|
Option::Option(OnChange f) : type("button"), min(0), max(0), on_change(f)
|
|
{}
|
|
|
|
Option::Option(double v, int minv, int maxv, OnChange f) : type("spin"), min(minv), max(maxv), on_change(f)
|
|
{ defaultValue = currentValue = std::to_string(v); }
|
|
|
|
Option::Option(const char* v, const char* cur, OnChange f) : type("combo"), min(0), max(0), on_change(f)
|
|
{ defaultValue = v; currentValue = cur; }
|
|
|
|
Option::operator double() const {
|
|
assert(type == "check" || type == "spin");
|
|
return (type == "spin" ? stof(currentValue) : currentValue == "true");
|
|
}
|
|
|
|
Option::operator std::string() const {
|
|
assert(type == "string");
|
|
return currentValue;
|
|
}
|
|
|
|
bool Option::operator==(const char* s) const {
|
|
assert(type == "combo");
|
|
return !CaseInsensitiveLess()(currentValue, s)
|
|
&& !CaseInsensitiveLess()(s, currentValue);
|
|
}
|
|
|
|
|
|
/// operator<<() inits options and assigns idx in the correct printing order
|
|
|
|
void Option::operator<<(const Option& o) {
|
|
|
|
static size_t insert_order = 0;
|
|
|
|
*this = o;
|
|
idx = insert_order++;
|
|
}
|
|
|
|
|
|
/// operator=() updates currentValue and triggers on_change() action. It's up to
|
|
/// the GUI to check for option's limits, but we could receive the new value
|
|
/// from the user by console window, so let's check the bounds anyway.
|
|
|
|
Option& Option::operator=(const string& v) {
|
|
|
|
assert(!type.empty());
|
|
|
|
if ( (type != "button" && type != "string" && v.empty())
|
|
|| (type == "check" && v != "true" && v != "false")
|
|
|| (type == "spin" && (stof(v) < min || stof(v) > max)))
|
|
return *this;
|
|
|
|
if (type == "combo")
|
|
{
|
|
OptionsMap comboMap; // To have case insensitive compare
|
|
string token;
|
|
std::istringstream ss(defaultValue);
|
|
while (ss >> token)
|
|
comboMap[token] << Option();
|
|
if (!comboMap.count(v) || v == "var")
|
|
return *this;
|
|
}
|
|
|
|
if (type != "button")
|
|
currentValue = v;
|
|
|
|
if (on_change)
|
|
on_change(*this);
|
|
|
|
return *this;
|
|
}
|
|
|
|
} // namespace UCI
|
|
|
|
} // namespace Stockfish
|