1
0
Fork 0
mirror of https://github.com/sockspls/badfish synced 2025-05-01 09:13:08 +00:00

Re-arrange Skill struct

Instead of swapping sub-optimal move in Skill
d'tor, make it explicitly at the end of the search.

Also streamline and clarify relation with multiPV
and pass it directly instead of relying on the hacky
'candidates' member.

No functional change.
This commit is contained in:
Marco Costalba 2015-01-25 11:07:43 +01:00
parent 69407ae9b8
commit 14f7d9a629

View file

@ -105,22 +105,14 @@ namespace {
string uci_pv(const Position& pos, Depth depth, Value alpha, Value beta); string uci_pv(const Position& pos, Depth depth, Value alpha, Value beta);
struct Skill { struct Skill {
Skill(int l, size_t rootSize) : level(l), Skill(int l) : level(l) {}
candidates(l < 20 ? std::min(4, (int)rootSize) : 0), bool enabled() const { return level < 20; }
best(MOVE_NONE) {}
~Skill() {
if (candidates) // Swap best PV line with the sub-optimal one
std::swap(RootMoves[0], *std::find(RootMoves.begin(),
RootMoves.end(), best ? best : pick_move()));
}
size_t candidates_size() const { return candidates; }
bool time_to_pick(Depth depth) const { return depth / ONE_PLY == 1 + level; } bool time_to_pick(Depth depth) const { return depth / ONE_PLY == 1 + level; }
Move pick_move(); Move best_move(size_t multiPV) { return best ? best : pick_best(multiPV); }
Move pick_best(size_t multiPV);
int level; int level;
size_t candidates; Move best = MOVE_NONE;
Move best;
}; };
} // namespace } // namespace
@ -309,11 +301,14 @@ namespace {
Followupmoves.clear(); Followupmoves.clear();
size_t multiPV = Options["MultiPV"]; size_t multiPV = Options["MultiPV"];
Skill skill(Options["Skill Level"], RootMoves.size()); Skill skill(Options["Skill Level"]);
// Do we have to play with skill handicap? In this case enable MultiPV search // When playing with strength handicap enable MultiPV search that we will
// that we will use behind the scenes to retrieve a set of possible moves. // use behind the scenes to retrieve a set of possible moves.
multiPV = std::max(multiPV, skill.candidates_size()); if (skill.enabled())
multiPV = std::max(multiPV, (size_t)4);
multiPV = std::min(multiPV, RootMoves.size());
// Iterative deepening loop until requested to stop or target depth reached // Iterative deepening loop until requested to stop or target depth reached
while (++depth < DEPTH_MAX && !Signals.stop && (!Limits.depth || depth <= Limits.depth)) while (++depth < DEPTH_MAX && !Signals.stop && (!Limits.depth || depth <= Limits.depth))
@ -327,7 +322,7 @@ namespace {
rm.previousScore = rm.score; rm.previousScore = rm.score;
// MultiPV loop. We perform a full root search for each PV line // MultiPV loop. We perform a full root search for each PV line
for (PVIdx = 0; PVIdx < std::min(multiPV, RootMoves.size()) && !Signals.stop; ++PVIdx) for (PVIdx = 0; PVIdx < multiPV && !Signals.stop; ++PVIdx)
{ {
// Reset aspiration window starting size // Reset aspiration window starting size
if (depth >= 5 * ONE_PLY) if (depth >= 5 * ONE_PLY)
@ -399,14 +394,13 @@ namespace {
sync_cout << "info nodes " << RootPos.nodes_searched() sync_cout << "info nodes " << RootPos.nodes_searched()
<< " time " << Time::now() - SearchTime << sync_endl; << " time " << Time::now() - SearchTime << sync_endl;
else if ( PVIdx + 1 == std::min(multiPV, RootMoves.size()) else if (PVIdx + 1 == multiPV || Time::now() - SearchTime > 3000)
|| Time::now() - SearchTime > 3000)
sync_cout << uci_pv(pos, depth, alpha, beta) << sync_endl; sync_cout << uci_pv(pos, depth, alpha, beta) << sync_endl;
} }
// If skill levels are enabled and time is up, pick a sub-optimal best move // If skill level is enabled and time is up, pick a sub-optimal best move
if (skill.candidates_size() && skill.time_to_pick(depth)) if (skill.enabled() && skill.time_to_pick(depth))
skill.pick_move(); skill.pick_best(multiPV);
// Have we found a "mate in x"? // Have we found a "mate in x"?
if ( Limits.mate if ( Limits.mate
@ -435,6 +429,11 @@ namespace {
} }
} }
} }
// If skill level is enabled, swap best PV line with the sub-optimal one
if (skill.enabled())
std::swap(RootMoves[0], *std::find(RootMoves.begin(),
RootMoves.end(), skill.best_move(multiPV)));
} }
@ -1370,24 +1369,23 @@ moves_loop: // When in check and at SpNode search starts from here
} }
// When playing with a strength handicap, choose best move among the first 'candidates' // When playing with strength handicap, choose best move among a set of RootMoves
// RootMoves using a statistical rule dependent on 'level'. Idea by Heinz van Saanen. // using a statistical rule dependent on 'level'. Idea by Heinz van Saanen.
Move Skill::pick_move() { Move Skill::pick_best(size_t multiPV) {
// PRNG sequence should be non-deterministic, so we seed it with the time at init // PRNG sequence should be non-deterministic, so we seed it with the time at init
static PRNG rng(Time::now()); static PRNG rng(Time::now());
// RootMoves are already sorted by score in descending order // RootMoves are already sorted by score in descending order
int variance = std::min(RootMoves[0].score - RootMoves[candidates - 1].score, PawnValueMg); int variance = std::min(RootMoves[0].score - RootMoves[multiPV - 1].score, PawnValueMg);
int weakness = 120 - 2 * level; int weakness = 120 - 2 * level;
int maxScore = -VALUE_INFINITE; int maxScore = -VALUE_INFINITE;
best = MOVE_NONE;
// Choose best move. For each move score we add two terms both dependent on // Choose best move. For each move score we add two terms both dependent on
// weakness. One deterministic and bigger for weaker moves, and one random, // weakness. One deterministic and bigger for weaker levels, and one random,
// then we choose the move with the resulting highest score. // then we choose the move with the resulting highest score.
for (size_t i = 0; i < candidates; ++i) for (size_t i = 0; i < multiPV; ++i)
{ {
int score = RootMoves[i].score; int score = RootMoves[i].score;