Skip to content

Commit 9e1af25

Browse files
authored
Contempt v2 (#27)
Added contempt and armageddon settings back after they were temporarily removed earlier in the development cycle for v0.9. Binaries and official release of 0.9 are following shortly. * Added a version of contempt and armageddon which should be similar to the v0.8 versions * Added UCI_ShowWDL setting and updated version number Bench 811188
1 parent 2e5414b commit 9e1af25

File tree

7 files changed

+129
-85
lines changed

7 files changed

+129
-85
lines changed

src/general/settings.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
namespace settings {
3434

3535
const std::string engine_name = "Winter";
36-
const std::string engine_version = "0.8.16";
36+
const std::string engine_version = "0.9";
3737
const std::string engine_author = "Jonathan Rosenthal";
3838

3939
#if defined(__BMI2__)

src/general/types.h

Lines changed: 3 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -184,37 +184,9 @@ inline float score_to_wpct(WDLScore score) {
184184
return score.to_wpct();
185185
}
186186

187-
//// TODO remove this abomination once rest of code is ready.
188-
//inline WDLScore score_to_wdl_estimate(Score score) {
189-
// return WDLScore::from_score(score);
190-
//// return WDLScore((score + kRescale) / 2);
191-
// //float wpct = score_to_wpct(score);
192-
// //return WDLScore(wpct, wpct);
193-
//}
194-
195-
//inline NScore wpct_to_cp(float wpct) {
196-
// constexpr float kEpsilon = 0.000001;
197-
// wpct = std::max(std::min(wpct, 1-kEpsilon), kEpsilon);
198-
// return std::round(std::log(wpct / (1-wpct)) * 1024);
199-
//}
200-
201-
// Rounds score to next valid score
202-
//inline Score get_valid_score(Score score) {
203-
// if (!is_valid_score(score) || score == kNoScore) {
204-
// if (score < kMinScore) {
205-
// return kMinScore;
206-
// }
207-
// if (score < kMinStaticEval) {
208-
// return kMinStaticEval;
209-
// }
210-
// if (score > kMaxScore) {
211-
// return kMaxScore;
212-
// }
213-
// assert(score > kMaxStaticEval);
214-
// return kMaxStaticEval;
215-
// }
216-
// return score;
217-
//}
187+
inline Color other_color(Color color) {
188+
return color ^ 0x1;
189+
}
218190

219191
constexpr int kLowerBound = 1;
220192
constexpr int kUpperBound = 2;

src/net_evaluation.cc

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ using Filter = Array2d<NetLayerType, 3, 3>;
3131
using DeconvFilter = Array2d<NetLayerType, 3, 3>;
3232

3333
//using CReLULayerType = Vec<float, act_block_size>;
34-
std::array<float, 2> contempt = { 0.5, 0.5 };
34+
std::array<int32_t, 2> contempt = { 0, 0 };
3535

3636
struct CNNHelper {
3737
std::vector<Square> our_p;
@@ -803,7 +803,7 @@ NetLayerType NetForward(CNNLayerType &cnn_layer_one, const CNNHelper &helper) {
803803
return out;
804804
}
805805

806-
Score NetForward(NetLayerType &layer_one, float c = 0.5) {
806+
Score NetForward(NetLayerType &layer_one) {
807807
layer_one += bias_layer_one;
808808
layer_one.relu();
809809

@@ -845,7 +845,10 @@ Score ScoreBoard(const Board &board) {
845845
layer_one = ScoreBoard<NetLayerType, kBlack>(board, ec);
846846
}
847847
layer_one += cnn_out;
848-
return NetForward(layer_one, contempt[board.get_turn()]);
848+
if (contempt[board.get_turn()] != 0) {
849+
return AddContempt(NetForward(layer_one), board.get_turn());
850+
}
851+
return NetForward(layer_one);
849852
}
850853

851854
template<size_t size>
@@ -1325,4 +1328,47 @@ void EstimateFeatureImpact() {
13251328
}
13261329
#endif
13271330

1331+
void SetContempt(Color color, int32_t value) {
1332+
contempt[color] = value;
1333+
contempt[other_color(color)] = -value;
1334+
if (value == 0) {
1335+
contempt[other_color(color)] = 0;
1336+
}
1337+
}
1338+
1339+
std::array<Score, 2> GetDrawArray() {
1340+
if (contempt[kWhite] == 0) {
1341+
return std::array<Score, 2> { kDrawScore, kDrawScore };
1342+
}
1343+
return std::array<Score, 2> { AddContempt(kDrawScore, kWhite), AddContempt(kDrawScore, kBlack) };
1344+
}
1345+
1346+
Score AddContempt(Score score, Color color) {
1347+
assert(score.is_static_eval());
1348+
int32_t diff = score.win_draw - score.win;
1349+
if (contempt[color] > 0) { // Contempt is positive, draws are counted as losses
1350+
diff = (diff * contempt[color]) / 100;
1351+
return WDLScore { score.win, score.win_draw - diff };
1352+
}
1353+
// contempt is negative, draws are counted as wins
1354+
diff = -(diff * contempt[color]) / 100;
1355+
return WDLScore { score.win + diff, score.win_draw};
1356+
}
1357+
1358+
Score RemoveContempt(Score score, Color color) {
1359+
if (!score.is_static_eval() || contempt[color] == 0
1360+
|| contempt[color] >= 100 || contempt[color] <= -100) {
1361+
return score;
1362+
}
1363+
int32_t diff = score.win_draw - score.win;
1364+
if (contempt[color] >= 0) {
1365+
int32_t orig_diff = (diff * 100) / (100 - contempt[color]);
1366+
diff = orig_diff - diff;
1367+
return WDLScore { score.win, score.win_draw + diff };
1368+
}
1369+
int32_t orig_diff = (diff * 100) / (100 + contempt[color]);
1370+
diff = orig_diff - diff;
1371+
return WDLScore { score.win - diff, score.win_draw };
1372+
}
1373+
13281374
}

src/net_evaluation.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,11 @@ void GenerateDatasetFromUCIGames(std::string filename, std::string out_name = "e
5252
size_t reroll_pct = 0);
5353
#endif
5454

55+
void SetContempt(Color color, int32_t value);
56+
std::array<Score, 2> GetDrawArray();
57+
58+
Score AddContempt(Score score, Color color);
59+
Score RemoveContempt(Score score, Color color);
5560
}
5661

5762
// TODO: Move to external file
@@ -112,5 +117,4 @@ constexpr size_t kChannelsPerSide = kChanKingsIdx + 1;
112117
constexpr size_t kNumChannels = 2 * kChannelsPerSide;
113118
}
114119

115-
116120
#endif /* NET_EVALUATION_H_ */

src/search.cc

Lines changed: 34 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,9 @@ int kNodeCountSampleAt = 1000;
6262
const int kMaxDepthSampled = 32;
6363
#endif
6464

65-
int contempt = 0;
65+
int32_t contempt = 0;
6666
bool armageddon = false;
67+
std::array<Score, 2> draw_score { kDrawScore, kDrawScore };
6768

6869
int rsearch_mode;
6970
Milliseconds rsearch_duration;
@@ -142,6 +143,7 @@ const Depth kLMPBaseNW = 3, kLMPBasePV = 5;
142143
const int32_t kLMPScalar = 12, kLMPQuad = 4;
143144
const Array2d<Depth, 2, 6> kLMP = init_lmp_breakpoints(kLMPBaseNW, kLMPBasePV, kLMPScalar, kLMPQuad);
144145
#endif
146+
bool uci_show_wdl = true;
145147

146148
// Parameters used to initialize the LMR reduction table
147149
LMRInitializer lmr_initializer {
@@ -599,7 +601,7 @@ Score QuiescentSearch(Thread &t, Score alpha, const Score beta) {
599601

600602
//End search immediately if trivial draw is reached
601603
if (t.board.IsTriviallyDrawnEnding()) {
602-
return kDrawScore;
604+
return draw_score[t.board.get_turn()];
603605
}
604606

605607
//TT probe
@@ -771,12 +773,14 @@ void update_counter_move_history(Thread &t, const std::vector<Move> &quiets, con
771773
}
772774

773775
inline const Score get_singular_beta(Score beta, Depth depth) {
774-
//return beta - 4*depth;
775776
WDLScore result = WDLScore{beta.win - 2*depth, beta.win_draw - 2*depth};
776777
if (result.win < 0) {
777778
result.win_draw += result.win;
778779
result.win = 0;
779780
}
781+
if (result.win_draw < 0) {
782+
result.win_draw = 0;
783+
}
780784
return result;
781785
}
782786

@@ -789,15 +793,14 @@ Score AlphaBeta(Thread &t, Score alpha, const Score beta, Depth depth, bool expe
789793
assert(node_type != NodeType::kPV || !expected_cut_node);
790794

791795
const Score original_alpha = alpha;
792-
// Score lower_bound_score = kMinScore+t.board.get_num_made_moves();
793796

794797
//Immediately return 0 if we detect a draw.
795798
if (t.board.IsDraw() || (settings::kRepsForDraw == 3 && t.board.CountRepetitions(min_ply) >= 2)) {
796799
t.nodes++;
797800
if (t.board.IsFiftyMoveDraw() && t.board.InCheck() && t.board.GetMoves<kNonQuiescent>().empty()) {
798801
return GetMatedOnMoveScore(t.board.get_num_made_moves());
799802
}
800-
return kDrawScore;
803+
return draw_score[t.board.get_turn()];
801804
}
802805

803806
//We drop to QSearch if we run out of depth.
@@ -807,10 +810,6 @@ Score AlphaBeta(Thread &t, Score alpha, const Score beta, Depth depth, bool expe
807810
return net_evaluation::ScoreBoard(t.board);
808811
}
809812
return QuiescentSearch<Mode>(t, alpha, beta);
810-
// t.board.Print();
811-
// Score score = QuiescentSearch<Mode>(t, alpha, beta);
812-
// std::cout << "AB QSearch return: (w:" << score.win << ", wd:" << score.win_draw << ")" << std::endl;
813-
// return score;
814813
}
815814

816815
// To avoid counting nodes twice if all we do is fall through to QSearch,
@@ -890,7 +889,7 @@ Score AlphaBeta(Thread &t, Score alpha, const Score beta, Depth depth, bool expe
890889
if (in_check) {
891890
return GetMatedOnMoveScore(t.board.get_num_made_moves());
892891
}
893-
return kDrawScore;
892+
return draw_score[t.board.get_turn()];
894893
}
895894

896895
// if (Mode == kSamplingSearchMode && node_type == NodeType::kNW && depth <= kMaxDepthSampled) {
@@ -1096,11 +1095,11 @@ Score RootSearchLoop(Thread &t, Score original_alpha, const Score beta,
10961095
Score alpha = original_alpha;
10971096
Score lower_bound_score = kMinScore;
10981097
//const bool in_check = board.InCheck();
1099-
if (settings::kRepsForDraw == 3 && alpha < kDrawScore.get_previous_score() && t.board.MoveInListCanRepeat(moves)) {
1100-
if (beta <= kDrawScore) {
1101-
return kDrawScore;
1098+
if (settings::kRepsForDraw == 3 && alpha < draw_score[t.board.get_turn()].get_previous_score() && t.board.MoveInListCanRepeat(moves)) {
1099+
if (beta <= draw_score[t.board.get_turn()]) {
1100+
return draw_score[t.board.get_turn()];
11021101
}
1103-
alpha = kDrawScore.get_previous_score();
1102+
alpha = draw_score[t.board.get_turn()].get_previous_score();
11041103
}
11051104
const bool in_check = t.board.InCheck();
11061105
for (size_t i = 0; i < moves.size(); ++i) {
@@ -1109,8 +1108,8 @@ Score RootSearchLoop(Thread &t, Score original_alpha, const Score beta,
11091108
if (i == 0) {
11101109
Score score = -AlphaBeta<NodeType::kPV, Mode>(t, -beta, -alpha, current_depth - 1);
11111110
assert(score.is_valid());
1112-
if (settings::kRepsForDraw == 3 && score < kDrawScore && t.board.CountRepetitions() >= 2) {
1113-
score = kDrawScore;
1111+
if (settings::kRepsForDraw == 3 && score < draw_score[t.board.get_turn()] && t.board.CountRepetitions() >= 2) {
1112+
score = draw_score[t.board.get_turn()];
11141113
}
11151114
t.board.UnMake();
11161115
if (score >= beta) {
@@ -1133,8 +1132,8 @@ Score RootSearchLoop(Thread &t, Score original_alpha, const Score beta,
11331132
if (score > alpha) {
11341133
score = -AlphaBeta<NodeType::kPV, Mode>(t, -beta, -alpha, current_depth - 1);
11351134
}
1136-
if (settings::kRepsForDraw == 3 && score < kDrawScore && t.board.CountRepetitions() >= 2) {
1137-
score = kDrawScore;
1135+
if (settings::kRepsForDraw == 3 && score < draw_score[t.board.get_turn()] && t.board.CountRepetitions() >= 2) {
1136+
score = draw_score[t.board.get_turn()];
11381137
}
11391138
lower_bound_score = std::max(score, lower_bound_score);
11401139
t.board.UnMake();
@@ -1227,15 +1226,10 @@ void PrintUCIInfoString(Thread &t, const Depth depth, const Time &begin,
12271226

12281227
if (!score.is_mate_score()) {
12291228
std::cout << " score cp ";
1230-
if (armageddon) {
1231-
// TODO change this to reflect armageddon odds.
1232-
std::cout << (score.to_cp() / 8);
1233-
}
1234-
else {
1235-
std::cout << (score.to_cp() / 8);
1229+
std::cout << (net_evaluation::RemoveContempt(score, t.board.get_turn()).to_cp() / 8);
1230+
if (uci_show_wdl) {
1231+
std::cout << " " << net_evaluation::RemoveContempt(score, t.board.get_turn()).get_uci_string();
12361232
}
1237-
std::cout << " " << score.get_uci_string();
1238-
12391233
}
12401234
else {
12411235
if (score.is_disadvantage()) {
@@ -1338,14 +1332,14 @@ void Thread::search() {
13381332
template<int Mode>
13391333
Move RootSearch(Board &board, Depth depth, Milliseconds duration = Milliseconds(24 * 60 * 60 * 1000)) {
13401334
table::UpdateGeneration();
1341-
// TODO fix contempt and armageddon.
1342-
// if (armageddon) {
1343-
// net_evaluation::SetContempt(60, kWhite);
1344-
// }
1345-
// else {
1346-
// net_evaluation::SetContempt(contempt, board.get_turn());
1347-
// }
1348-
// draw_score = net_evaluation::GetDrawArray();
1335+
if (armageddon) {
1336+
net_evaluation::SetContempt(kWhite, 60);
1337+
}
1338+
else {
1339+
net_evaluation::SetContempt(board.get_turn(), contempt);
1340+
}
1341+
draw_score = net_evaluation::GetDrawArray();
1342+
assert(armageddon || contempt != 0 || draw_score[kWhite] == kDrawScore);
13491343
min_ply = board.get_num_made_moves();
13501344
Threads.reset_node_count();
13511345
Threads.reset_depths();
@@ -2129,14 +2123,18 @@ std::vector<Board> GenerateEvalSampleSet(std::string filename) {
21292123
return boards;
21302124
}
21312125

2132-
void SetContempt(int contempt_) {
2133-
contempt = (contempt_ + 100) / 2;
2126+
void SetContempt(int32_t contempt_) {
2127+
contempt = contempt_;
21342128
}
21352129

21362130
void SetArmageddon(bool armageddon_) {
21372131
armageddon = armageddon_;
21382132
}
21392133

2134+
void SetUCIShowWDL(bool show_wdl) {
2135+
uci_show_wdl = show_wdl;
2136+
}
2137+
21402138
#ifdef TUNE
21412139
void SetInitialAspirationDelta(int32_t delta) {
21422140
kInitialAspirationDelta = delta;

src/search.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,9 @@ void LoadSearchVariablesHardCoded();
6868
void EvaluateCaptureMoveValue(int n);
6969
void EvaluateScoreDistributions(const int focus);
7070

71-
void SetContempt(int contempt);
7271
void SetArmageddon(bool armageddon);
72+
void SetContempt(int32_t contempt);
73+
void SetUCIShowWDL(bool show_wdl);
7374

7475
#ifdef TUNE
7576
void SetInitialAspirationDelta(int32_t delta);

0 commit comments

Comments
 (0)