io-chess
UCI chess engine
Loading...
Searching...
No Matches
WDLNormalizer.hpp
Go to the documentation of this file.
1
5#pragma once
6#include <algorithm>
7#include <cmath>
8#include <string>
9
14struct WDLOutput {
15 float win; // Probability of winning (0.0 - 1.0)
16 float draw; // Probability of draw (0.0 - 1.0)
17 float loss; // Probability of losing (0.0 - 1.0)
18};
19
28public:
29 // Lichess constant: 1 / 0.00368208 = 271.58
30 // Tuned on millions of real games
31 static constexpr float SCALE = 1.0f / 0.00368208;
32
33 // Large CP value for mate scores (for router)
34 static constexpr float MATE_CP = 15000.0f;
35
47 static WDLOutput convert(const std::string &eval_str, bool is_white_to_move) {
48 WDLOutput result;
49
50 // Check for mate scores
51 if (eval_str.find('#') != std::string::npos) {
52 result = handle_mate(eval_str);
53 } else {
54 // Handle centipawns
55 float cp = 0.0f;
56 try {
57 cp = std::stof(eval_str);
58 } catch (...) {
59 // Fallback to equal position
60 return {0.33f, 0.34f, 0.33f};
61 }
62 result = handle_centipawns(cp);
63 }
64
65 // Flip perspective for Black: swap Win <-> Loss
66 if (!is_white_to_move) {
67 std::swap(result.win, result.loss);
68 }
69
70 return result;
71 }
72
81 static float to_centipawns(const std::string &eval_str,
82 bool is_white_to_move) {
83 float cp = 0.0f;
84
85 if (eval_str.find('#') != std::string::npos) {
86 // Mate string → large CP value
87 std::string s = eval_str;
88 s.erase(std::remove(s.begin(), s.end(), '#'), s.end());
89 int moves = std::stoi(s);
90 int sign = (moves > 0) ? 1 : -1;
91 // Cap at ±15000, decay slightly with move count
92 cp = sign * (MATE_CP - std::abs(moves) * 10.0f);
93 } else {
94 try {
95 cp = std::stof(eval_str);
96 } catch (...) {
97 return 0.0f;
98 }
99 }
100
101 // Flip for Black (CSV is from White's perspective)
102 if (!is_white_to_move) {
103 cp = -cp;
104 }
105
106 return cp;
107 }
108
109private:
114 static WDLOutput handle_centipawns(float cp) {
115 // Sigmoid for win probability
116 float win_rate = 1.0f / (1.0f + std::exp(-cp / SCALE));
117
118 float w, d, l;
119
120 if (cp > 0) {
121 // Winning position
122 w = win_rate;
123 l = (1.0f - w) * 0.3f; // Small loss chance
124 d = 1.0f - w - l; // Remainder is draw
125 } else {
126 // Losing position
127 l = 1.0f - win_rate; // High loss probability
128 w = win_rate * 0.3f; // Small win chance
129 d = 1.0f - l - w; // Remainder is draw
130 }
131
132 // Clamp and normalize
133 w = std::max(0.0f, w);
134 d = std::max(0.0f, d);
135 l = std::max(0.0f, l);
136 float sum = w + d + l;
137
138 return {w / sum, d / sum, l / sum};
139 }
140
145 static WDLOutput handle_mate(std::string s) {
146 s.erase(std::remove(s.begin(), s.end(), '#'), s.end());
147 int moves = std::stoi(s);
148
149 if (moves > 0) {
150 // We mate them: Win=1.0
151 return {1.0f, 0.0f, 0.0f};
152 } else {
153 // They mate us: Loss=1.0
154 return {0.0f, 0.0f, 1.0f};
155 }
156 }
157};
Definition WDLNormalizer.hpp:27
static constexpr float SCALE
Definition WDLNormalizer.hpp:31
static constexpr float MATE_CP
Definition WDLNormalizer.hpp:34
static WDLOutput handle_centipawns(float cp)
Definition WDLNormalizer.hpp:114
static float to_centipawns(const std::string &eval_str, bool is_white_to_move)
Definition WDLNormalizer.hpp:81
static WDLOutput convert(const std::string &eval_str, bool is_white_to_move)
Definition WDLNormalizer.hpp:47
static WDLOutput handle_mate(std::string s)
Definition WDLNormalizer.hpp:145
Definition loss.py:1
Definition WDLNormalizer.hpp:14
float draw
Definition WDLNormalizer.hpp:16
float loss
Definition WDLNormalizer.hpp:17
float win
Definition WDLNormalizer.hpp:15