Skip to content

Commit 6588eb5

Browse files
snicoletgoodkov
authored andcommitted
A better contempt implementation for Stockfish (official-stockfish#1325)
* A better contempt implementation for Stockfish The round 2 of TCEC season 10 demonstrated the benefit of having a nice contempt implementation: it gives the strongest programs in the tournament the ability to slow down the game when they feel the position is slightly worse, prefering to stay in a complicated (even if slightly risky) middle game rather than simplifying by force into a drawn endgame. The current contempt implementation of Stockfish is inadequate, and this patch is an attempt to provide a better one. Passed STC non-regression test against master: LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 83360 W: 15089 L: 15075 D: 53196 http://tests.stockfishchess.org/tests/view/5a1bf2de0ebc590ccbb8b370 This contempt implementation is showing promising results in certains situations. For instance, it obtained a nice +30 Elo gain when playing with contempt=40 against Stockfish 7, compared to current master: • master against SF 7 (20000 games at LTC): +121.2 Elo • this patch with contempt=40 (20000 games at LTC): +154.11 Elo This was the result of real cooperative work from the Stockfish team, with key ideas coming from Stefan Geschwentner (locutus2) and Chris Cain (ceebo) while most of the community helped with feedback and computer time. In this commit the bench is unchanged by default, but you can test at home with the new contempt in the UCI options. The style of play will change a lot when using contempt different of zero (I repeat: not done in this version by default, however)! The Stockfish team is still deliberating over the best default contempt value in self-play and the best contempt modeling strategy, to help users choosing a contempt value when playing against much weaker programs. These informations will be given in future commits when available :-) Bench: 5051254 * Remove the prefetch No functional change.
1 parent 4fab5a2 commit 6588eb5

File tree

3 files changed

+11
-11
lines changed

3 files changed

+11
-11
lines changed

src/evaluate.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -840,7 +840,7 @@ namespace {
840840
// Initialize score by reading the incrementally updated scores included in
841841
// the position object (material + piece square tables) and the material
842842
// imbalance. Score is computed internally from the white point of view.
843-
Score score = pos.psq_score() + me->imbalance();
843+
Score score = pos.psq_score() + me->imbalance() + Eval::Contempt;
844844

845845
// Probe the pawn hash table
846846
pe = Pawns::probe(pos);
@@ -903,6 +903,7 @@ namespace {
903903

904904
} // namespace
905905

906+
Score Eval::Contempt = SCORE_ZERO;
906907

907908
/// evaluate() is the evaluator for the outer world. It returns a static evaluation
908909
/// of the position from the point of view of the side to move.

src/evaluate.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ namespace Eval {
3131

3232
const Value Tempo = Value(20); // Must be visible to search
3333

34+
extern Score Contempt;
35+
3436
std::string trace(const Position& pos);
3537

3638
Value evaluate(const Position& pos);

src/search.cpp

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,6 @@ namespace {
9696
Move best = MOVE_NONE;
9797
};
9898

99-
Value DrawValue[COLOR_NB];
100-
10199
template <NodeType NT>
102100
Value search(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth, bool cutNode, bool skipEarlyPruning);
103101

@@ -202,8 +200,9 @@ void MainThread::search() {
202200
TT.new_search();
203201

204202
int contempt = Options["Contempt"] * PawnValueEg / 100; // From centipawns
205-
DrawValue[ us] = VALUE_DRAW - Value(contempt);
206-
DrawValue[~us] = VALUE_DRAW + Value(contempt);
203+
204+
Eval::Contempt = (us == WHITE ? make_score(contempt, contempt / 2)
205+
: -make_score(contempt, contempt / 2));
207206

208207
if (rootMoves.empty())
209208
{
@@ -444,7 +443,7 @@ void Thread::search() {
444443
int improvingFactor = std::max(229, std::min(715, 357 + 119 * F[0] - 6 * F[1]));
445444

446445
Color us = rootPos.side_to_move();
447-
bool thinkHard = DrawValue[us] == bestValue
446+
bool thinkHard = bestValue == VALUE_DRAW
448447
&& Limits.time[us] - Time.elapsed() > Limits.time[~us]
449448
&& ::pv_is_draw(rootPos);
450449

@@ -532,8 +531,7 @@ namespace {
532531
{
533532
// Step 2. Check for aborted search and immediate draw
534533
if (Threads.stop.load(std::memory_order_relaxed) || pos.is_draw(ss->ply) || ss->ply >= MAX_PLY)
535-
return ss->ply >= MAX_PLY && !inCheck ? evaluate(pos)
536-
: DrawValue[pos.side_to_move()];
534+
return ss->ply >= MAX_PLY && !inCheck ? evaluate(pos) : VALUE_DRAW;
537535

538536
// Step 3. Mate distance pruning. Even if we mate at the next move our score
539537
// would be at best mate_in(ss->ply+1), but if alpha is already bigger because
@@ -1074,7 +1072,7 @@ namespace {
10741072

10751073
if (!moveCount)
10761074
bestValue = excludedMove ? alpha
1077-
: inCheck ? mated_in(ss->ply) : DrawValue[pos.side_to_move()];
1075+
: inCheck ? mated_in(ss->ply) : VALUE_DRAW;
10781076
else if (bestMove)
10791077
{
10801078
// Quiet best move: update move sorting heuristics
@@ -1142,8 +1140,7 @@ namespace {
11421140

11431141
// Check for an instant draw or if the maximum ply has been reached
11441142
if (pos.is_draw(ss->ply) || ss->ply >= MAX_PLY)
1145-
return ss->ply >= MAX_PLY && !InCheck ? evaluate(pos)
1146-
: DrawValue[pos.side_to_move()];
1143+
return ss->ply >= MAX_PLY && !InCheck ? evaluate(pos) : VALUE_DRAW;
11471144

11481145
assert(0 <= ss->ply && ss->ply < MAX_PLY);
11491146

0 commit comments

Comments
 (0)