mirror of
https://github.com/sockspls/badfish
synced 2025-04-30 00:33:09 +00:00
Assorted trivia in search.cpp
The only interesting change is the moving of stack[MAX_PLY+4] back to its original position in id_loop (now renamed Thread::search). No functional change.
This commit is contained in:
parent
aa242d2f84
commit
86f04dbcc0
8 changed files with 41 additions and 45 deletions
|
@ -91,8 +91,8 @@ const vector<string> Defaults = {
|
||||||
void benchmark(const Position& current, istream& is) {
|
void benchmark(const Position& current, istream& is) {
|
||||||
|
|
||||||
string token;
|
string token;
|
||||||
Search::LimitsType limits;
|
|
||||||
vector<string> fens;
|
vector<string> fens;
|
||||||
|
Search::LimitsType limits;
|
||||||
|
|
||||||
// Assign default values to missing arguments
|
// Assign default values to missing arguments
|
||||||
string ttSize = (is >> token) ? token : "16";
|
string ttSize = (is >> token) ? token : "16";
|
||||||
|
@ -103,10 +103,10 @@ void benchmark(const Position& current, istream& is) {
|
||||||
|
|
||||||
Options["Hash"] = ttSize;
|
Options["Hash"] = ttSize;
|
||||||
Options["Threads"] = threads;
|
Options["Threads"] = threads;
|
||||||
Search::reset();
|
Search::clear();
|
||||||
|
|
||||||
if (limitType == "time")
|
if (limitType == "time")
|
||||||
limits.movetime = stoi(limit); // movetime is in ms
|
limits.movetime = stoi(limit); // movetime is in millisecs
|
||||||
|
|
||||||
else if (limitType == "nodes")
|
else if (limitType == "nodes")
|
||||||
limits.nodes = stoi(limit);
|
limits.nodes = stoi(limit);
|
||||||
|
@ -151,7 +151,7 @@ void benchmark(const Position& current, istream& is) {
|
||||||
cerr << "\nPosition: " << i + 1 << '/' << fens.size() << endl;
|
cerr << "\nPosition: " << i + 1 << '/' << fens.size() << endl;
|
||||||
|
|
||||||
if (limitType == "perft")
|
if (limitType == "perft")
|
||||||
nodes += Search::perft<true>(pos, limits.depth * ONE_PLY);
|
nodes += Search::perft(pos, limits.depth * ONE_PLY);
|
||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -60,7 +60,7 @@ namespace {
|
||||||
const int PushAway [8] = { 0, 5, 20, 40, 60, 80, 90, 100 };
|
const int PushAway [8] = { 0, 5, 20, 40, 60, 80, 90, 100 };
|
||||||
|
|
||||||
// Pawn Rank based scaling factors used in KRPPKRP endgame
|
// Pawn Rank based scaling factors used in KRPPKRP endgame
|
||||||
const int KRPPKRPScaleFactors[RANK_NB] = {0, 9, 10, 14, 21, 44, 0, 0};
|
const int KRPPKRPScaleFactors[RANK_NB] = { 0, 9, 10, 14, 21, 44, 0, 0 };
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
bool verify_material(const Position& pos, Color c, Value npm, int pawnsCnt) {
|
bool verify_material(const Position& pos, Color c, Value npm, int pawnsCnt) {
|
||||||
|
|
|
@ -174,9 +174,9 @@ void Search::init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Search::reset() clears all search memory, to obtain reproducible search results
|
/// Search::clear() resets to zero search state, to obtain reproducible results
|
||||||
|
|
||||||
void Search::reset () {
|
void Search::clear() {
|
||||||
|
|
||||||
TT.clear();
|
TT.clear();
|
||||||
CounterMovesHistory.clear();
|
CounterMovesHistory.clear();
|
||||||
|
@ -216,7 +216,7 @@ uint64_t Search::perft(Position& pos, Depth depth) {
|
||||||
return nodes;
|
return nodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
template uint64_t Search::perft<true>(Position& pos, Depth depth);
|
template uint64_t Search::perft<true>(Position&, Depth);
|
||||||
|
|
||||||
|
|
||||||
/// MainThread::think() is called by the main thread when the program receives
|
/// MainThread::think() is called by the main thread when the program receives
|
||||||
|
@ -344,7 +344,7 @@ void MainThread::think() {
|
||||||
|
|
||||||
void Thread::search(bool isMainThread) {
|
void Thread::search(bool isMainThread) {
|
||||||
|
|
||||||
Stack* ss = stack + 2; // To allow referencing (ss-2) and (ss+2)
|
Stack stack[MAX_PLY+4], *ss = stack+2; // To allow referencing (ss-2) and (ss+2)
|
||||||
Value bestValue, alpha, beta, delta;
|
Value bestValue, alpha, beta, delta;
|
||||||
Move easyMove = MOVE_NONE;
|
Move easyMove = MOVE_NONE;
|
||||||
|
|
||||||
|
@ -836,7 +836,7 @@ moves_loop: // When in check search starts from here
|
||||||
|
|
||||||
if (RootNode && thisThread == Threads.main())
|
if (RootNode && thisThread == Threads.main())
|
||||||
{
|
{
|
||||||
Signals.firstRootMove = moveCount == 1;
|
Signals.firstRootMove = (moveCount == 1);
|
||||||
|
|
||||||
if (Time.elapsed() > 3000)
|
if (Time.elapsed() > 3000)
|
||||||
sync_cout << "info depth " << depth / ONE_PLY
|
sync_cout << "info depth " << depth / ONE_PLY
|
||||||
|
@ -1095,7 +1095,7 @@ moves_loop: // When in check search starts from here
|
||||||
&& is_ok((ss - 1)->currentMove)
|
&& is_ok((ss - 1)->currentMove)
|
||||||
&& is_ok((ss - 2)->currentMove))
|
&& is_ok((ss - 2)->currentMove))
|
||||||
{
|
{
|
||||||
Value bonus = Value((depth / ONE_PLY) * (depth / ONE_PLY) + depth / ONE_PLY -1);
|
Value bonus = Value((depth / ONE_PLY) * (depth / ONE_PLY) + depth / ONE_PLY - 1);
|
||||||
Square prevPrevSq = to_sq((ss - 2)->currentMove);
|
Square prevPrevSq = to_sq((ss - 2)->currentMove);
|
||||||
CounterMovesStats& prevCmh = CounterMovesHistory[pos.piece_on(prevPrevSq)][prevPrevSq];
|
CounterMovesStats& prevCmh = CounterMovesHistory[pos.piece_on(prevPrevSq)][prevPrevSq];
|
||||||
prevCmh.update(pos.piece_on(prevSq), prevSq, bonus);
|
prevCmh.update(pos.piece_on(prevSq), prevSq, bonus);
|
||||||
|
@ -1359,8 +1359,8 @@ moves_loop: // When in check search starts from here
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// update_stats() updates killers, history, countermove history and
|
// update_stats() updates killers, history, countermove and countermove
|
||||||
// countermoves stats for a quiet best move.
|
// history when a new quiet best move is found.
|
||||||
|
|
||||||
void update_stats(const Position& pos, Stack* ss, Move move,
|
void update_stats(const Position& pos, Stack* ss, Move move,
|
||||||
Depth depth, Move* quiets, int quietsCnt) {
|
Depth depth, Move* quiets, int quietsCnt) {
|
||||||
|
@ -1371,7 +1371,7 @@ moves_loop: // When in check search starts from here
|
||||||
ss->killers[0] = move;
|
ss->killers[0] = move;
|
||||||
}
|
}
|
||||||
|
|
||||||
Value bonus = Value((depth / ONE_PLY) * (depth / ONE_PLY) + depth / ONE_PLY -1);
|
Value bonus = Value((depth / ONE_PLY) * (depth / ONE_PLY) + depth / ONE_PLY - 1);
|
||||||
|
|
||||||
Square prevSq = to_sq((ss-1)->currentMove);
|
Square prevSq = to_sq((ss-1)->currentMove);
|
||||||
CounterMovesStats& cmh = CounterMovesHistory[pos.piece_on(prevSq)][prevSq];
|
CounterMovesStats& cmh = CounterMovesHistory[pos.piece_on(prevSq)][prevSq];
|
||||||
|
@ -1394,14 +1394,14 @@ moves_loop: // When in check search starts from here
|
||||||
cmh.update(pos.moved_piece(quiets[i]), to_sq(quiets[i]), -bonus);
|
cmh.update(pos.moved_piece(quiets[i]), to_sq(quiets[i]), -bonus);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extra penalty for TT move in previous ply when it gets refuted
|
// Extra penalty for a quiet TT move in previous ply when it gets refuted
|
||||||
if ( (ss-1)->moveCount == 1
|
if ( (ss-1)->moveCount == 1
|
||||||
&& !pos.captured_piece_type()
|
&& !pos.captured_piece_type()
|
||||||
&& is_ok((ss-2)->currentMove))
|
&& is_ok((ss-2)->currentMove))
|
||||||
{
|
{
|
||||||
Square prevPrevSq = to_sq((ss-2)->currentMove);
|
Square prevPrevSq = to_sq((ss-2)->currentMove);
|
||||||
CounterMovesStats& prevCmh = CounterMovesHistory[pos.piece_on(prevPrevSq)][prevPrevSq];
|
CounterMovesStats& prevCmh = CounterMovesHistory[pos.piece_on(prevPrevSq)][prevPrevSq];
|
||||||
prevCmh.update(pos.piece_on(prevSq), prevSq, -bonus - 2 * ((depth + 1) / ONE_PLY));
|
prevCmh.update(pos.piece_on(prevSq), prevSq, -bonus - 2 * (depth + 1) / ONE_PLY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1411,23 +1411,23 @@ moves_loop: // When in check search starts from here
|
||||||
|
|
||||||
Move Skill::pick_best(size_t multiPV) {
|
Move Skill::pick_best(size_t multiPV) {
|
||||||
|
|
||||||
// PRNG sequence should be non-deterministic, so we seed it with the time at init
|
|
||||||
const Search::RootMoveVector& rootMoves = Threads.main()->rootMoves;
|
const Search::RootMoveVector& rootMoves = Threads.main()->rootMoves;
|
||||||
static PRNG rng(now());
|
static PRNG rng(now()); // PRNG sequence should be non-deterministic
|
||||||
|
|
||||||
// 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[multiPV - 1].score, PawnValueMg);
|
Value topScore = rootMoves[0].score;
|
||||||
|
int delta = std::min(topScore - rootMoves[multiPV - 1].score, PawnValueMg);
|
||||||
int weakness = 120 - 2 * level;
|
int weakness = 120 - 2 * level;
|
||||||
int maxScore = -VALUE_INFINITE;
|
int maxScore = -VALUE_INFINITE;
|
||||||
|
|
||||||
// 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 levels, 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 < multiPV; ++i)
|
for (size_t i = 0; i < multiPV; ++i)
|
||||||
{
|
{
|
||||||
// This is our magic formula
|
// This is our magic formula
|
||||||
int push = ( weakness * int(rootMoves[0].score - rootMoves[i].score)
|
int push = ( weakness * int(topScore - rootMoves[i].score)
|
||||||
+ variance * (rng.rand<unsigned>() % weakness)) / 128;
|
+ delta * (rng.rand<unsigned>() % weakness)) / 128;
|
||||||
|
|
||||||
if (rootMoves[i].score + push > maxScore)
|
if (rootMoves[i].score + push > maxScore)
|
||||||
{
|
{
|
||||||
|
@ -1435,6 +1435,7 @@ moves_loop: // When in check search starts from here
|
||||||
best = rootMoves[i].pv[0];
|
best = rootMoves[i].pv[0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return best;
|
return best;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1512,7 +1513,8 @@ void RootMove::insert_pv_in_tt(Position& pos) {
|
||||||
TTEntry* tte = TT.probe(pos.key(), ttHit);
|
TTEntry* tte = TT.probe(pos.key(), ttHit);
|
||||||
|
|
||||||
if (!ttHit || tte->move() != m) // Don't overwrite correct entries
|
if (!ttHit || tte->move() != m) // Don't overwrite correct entries
|
||||||
tte->save(pos.key(), VALUE_NONE, BOUND_NONE, DEPTH_NONE, m, VALUE_NONE, TT.generation());
|
tte->save(pos.key(), VALUE_NONE, BOUND_NONE, DEPTH_NONE,
|
||||||
|
m, VALUE_NONE, TT.generation());
|
||||||
|
|
||||||
pos.do_move(m, *st++, pos.gives_check(m, CheckInfo(pos)));
|
pos.do_move(m, *st++, pos.gives_check(m, CheckInfo(pos)));
|
||||||
}
|
}
|
||||||
|
@ -1522,10 +1524,10 @@ void RootMove::insert_pv_in_tt(Position& pos) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// RootMove::extract_ponder_from_tt() is called in case we have no ponder move before
|
/// RootMove::extract_ponder_from_tt() is called in case we have no ponder move
|
||||||
/// exiting the search, for instance in case we stop the search during a fail high at
|
/// before exiting the search, for instance in case we stop the search during a
|
||||||
/// root. We try hard to have a ponder move to return to the GUI, otherwise in case of
|
/// fail high at root. We try hard to have a ponder move to return to the GUI,
|
||||||
/// 'ponder on' we have nothing to think on.
|
/// otherwise in case of 'ponder on' we have nothing to think on.
|
||||||
|
|
||||||
bool RootMove::extract_ponder_from_tt(Position& pos)
|
bool RootMove::extract_ponder_from_tt(Position& pos)
|
||||||
{
|
{
|
||||||
|
@ -1549,11 +1551,11 @@ bool RootMove::extract_ponder_from_tt(Position& pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// check_time() is called by the timer thread when the timer triggers. It is
|
/// TimerThread::check_time() is called by when the timer triggers. It is used
|
||||||
/// used to print debug info and, more importantly, to detect when we are out of
|
/// to print debug info and, more importantly, to detect when we are out of
|
||||||
/// available time and thus stop the search.
|
/// available time and thus stop the search.
|
||||||
|
|
||||||
void check_time() {
|
void TimerThread::check_time() {
|
||||||
|
|
||||||
static TimePoint lastInfoTime = now();
|
static TimePoint lastInfoTime = now();
|
||||||
int elapsed = Time.elapsed();
|
int elapsed = Time.elapsed();
|
||||||
|
|
|
@ -103,8 +103,8 @@ extern LimitsType Limits;
|
||||||
extern StateStackPtr SetupStates;
|
extern StateStackPtr SetupStates;
|
||||||
|
|
||||||
void init();
|
void init();
|
||||||
void reset();
|
void clear();
|
||||||
template<bool Root> uint64_t perft(Position& pos, Depth depth);
|
template<bool Root = true> uint64_t perft(Position& pos, Depth depth);
|
||||||
|
|
||||||
} // namespace Search
|
} // namespace Search
|
||||||
|
|
||||||
|
|
|
@ -29,8 +29,6 @@ using namespace Search;
|
||||||
|
|
||||||
ThreadPool Threads; // Global object
|
ThreadPool Threads; // Global object
|
||||||
|
|
||||||
extern void check_time();
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
// Helpers to launch a thread after creation and joining before delete. Outside the
|
// Helpers to launch a thread after creation and joining before delete. Outside the
|
||||||
|
|
|
@ -34,10 +34,6 @@
|
||||||
#include "search.h"
|
#include "search.h"
|
||||||
#include "thread_win32.h"
|
#include "thread_win32.h"
|
||||||
|
|
||||||
struct Thread;
|
|
||||||
|
|
||||||
const size_t MAX_THREADS = 128;
|
|
||||||
|
|
||||||
|
|
||||||
/// ThreadBase struct is the base of the hierarchy from where we derive all the
|
/// ThreadBase struct is the base of the hierarchy from where we derive all the
|
||||||
/// specialized thread classes.
|
/// specialized thread classes.
|
||||||
|
@ -78,7 +74,6 @@ struct Thread : public ThreadBase {
|
||||||
Position rootPos;
|
Position rootPos;
|
||||||
Search::RootMoveVector rootMoves;
|
Search::RootMoveVector rootMoves;
|
||||||
Depth rootDepth;
|
Depth rootDepth;
|
||||||
Search::Stack stack[MAX_PLY+4];
|
|
||||||
HistoryStats history;
|
HistoryStats history;
|
||||||
MovesStats counterMoves;
|
MovesStats counterMoves;
|
||||||
};
|
};
|
||||||
|
@ -100,6 +95,7 @@ struct TimerThread : public ThreadBase {
|
||||||
static const int Resolution = 5; // Millisec between two check_time() calls
|
static const int Resolution = 5; // Millisec between two check_time() calls
|
||||||
|
|
||||||
virtual void idle_loop();
|
virtual void idle_loop();
|
||||||
|
void check_time();
|
||||||
|
|
||||||
bool run = false;
|
bool run = false;
|
||||||
};
|
};
|
||||||
|
|
|
@ -182,7 +182,7 @@ void UCI::loop(int argc, char* argv[]) {
|
||||||
|
|
||||||
else if (token == "ucinewgame")
|
else if (token == "ucinewgame")
|
||||||
{
|
{
|
||||||
Search::reset();
|
Search::clear();
|
||||||
Time.availableNodes = 0;
|
Time.availableNodes = 0;
|
||||||
}
|
}
|
||||||
else if (token == "isready") sync_cout << "readyok" << sync_endl;
|
else if (token == "isready") sync_cout << "readyok" << sync_endl;
|
||||||
|
|
|
@ -35,7 +35,7 @@ UCI::OptionsMap Options; // Global object
|
||||||
namespace UCI {
|
namespace UCI {
|
||||||
|
|
||||||
/// 'On change' actions, triggered by an option's value change
|
/// 'On change' actions, triggered by an option's value change
|
||||||
void on_clear_hash(const Option&) { Search::reset(); }
|
void on_clear_hash(const Option&) { Search::clear(); }
|
||||||
void on_hash_size(const Option& o) { TT.resize(o); }
|
void on_hash_size(const Option& o) { TT.resize(o); }
|
||||||
void on_logger(const Option& o) { start_logger(o); }
|
void on_logger(const Option& o) { start_logger(o); }
|
||||||
void on_threads(const Option&) { Threads.read_uci_options(); }
|
void on_threads(const Option&) { Threads.read_uci_options(); }
|
||||||
|
@ -58,7 +58,7 @@ void init(OptionsMap& o) {
|
||||||
|
|
||||||
o["Write Debug Log"] << Option(false, on_logger);
|
o["Write Debug Log"] << Option(false, on_logger);
|
||||||
o["Contempt"] << Option(0, -100, 100);
|
o["Contempt"] << Option(0, -100, 100);
|
||||||
o["Threads"] << Option(1, 1, MAX_THREADS, on_threads);
|
o["Threads"] << Option(1, 1, 128, on_threads);
|
||||||
o["Hash"] << Option(16, 1, MaxHashMB, on_hash_size);
|
o["Hash"] << Option(16, 1, MaxHashMB, on_hash_size);
|
||||||
o["Clear Hash"] << Option(on_clear_hash);
|
o["Clear Hash"] << Option(on_clear_hash);
|
||||||
o["Ponder"] << Option(true);
|
o["Ponder"] << Option(true);
|
||||||
|
|
Loading…
Add table
Reference in a new issue