Add endgame configuration stats

This commit is contained in:
Tomasz Sobczyk
2021-05-19 13:48:02 +02:00
parent d664ae123f
commit f89f8bd8ee
+146 -2
View File
@@ -59,9 +59,23 @@ namespace Stockfish::Tools::Stats
[[nodiscard]] std::string left_pad_to_length(const std::string& str, char ch, int length) [[nodiscard]] std::string left_pad_to_length(const std::string& str, char ch, int length)
{ {
if (str.size() < length) const int str_size = static_cast<int>(str.size());
if (str_size < length)
{ {
return std::string(length - static_cast<int>(str.size()), ch) + str; return std::string(length - str_size, ch) + str;
}
else
{
return str;
}
}
[[nodiscard]] std::string right_pad_to_length(const std::string& str, char ch, int length)
{
const int str_size = static_cast<int>(str.size());
if (str_size < length)
{
return str + std::string(length - str_size, ch);
} }
else else
{ {
@@ -940,6 +954,134 @@ namespace Stockfish::Tools::Stats
std::uint64_t m_stm_loses; std::uint64_t m_stm_loses;
}; };
template <int MaxManCount>
struct EndgameConfigurations : StatisticGathererBase
{
static_assert(MaxManCount < 10);
static_assert(MaxManCount > 2);
static inline std::string name = std::string("EndgameConfigurations") + std::to_string(MaxManCount);
using MaterialKey = std::uint64_t;
EndgameConfigurations()
{
reset();
}
void on_entry(const Position& pos, const Move&, const PackedSfenValue&) override
{
const int piece_count = pos.count<ALL_PIECES>();
if (piece_count > MaxManCount)
{
return;
}
const auto index = get_material_key_for_position(pos);
m_counts[index] += 1;
}
void reset() override
{
m_counts.clear();
}
[[nodiscard]] const std::string& get_name() const override
{
return name;
}
[[nodiscard]] StatisticOutput get_output() const override
{
StatisticOutput out;
auto& header = out.emplace_node<StatisticOutputEntryHeader>("Distribution of endgame configurations:");
std::vector<std::pair<MaterialKey, std::uint64_t>> flattened(m_counts.begin(), m_counts.end());
std::sort(flattened.begin(), flattened.end(), [](const auto& lhs, const auto& rhs) { return lhs.second > rhs.second; });
for (auto&& [index, count] : flattened)
{
header.emplace_child<StatisticOutputEntryValue<std::uint64_t>>(
get_padded_name_by_material_key(index),
count
);
}
return out;
}
private:
// can support up to 17 pieces.
// it's basically the material string encoded as a number in base 8
// encoding is from the least significant digit to most significant
// v=1, P=2, N=3, B=4, R=5, Q=6, K=7. 0 indicates end
std::map<MaterialKey, std::uint64_t> m_counts;
[[nodiscard]] MaterialKey get_material_key_for_position(const Position& pos) const
{
MaterialKey index = 0;
std::uint64_t shift = 0;
index += 7 << shift; shift += 3;
for (int i = 0; i < pos.count<PAWN>(WHITE); ++i) { index += 2 << shift; shift += 3; }
for (int i = 0; i < pos.count<BISHOP>(WHITE); ++i) { index += 3 << shift; shift += 3; }
for (int i = 0; i < pos.count<KNIGHT>(WHITE); ++i) { index += 4 << shift; shift += 3; }
for (int i = 0; i < pos.count<ROOK>(WHITE); ++i) { index += 5 << shift; shift += 3; }
for (int i = 0; i < pos.count<QUEEN>(WHITE); ++i) { index += 6 << shift; shift += 3; }
index += 1 << shift; shift += 3;
index += 7 << shift; shift += 3;
for (int i = 0; i < pos.count<PAWN>(BLACK); ++i) { index += 2 << shift; shift += 3; }
for (int i = 0; i < pos.count<BISHOP>(BLACK); ++i) { index += 3 << shift; shift += 3; }
for (int i = 0; i < pos.count<KNIGHT>(BLACK); ++i) { index += 4 << shift; shift += 3; }
for (int i = 0; i < pos.count<ROOK>(BLACK); ++i) { index += 5 << shift; shift += 3; }
for (int i = 0; i < pos.count<QUEEN>(BLACK); ++i) { index += 6 << shift; shift += 3; }
return index;
}
[[nodiscard]] std::string get_padded_name_by_material_key(MaterialKey index) const
{
std::string sides[COLOR_NB];
Color side = WHITE;
while (index != 0)
{
switch (index % 8)
{
case 1:
side = BLACK;
break;
case 2:
sides[side] += 'P';
break;
case 3:
sides[side] += 'N';
break;
case 4:
sides[side] += 'B';
break;
case 5:
sides[side] += 'R';
break;
case 6:
sides[side] += 'Q';
break;
case 7:
sides[side] += 'K';
break;
default:
break;
}
index >>= 3;
}
return
right_pad_to_length(sides[WHITE], ' ', MaxManCount-1)
+ 'v'
+ right_pad_to_length(sides[BLACK], ' ', MaxManCount-1);
}
};
/* /*
This function provides factories for all possible statistic gatherers. This function provides factories for all possible statistic gatherers.
Each new statistic gatherer needs to be added there. Each new statistic gatherer needs to be added there.
@@ -966,6 +1108,8 @@ namespace Stockfish::Tools::Stats
reg.add<PieceCountCounter>("piece_count"); reg.add<PieceCountCounter>("piece_count");
reg.add<EndgameConfigurations<6>>("endgames_6man");
return reg; return reg;
}(); }();