Skip to content

Commit d865bad

Browse files
authored
Merge pull request #622 from IIvec/master
New master
2 parents e781e5e + b508f95 commit d865bad

File tree

6 files changed

+73
-55
lines changed

6 files changed

+73
-55
lines changed

src/evaluate.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -488,7 +488,11 @@ namespace {
488488

489489
// Transform the kingDanger units into a Score, and substract it from the evaluation
490490
if (kingDanger > 0)
491+
{
492+
int mobilityDanger = mg_value(mobility[Them] - mobility[Us]);
493+
kingDanger = std::max(0, kingDanger + mobilityDanger);
491494
score -= make_score(kingDanger * kingDanger / 4096, kingDanger / 16);
495+
}
492496
}
493497

494498
// King tropism: firstly, find squares that opponent attacks in our king flank

src/search.cpp

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -676,7 +676,7 @@ namespace {
676676
if ( !PvNode
677677
&& eval >= beta
678678
&& ss->staticEval >= beta - 36 * depth / ONE_PLY + 225
679-
&& (ss->ply >= thisThread->nmp_ply || ss->ply % 2 == thisThread->pair))
679+
&& (ss->ply >= thisThread->nmp_ply || ss->ply % 2 != thisThread->nmp_odd))
680680
{
681681

682682
assert(eval - beta >= 0);
@@ -698,21 +698,18 @@ namespace {
698698
if (nullValue >= VALUE_MATE_IN_MAX_PLY)
699699
nullValue = beta;
700700

701-
if (depth < 12 * ONE_PLY && abs(beta) < VALUE_KNOWN_WIN)
701+
if (abs(beta) < VALUE_KNOWN_WIN && (depth < 12 * ONE_PLY || thisThread->nmp_ply))
702702
return nullValue;
703703

704704
// Do verification search at high depths
705-
R += ONE_PLY;
706705
// disable null move pruning for side to move for the first part of the remaining search tree
707-
int nmp_ply = thisThread->nmp_ply;
708-
int pair = thisThread->pair;
709706
thisThread->nmp_ply = ss->ply + 3 * (depth-R) / 4;
710-
thisThread->pair = (ss->ply % 2) == 0;
707+
thisThread->nmp_odd = ss->ply % 2;
711708

712709
Value v = depth-R < ONE_PLY ? qsearch<NonPV, false>(pos, ss, beta-1, beta)
713710
: search<NonPV>(pos, ss, beta-1, beta, depth-R, false, true);
714-
thisThread->pair = pair;
715-
thisThread->nmp_ply = nmp_ply;
711+
712+
thisThread->nmp_odd = thisThread->nmp_ply = 0;
716713

717714
if (v >= beta)
718715
return nullValue;
@@ -1497,7 +1494,7 @@ namespace {
14971494
if (Threads.ponder)
14981495
return;
14991496

1500-
if ( (Limits.use_time_management() && elapsed > Time.maximum())
1497+
if ( (Limits.use_time_management() && elapsed > Time.maximum() - 10)
15011498
|| (Limits.movetime && elapsed >= Limits.movetime)
15021499
|| (Limits.nodes && Threads.nodes_searched() >= (uint64_t)Limits.nodes))
15031500
Threads.stop = true;

src/thread.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -187,12 +187,10 @@ void ThreadPool::start_thinking(Position& pos, StateListPtr& states,
187187

188188
for (Thread* th : *this)
189189
{
190-
th->nodes = th->tbHits = 0;
190+
th->nodes = th->tbHits = th->nmp_ply = th->nmp_odd = 0;
191191
th->rootDepth = th->completedDepth = DEPTH_ZERO;
192192
th->rootMoves = rootMoves;
193193
th->rootPos.set(pos.fen(), pos.is_chess960(), &setupStates->back(), th);
194-
th->nmp_ply = 0;
195-
th->pair = -1;
196194
}
197195

198196
setupStates->back() = tmp;

src/thread.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ class Thread {
6161
Material::Table materialTable;
6262
Endgames endgames;
6363
size_t PVIdx;
64-
int selDepth, nmp_ply, pair;
64+
int selDepth, nmp_ply, nmp_odd;
6565
std::atomic<uint64_t> nodes, tbHits;
6666

6767
Position rootPos;

src/timeman.cpp

Lines changed: 58 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
*/
2020

2121
#include <algorithm>
22+
#include <cfloat>
23+
#include <cmath>
2224

2325
#include "search.h"
2426
#include "timeman.h"
@@ -30,46 +32,41 @@ namespace {
3032

3133
enum TimeType { OptimumTime, MaxTime };
3234

33-
int remaining(int myTime, int myInc, int moveOverhead, int movesToGo,
34-
int moveNum, bool ponder, TimeType type) {
35+
const int MoveHorizon = 50; // Plan time management at most this many moves ahead
36+
const double MaxRatio = 7.09; // When in trouble, we can step over reserved time with this ratio
37+
const double StealRatio = 0.35; // However we must not steal time from remaining moves over this ratio
3538

36-
if (myTime <= 0)
37-
return 0;
3839

39-
double ratio; // Which ratio of myTime we are going to use
40+
// move_importance() is a skew-logistic function based on naive statistical
41+
// analysis of "how many games are still undecided after n half-moves". Game
42+
// is considered "undecided" as long as neither side has >275cp advantage.
43+
// Data was extracted from the CCRL game database with some simple filtering criteria.
4044

41-
// Usage of increment follows quadratic distribution with the maximum at move 25
42-
double inc = myInc * std::max(55.0, 120 - 0.12 * (moveNum - 25) * (moveNum - 25));
45+
double move_importance(int ply) {
4346

44-
// In moves-to-go we distribute time according to a quadratic function with
45-
// the maximum around move 20 for 40 moves in y time case.
46-
if (movesToGo)
47-
{
48-
ratio = (type == OptimumTime ? 1.0 : 6.0) / std::min(50, movesToGo);
47+
const double XScale = 7.64;
48+
const double XShift = 58.4;
49+
const double Skew = 0.183;
4950

50-
if (moveNum <= 40)
51-
ratio *= 1.1 - 0.001 * (moveNum - 20) * (moveNum - 20);
52-
else
53-
ratio *= 1.5;
51+
return pow((1 + exp((ply - XShift) / XScale)), -Skew) + DBL_MIN; // Ensure non-zero
52+
}
53+
54+
template<TimeType T>
55+
int remaining(int myTime, int movesToGo, int ply, int slowMover) {
5456

55-
if (movesToGo > 1)
56-
ratio = std::min(0.75, ratio);
57+
const double TMaxRatio = (T == OptimumTime ? 1 : MaxRatio);
58+
const double TStealRatio = (T == OptimumTime ? 0 : StealRatio);
5759

58-
ratio *= 1 + inc / (myTime * 8.5);
59-
}
60-
// Otherwise we increase usage of remaining time as the game goes on
61-
else
62-
{
63-
double k = 1 + 20 * moveNum / (500.0 + moveNum);
64-
ratio = (type == OptimumTime ? 0.017 : 0.07) * (k + inc / myTime);
65-
}
60+
double moveImportance = (move_importance(ply) * slowMover) / 100;
61+
double otherMovesImportance = 0;
6662

67-
int time = int(std::min(1.0, ratio) * std::max(0, myTime - moveOverhead));
63+
for (int i = 1; i < movesToGo; ++i)
64+
otherMovesImportance += move_importance(ply + 2 * i);
6865

69-
if (type == OptimumTime && ponder)
70-
time = 5 * time / 4;
66+
double ratio1 = (TMaxRatio * moveImportance) / (TMaxRatio * moveImportance + otherMovesImportance);
67+
double ratio2 = (moveImportance + TStealRatio * otherMovesImportance) / (moveImportance + otherMovesImportance);
7168

72-
return time;
69+
return int(myTime * std::min(ratio1, ratio2)); // Intel C++ asks for an explicit cast
7370
}
7471

7572
} // namespace
@@ -84,11 +81,12 @@ namespace {
8481
/// inc > 0 && movestogo == 0 means: x basetime + z increment
8582
/// inc > 0 && movestogo != 0 means: x moves in y minutes + z increment
8683

87-
void TimeManagement::init(Search::LimitsType& limits, Color us, int ply)
88-
{
89-
int moveOverhead = Options["Move Overhead"];
90-
int npmsec = Options["nodestime"];
91-
bool ponder = Options["Ponder"];
84+
void TimeManagement::init(Search::LimitsType& limits, Color us, int ply) {
85+
86+
int minThinkingTime = Options["Minimum Thinking Time"];
87+
int moveOverhead = Options["Move Overhead"];
88+
int slowMover = Options["Slow Mover"];
89+
int npmsec = Options["nodestime"];
9290

9391
// If we have to play in 'nodes as time' mode, then convert from time
9492
// to nodes, and use resulting values in time management formulas.
@@ -105,11 +103,30 @@ void TimeManagement::init(Search::LimitsType& limits, Color us, int ply)
105103
limits.npmsec = npmsec;
106104
}
107105

108-
int moveNum = (ply + 1) / 2;
109-
110106
startTime = limits.startTime;
111-
optimumTime = remaining(limits.time[us], limits.inc[us], moveOverhead,
112-
limits.movestogo, moveNum, ponder, OptimumTime);
113-
maximumTime = remaining(limits.time[us], limits.inc[us], moveOverhead,
114-
limits.movestogo, moveNum, ponder, MaxTime);
107+
optimumTime = maximumTime = std::max(limits.time[us], minThinkingTime);
108+
109+
const int MaxMTG = limits.movestogo ? std::min(limits.movestogo, MoveHorizon) : MoveHorizon;
110+
111+
// We calculate optimum time usage for different hypothetical "moves to go"-values
112+
// and choose the minimum of calculated search time values. Usually the greatest
113+
// hypMTG gives the minimum values.
114+
for (int hypMTG = 1; hypMTG <= MaxMTG; ++hypMTG)
115+
{
116+
// Calculate thinking time for hypothetical "moves to go"-value
117+
int hypMyTime = limits.time[us]
118+
+ limits.inc[us] * (hypMTG - 1)
119+
- moveOverhead * (2 + std::min(hypMTG, 40));
120+
121+
hypMyTime = std::max(hypMyTime, 0);
122+
123+
int t1 = minThinkingTime + remaining<OptimumTime>(hypMyTime, hypMTG, ply, slowMover);
124+
int t2 = minThinkingTime + remaining<MaxTime >(hypMyTime, hypMTG, ply, slowMover);
125+
126+
optimumTime = std::min(t1, optimumTime);
127+
maximumTime = std::min(t2, maximumTime);
128+
}
129+
130+
if (Options["Ponder"])
131+
optimumTime += optimumTime / 4;
115132
}

src/ucioption.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,9 @@ void init(OptionsMap& o) {
6666
o["Ponder"] << Option(false);
6767
o["MultiPV"] << Option(1, 1, 500);
6868
o["Skill Level"] << Option(20, 0, 20);
69-
o["Move Overhead"] << Option(100, 0, 5000);
69+
o["Move Overhead"] << Option(30, 0, 5000);
70+
o["Minimum Thinking Time"] << Option(20, 0, 5000);
71+
o["Slow Mover"] << Option(89, 10, 1000);
7072
o["nodestime"] << Option(0, 0, 10000);
7173
o["UCI_Chess960"] << Option(false);
7274
o["SyzygyPath"] << Option("<empty>", on_tb_path);

0 commit comments

Comments
 (0)