mirror of
https://github.com/sockspls/badfish
synced 2025-05-02 01:29:36 +00:00
parent
74e2fa97b7
commit
89723339d9
12 changed files with 103 additions and 102 deletions
|
@ -111,4 +111,4 @@ to where the source code can be found. If you make any changes to the
|
||||||
source code, these changes must also be made available under the GPL.
|
source code, these changes must also be made available under the GPL.
|
||||||
|
|
||||||
For full details, read the copy of the GPL found in the file named
|
For full details, read the copy of the GPL found in the file named
|
||||||
*Copying.txt*
|
*Copying.txt*.
|
||||||
|
|
|
@ -166,7 +166,7 @@ void benchmark(const Position& current, istream& is) {
|
||||||
|
|
||||||
elapsed = now() - elapsed + 1; // Ensure positivity to avoid a 'divide by zero'
|
elapsed = now() - elapsed + 1; // Ensure positivity to avoid a 'divide by zero'
|
||||||
|
|
||||||
dbg_print(); // Just before to exit
|
dbg_print(); // Just before exiting
|
||||||
|
|
||||||
cerr << "\n==========================="
|
cerr << "\n==========================="
|
||||||
<< "\nTotal time (ms) : " << elapsed
|
<< "\nTotal time (ms) : " << elapsed
|
||||||
|
|
|
@ -33,7 +33,7 @@ namespace {
|
||||||
|
|
||||||
namespace Trace {
|
namespace Trace {
|
||||||
|
|
||||||
enum Term { // First 8 entries are for PieceType
|
enum Term { // The first 8 entries are for PieceType
|
||||||
MATERIAL = 8, IMBALANCE, MOBILITY, THREAT, PASSED, SPACE, TOTAL, TERM_NB
|
MATERIAL = 8, IMBALANCE, MOBILITY, THREAT, PASSED, SPACE, TOTAL, TERM_NB
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -89,7 +89,7 @@ namespace {
|
||||||
// which attack a square in the kingRing of the enemy king.
|
// which attack a square in the kingRing of the enemy king.
|
||||||
int kingAttackersCount[COLOR_NB];
|
int kingAttackersCount[COLOR_NB];
|
||||||
|
|
||||||
// kingAttackersWeight[color] is the sum of the "weight" of the pieces of the
|
// kingAttackersWeight[color] is the sum of the "weights" of the pieces of the
|
||||||
// given color which attack a square in the kingRing of the enemy king. The
|
// given color which attack a square in the kingRing of the enemy king. The
|
||||||
// weights of the individual piece types are given by the elements in the
|
// weights of the individual piece types are given by the elements in the
|
||||||
// KingAttackWeights array.
|
// KingAttackWeights array.
|
||||||
|
@ -161,20 +161,20 @@ namespace {
|
||||||
const Score RookOnFile[2] = { S(19, 10), S(43, 21) };
|
const Score RookOnFile[2] = { S(19, 10), S(43, 21) };
|
||||||
|
|
||||||
// ThreatBySafePawn[PieceType] contains bonuses according to which piece
|
// ThreatBySafePawn[PieceType] contains bonuses according to which piece
|
||||||
// type is attacked by a pawn which is protected or not attacked.
|
// type is attacked by a pawn which is protected or is not attacked.
|
||||||
const Score ThreatBySafePawn[PIECE_TYPE_NB] = {
|
const Score ThreatBySafePawn[PIECE_TYPE_NB] = {
|
||||||
S(0, 0), S(0, 0), S(176, 139), S(131, 127), S(217, 218), S(203, 215) };
|
S(0, 0), S(0, 0), S(176, 139), S(131, 127), S(217, 218), S(203, 215) };
|
||||||
|
|
||||||
// Threat[by minor/by rook][attacked PieceType] contains
|
// Threat[by minor/by rook][attacked PieceType] contains
|
||||||
// bonuses according to which piece type attacks which one.
|
// bonuses according to which piece type attacks which one.
|
||||||
// Attacks on lesser pieces which are pawn defended are not considered.
|
// Attacks on lesser pieces which are pawn-defended are not considered.
|
||||||
const Score Threat[][PIECE_TYPE_NB] = {
|
const Score Threat[][PIECE_TYPE_NB] = {
|
||||||
{ S(0, 0), S(0, 33), S(45, 43), S(46, 47), S(72,107), S(48,118) }, // by Minor
|
{ S(0, 0), S(0, 33), S(45, 43), S(46, 47), S(72,107), S(48,118) }, // by Minor
|
||||||
{ S(0, 0), S(0, 25), S(40, 62), S(40, 59), S( 0, 34), S(35, 48) } // by Rook
|
{ S(0, 0), S(0, 25), S(40, 62), S(40, 59), S( 0, 34), S(35, 48) } // by Rook
|
||||||
};
|
};
|
||||||
|
|
||||||
// ThreatByKing[on one/on many] contains bonuses for King attacks on
|
// ThreatByKing[on one/on many] contains bonuses for King attacks on
|
||||||
// pawns or pieces which are not pawn defended.
|
// pawns or pieces which are not pawn-defended.
|
||||||
const Score ThreatByKing[2] = { S(3, 62), S(9, 138) };
|
const Score ThreatByKing[2] = { S(3, 62), S(9, 138) };
|
||||||
|
|
||||||
// Passed[mg/eg][Rank] contains midgame and endgame bonuses for passed pawns.
|
// Passed[mg/eg][Rank] contains midgame and endgame bonuses for passed pawns.
|
||||||
|
@ -226,7 +226,7 @@ namespace {
|
||||||
const int KnightCheck = 14;
|
const int KnightCheck = 14;
|
||||||
|
|
||||||
|
|
||||||
// eval_init() initializes king and attack bitboards for given color
|
// eval_init() initializes king and attack bitboards for a given color
|
||||||
// adding pawn attacks. To be done at the beginning of the evaluation.
|
// adding pawn attacks. To be done at the beginning of the evaluation.
|
||||||
|
|
||||||
template<Color Us>
|
template<Color Us>
|
||||||
|
@ -319,7 +319,7 @@ namespace {
|
||||||
&& (pos.pieces(PAWN) & (s + pawn_push(Us))))
|
&& (pos.pieces(PAWN) & (s + pawn_push(Us))))
|
||||||
score += MinorBehindPawn;
|
score += MinorBehindPawn;
|
||||||
|
|
||||||
// Penalty for pawns on same color square of bishop
|
// Penalty for pawns on the same color square as the bishop
|
||||||
if (Pt == BISHOP)
|
if (Pt == BISHOP)
|
||||||
score -= BishopPawns * ei.pi->pawns_on_same_color_squares(Us, s);
|
score -= BishopPawns * ei.pi->pawns_on_same_color_squares(Us, s);
|
||||||
|
|
||||||
|
@ -352,7 +352,7 @@ namespace {
|
||||||
if (ei.pi->semiopen_file(Us, file_of(s)))
|
if (ei.pi->semiopen_file(Us, file_of(s)))
|
||||||
score += RookOnFile[!!ei.pi->semiopen_file(Them, file_of(s))];
|
score += RookOnFile[!!ei.pi->semiopen_file(Them, file_of(s))];
|
||||||
|
|
||||||
// Penalize when trapped by the king, even more if king cannot castle
|
// Penalize when trapped by the king, even more if the king cannot castle
|
||||||
else if (mob <= 3)
|
else if (mob <= 3)
|
||||||
{
|
{
|
||||||
Square ksq = pos.square<KING>(Us);
|
Square ksq = pos.square<KING>(Us);
|
||||||
|
@ -368,7 +368,7 @@ namespace {
|
||||||
if (DoTrace)
|
if (DoTrace)
|
||||||
Trace::add(Pt, Us, score);
|
Trace::add(Pt, Us, score);
|
||||||
|
|
||||||
// Recursively call evaluate_pieces() of next piece type until KING excluded
|
// Recursively call evaluate_pieces() of next piece type until KING is excluded
|
||||||
return score - evaluate_pieces<DoTrace, Them, NextPt>(pos, ei, mobility, mobilityArea);
|
return score - evaluate_pieces<DoTrace, Them, NextPt>(pos, ei, mobility, mobilityArea);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -468,7 +468,7 @@ namespace {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finally, extract the king danger score from the KingDanger[]
|
// Finally, extract the king danger score from the KingDanger[]
|
||||||
// array and subtract the score from evaluation.
|
// array and subtract the score from the evaluation.
|
||||||
score -= KingDanger[std::max(std::min(attackUnits, 399), 0)];
|
score -= KingDanger[std::max(std::min(attackUnits, 399), 0)];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -479,8 +479,8 @@ namespace {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// evaluate_threats() assigns bonuses according to the type of attacking piece
|
// evaluate_threats() assigns bonuses according to the types of the attacking
|
||||||
// and the type of attacked one.
|
// and the attacked pieces.
|
||||||
|
|
||||||
template<Color Us, bool DoTrace>
|
template<Color Us, bool DoTrace>
|
||||||
Score evaluate_threats(const Position& pos, const EvalInfo& ei) {
|
Score evaluate_threats(const Position& pos, const EvalInfo& ei) {
|
||||||
|
@ -619,7 +619,7 @@ namespace {
|
||||||
// assign a smaller bonus if the block square isn't attacked.
|
// assign a smaller bonus if the block square isn't attacked.
|
||||||
int k = !unsafeSquares ? 18 : !(unsafeSquares & blockSq) ? 8 : 0;
|
int k = !unsafeSquares ? 18 : !(unsafeSquares & blockSq) ? 8 : 0;
|
||||||
|
|
||||||
// If the path to queen is fully defended, assign a big bonus.
|
// If the path to the queen is fully defended, assign a big bonus.
|
||||||
// Otherwise assign a smaller bonus if the block square is defended.
|
// Otherwise assign a smaller bonus if the block square is defended.
|
||||||
if (defendedSquares == squaresToQueen)
|
if (defendedSquares == squaresToQueen)
|
||||||
k += 6;
|
k += 6;
|
||||||
|
@ -687,7 +687,7 @@ namespace {
|
||||||
|
|
||||||
|
|
||||||
// evaluate_initiative() computes the initiative correction value for the
|
// evaluate_initiative() computes the initiative correction value for the
|
||||||
// position, i.e. second order bonus/malus based on the known attacking/defending
|
// position, i.e., second order bonus/malus based on the known attacking/defending
|
||||||
// status of the players.
|
// status of the players.
|
||||||
Score evaluate_initiative(const Position& pos, int asymmetry, Value eg) {
|
Score evaluate_initiative(const Position& pos, int asymmetry, Value eg) {
|
||||||
|
|
||||||
|
@ -720,7 +720,7 @@ namespace {
|
||||||
if (pos.opposite_bishops())
|
if (pos.opposite_bishops())
|
||||||
{
|
{
|
||||||
// Endgame with opposite-colored bishops and no other pieces (ignoring pawns)
|
// Endgame with opposite-colored bishops and no other pieces (ignoring pawns)
|
||||||
// is almost a draw, in case of KBP vs KB is even more a draw.
|
// is almost a draw, in case of KBP vs KB, it is even more a draw.
|
||||||
if ( pos.non_pawn_material(WHITE) == BishopValueMg
|
if ( pos.non_pawn_material(WHITE) == BishopValueMg
|
||||||
&& pos.non_pawn_material(BLACK) == BishopValueMg)
|
&& pos.non_pawn_material(BLACK) == BishopValueMg)
|
||||||
sf = more_than_one(pos.pieces(PAWN)) ? ScaleFactor(31) : ScaleFactor(9);
|
sf = more_than_one(pos.pieces(PAWN)) ? ScaleFactor(31) : ScaleFactor(9);
|
||||||
|
|
|
@ -51,7 +51,7 @@ namespace {
|
||||||
|
|
||||||
// pick_best() finds the best move in the range (begin, end) and moves it to
|
// pick_best() finds the best move in the range (begin, end) and moves it to
|
||||||
// the front. It's faster than sorting all the moves in advance when there
|
// the front. It's faster than sorting all the moves in advance when there
|
||||||
// are few moves e.g. the possible captures.
|
// are few moves, e.g., the possible captures.
|
||||||
Move pick_best(ExtMove* begin, ExtMove* end)
|
Move pick_best(ExtMove* begin, ExtMove* end)
|
||||||
{
|
{
|
||||||
std::swap(*begin, *std::max_element(begin, end));
|
std::swap(*begin, *std::max_element(begin, end));
|
||||||
|
@ -64,12 +64,12 @@ namespace {
|
||||||
/// Constructors of the MovePicker class. As arguments we pass information
|
/// Constructors of the MovePicker class. As arguments we pass information
|
||||||
/// to help it to return the (presumably) good moves first, to decide which
|
/// to help it to return the (presumably) good moves first, to decide which
|
||||||
/// moves to return (in the quiescence search, for instance, we only want to
|
/// moves to return (in the quiescence search, for instance, we only want to
|
||||||
/// search captures, promotions and some checks) and how important good move
|
/// search captures, promotions, and some checks) and how important good move
|
||||||
/// ordering is at the current node.
|
/// ordering is at the current node.
|
||||||
|
|
||||||
MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const HistoryStats& h,
|
MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const HistoryStats& h,
|
||||||
const CounterMovesStats& cmh, Move cm, Search::Stack* s)
|
const CounterMoveStats& cmh, Move cm, Search::Stack* s)
|
||||||
: pos(p), history(h), counterMovesHistory(&cmh), ss(s), countermove(cm), depth(d) {
|
: pos(p), history(h), counterMoveHistory(&cmh), ss(s), countermove(cm), depth(d) {
|
||||||
|
|
||||||
assert(d > DEPTH_ZERO);
|
assert(d > DEPTH_ZERO);
|
||||||
|
|
||||||
|
@ -80,7 +80,7 @@ MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const HistoryStats&
|
||||||
|
|
||||||
MovePicker::MovePicker(const Position& p, Move ttm, Depth d,
|
MovePicker::MovePicker(const Position& p, Move ttm, Depth d,
|
||||||
const HistoryStats& h, Square s)
|
const HistoryStats& h, Square s)
|
||||||
: pos(p), history(h), counterMovesHistory(nullptr) {
|
: pos(p), history(h), counterMoveHistory(nullptr) {
|
||||||
|
|
||||||
assert(d <= DEPTH_ZERO);
|
assert(d <= DEPTH_ZERO);
|
||||||
|
|
||||||
|
@ -105,7 +105,7 @@ MovePicker::MovePicker(const Position& p, Move ttm, Depth d,
|
||||||
}
|
}
|
||||||
|
|
||||||
MovePicker::MovePicker(const Position& p, Move ttm, const HistoryStats& h, Value th)
|
MovePicker::MovePicker(const Position& p, Move ttm, const HistoryStats& h, Value th)
|
||||||
: pos(p), history(h), counterMovesHistory(nullptr), threshold(th) {
|
: pos(p), history(h), counterMoveHistory(nullptr), threshold(th) {
|
||||||
|
|
||||||
assert(!pos.checkers());
|
assert(!pos.checkers());
|
||||||
|
|
||||||
|
@ -127,9 +127,9 @@ template<>
|
||||||
void MovePicker::score<CAPTURES>() {
|
void MovePicker::score<CAPTURES>() {
|
||||||
// Winning and equal captures in the main search are ordered by MVV, preferring
|
// Winning and equal captures in the main search are ordered by MVV, preferring
|
||||||
// captures near our home rank. Surprisingly, this appears to perform slightly
|
// captures near our home rank. Surprisingly, this appears to perform slightly
|
||||||
// better than SEE based move ordering: exchanging big pieces before capturing
|
// better than SEE-based move ordering: exchanging big pieces before capturing
|
||||||
// a hanging piece probably helps to reduce the subtree size.
|
// a hanging piece probably helps to reduce the subtree size.
|
||||||
// In main search we want to push captures with negative SEE values to the
|
// In the main search we want to push captures with negative SEE values to the
|
||||||
// badCaptures[] array, but instead of doing it now we delay until the move
|
// badCaptures[] array, but instead of doing it now we delay until the move
|
||||||
// has been picked up, saving some SEE calls in case we get a cutoff.
|
// has been picked up, saving some SEE calls in case we get a cutoff.
|
||||||
for (auto& m : *this)
|
for (auto& m : *this)
|
||||||
|
@ -142,14 +142,14 @@ void MovePicker::score<QUIETS>() {
|
||||||
|
|
||||||
for (auto& m : *this)
|
for (auto& m : *this)
|
||||||
m.value = history[pos.moved_piece(m)][to_sq(m)]
|
m.value = history[pos.moved_piece(m)][to_sq(m)]
|
||||||
+ (*counterMovesHistory)[pos.moved_piece(m)][to_sq(m)];
|
+ (*counterMoveHistory)[pos.moved_piece(m)][to_sq(m)];
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
void MovePicker::score<EVASIONS>() {
|
void MovePicker::score<EVASIONS>() {
|
||||||
// Try winning and equal captures captures ordered by MVV/LVA, then non-captures
|
// Try winning and equal captures ordered by MVV/LVA, then non-captures ordered
|
||||||
// ordered by history value, then bad-captures and quiet moves with a negative
|
// by history value, then bad captures and quiet moves with a negative SEE ordered
|
||||||
// SEE ordered by SEE value.
|
// by SEE value.
|
||||||
Value see;
|
Value see;
|
||||||
|
|
||||||
for (auto& m : *this)
|
for (auto& m : *this)
|
||||||
|
@ -164,7 +164,7 @@ void MovePicker::score<EVASIONS>() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// generate_next_stage() generates, scores and sorts the next bunch of moves,
|
/// generate_next_stage() generates, scores, and sorts the next bunch of moves
|
||||||
/// when there are no more moves to try for the current stage.
|
/// when there are no more moves to try for the current stage.
|
||||||
|
|
||||||
void MovePicker::generate_next_stage() {
|
void MovePicker::generate_next_stage() {
|
||||||
|
|
|
@ -65,10 +65,10 @@ private:
|
||||||
T table[PIECE_NB][SQUARE_NB];
|
T table[PIECE_NB][SQUARE_NB];
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef Stats<Move> MovesStats;
|
typedef Stats<Move> MoveStats;
|
||||||
typedef Stats<Value, false> HistoryStats;
|
typedef Stats<Value, false> HistoryStats;
|
||||||
typedef Stats<Value, true> CounterMovesStats;
|
typedef Stats<Value, true> CounterMoveStats;
|
||||||
typedef Stats<CounterMovesStats> CounterMovesHistoryStats;
|
typedef Stats<CounterMoveStats> CounterMoveHistoryStats;
|
||||||
|
|
||||||
|
|
||||||
/// MovePicker class is used to pick one pseudo legal move at a time from the
|
/// MovePicker class is used to pick one pseudo legal move at a time from the
|
||||||
|
@ -85,7 +85,7 @@ public:
|
||||||
|
|
||||||
MovePicker(const Position&, Move, Depth, const HistoryStats&, Square);
|
MovePicker(const Position&, Move, Depth, const HistoryStats&, Square);
|
||||||
MovePicker(const Position&, Move, const HistoryStats&, Value);
|
MovePicker(const Position&, Move, const HistoryStats&, Value);
|
||||||
MovePicker(const Position&, Move, Depth, const HistoryStats&, const CounterMovesStats&, Move, Search::Stack*);
|
MovePicker(const Position&, Move, Depth, const HistoryStats&, const CounterMoveStats&, Move, Search::Stack*);
|
||||||
|
|
||||||
Move next_move();
|
Move next_move();
|
||||||
|
|
||||||
|
@ -97,7 +97,7 @@ private:
|
||||||
|
|
||||||
const Position& pos;
|
const Position& pos;
|
||||||
const HistoryStats& history;
|
const HistoryStats& history;
|
||||||
const CounterMovesStats* counterMovesHistory;
|
const CounterMoveStats* counterMoveHistory;
|
||||||
Search::Stack* ss;
|
Search::Stack* ss;
|
||||||
Move countermove;
|
Move countermove;
|
||||||
Depth depth;
|
Depth depth;
|
||||||
|
|
|
@ -61,7 +61,7 @@ using namespace Search;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
// Different node types, used as template parameter
|
// Different node types, used as a template parameter
|
||||||
enum NodeType { Root, PV, NonPV };
|
enum NodeType { Root, PV, NonPV };
|
||||||
|
|
||||||
// Razoring and futility margin based on depth
|
// Razoring and futility margin based on depth
|
||||||
|
@ -76,7 +76,7 @@ namespace {
|
||||||
return Reductions[PvNode][i][std::min(d, 63 * ONE_PLY)][std::min(mn, 63)];
|
return Reductions[PvNode][i][std::min(d, 63 * ONE_PLY)][std::min(mn, 63)];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Skill struct is used to implement strength limiting
|
// Skill structure is used to implement strength limit
|
||||||
struct Skill {
|
struct Skill {
|
||||||
Skill(int l) : level(l) {}
|
Skill(int l) : level(l) {}
|
||||||
bool enabled() const { return level < 20; }
|
bool enabled() const { return level < 20; }
|
||||||
|
@ -88,8 +88,8 @@ namespace {
|
||||||
Move best = MOVE_NONE;
|
Move best = MOVE_NONE;
|
||||||
};
|
};
|
||||||
|
|
||||||
// EasyMoveManager struct is used to detect a so called 'easy move'; when PV is
|
// EasyMoveManager structure is used to detect an 'easy move'. When the PV is
|
||||||
// stable across multiple search iterations we can fast return the best move.
|
// stable across multiple search iterations, we can quickly return the best move.
|
||||||
struct EasyMoveManager {
|
struct EasyMoveManager {
|
||||||
|
|
||||||
void clear() {
|
void clear() {
|
||||||
|
@ -106,7 +106,7 @@ namespace {
|
||||||
|
|
||||||
assert(newPv.size() >= 3);
|
assert(newPv.size() >= 3);
|
||||||
|
|
||||||
// Keep track of how many times in a row 3rd ply remains stable
|
// Keep track of how many times in a row the 3rd ply remains stable
|
||||||
stableCnt = (newPv[2] == pv[2]) ? stableCnt + 1 : 0;
|
stableCnt = (newPv[2] == pv[2]) ? stableCnt + 1 : 0;
|
||||||
|
|
||||||
if (!std::equal(newPv.begin(), newPv.begin() + 3, pv))
|
if (!std::equal(newPv.begin(), newPv.begin() + 3, pv))
|
||||||
|
@ -129,7 +129,7 @@ namespace {
|
||||||
|
|
||||||
EasyMoveManager EasyMove;
|
EasyMoveManager EasyMove;
|
||||||
Value DrawValue[COLOR_NB];
|
Value DrawValue[COLOR_NB];
|
||||||
CounterMovesHistoryStats CounterMovesHistory;
|
CounterMoveHistoryStats CounterMoveHistory;
|
||||||
|
|
||||||
template <NodeType NT>
|
template <NodeType NT>
|
||||||
Value search(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth, bool cutNode);
|
Value search(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth, bool cutNode);
|
||||||
|
@ -175,12 +175,12 @@ void Search::init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Search::clear() resets to zero search state, to obtain reproducible results
|
/// Search::clear() resets search state to zero, to obtain reproducible results
|
||||||
|
|
||||||
void Search::clear() {
|
void Search::clear() {
|
||||||
|
|
||||||
TT.clear();
|
TT.clear();
|
||||||
CounterMovesHistory.clear();
|
CounterMoveHistory.clear();
|
||||||
|
|
||||||
for (Thread* th : Threads)
|
for (Thread* th : Threads)
|
||||||
{
|
{
|
||||||
|
@ -193,7 +193,7 @@ void Search::clear() {
|
||||||
|
|
||||||
|
|
||||||
/// Search::perft() is our utility to verify move generation. All the leaf nodes
|
/// Search::perft() is our utility to verify move generation. All the leaf nodes
|
||||||
/// up to the given depth are generated and counted and the sum returned.
|
/// up to the given depth are generated and counted, and the sum is returned.
|
||||||
template<bool Root>
|
template<bool Root>
|
||||||
uint64_t Search::perft(Position& pos, Depth depth) {
|
uint64_t Search::perft(Position& pos, Depth depth) {
|
||||||
|
|
||||||
|
@ -223,8 +223,7 @@ template uint64_t Search::perft<true>(Position&, Depth);
|
||||||
|
|
||||||
|
|
||||||
/// MainThread::search() is called by the main thread when the program receives
|
/// MainThread::search() is called by the main thread when the program receives
|
||||||
/// the UCI 'go' command. It searches from root position and at the end prints
|
/// the UCI 'go' command. It searches from the root position and outputs the "bestmove".
|
||||||
/// the "bestmove" to output.
|
|
||||||
|
|
||||||
void MainThread::search() {
|
void MainThread::search() {
|
||||||
|
|
||||||
|
@ -260,8 +259,8 @@ void MainThread::search() {
|
||||||
if (TB::Cardinality >= rootPos.count<ALL_PIECES>(WHITE)
|
if (TB::Cardinality >= rootPos.count<ALL_PIECES>(WHITE)
|
||||||
+ rootPos.count<ALL_PIECES>(BLACK))
|
+ rootPos.count<ALL_PIECES>(BLACK))
|
||||||
{
|
{
|
||||||
// If the current root position is in the tablebases then RootMoves
|
// If the current root position is in the tablebases, then RootMoves
|
||||||
// contains only moves that preserve the draw or win.
|
// contains only moves that preserve the draw or the win.
|
||||||
TB::RootInTB = Tablebases::root_probe(rootPos, rootMoves, TB::Score);
|
TB::RootInTB = Tablebases::root_probe(rootPos, rootMoves, TB::Score);
|
||||||
|
|
||||||
if (TB::RootInTB)
|
if (TB::RootInTB)
|
||||||
|
@ -269,7 +268,7 @@ void MainThread::search() {
|
||||||
|
|
||||||
else // If DTZ tables are missing, use WDL tables as a fallback
|
else // If DTZ tables are missing, use WDL tables as a fallback
|
||||||
{
|
{
|
||||||
// Filter out moves that do not preserve a draw or win
|
// Filter out moves that do not preserve the draw or the win.
|
||||||
TB::RootInTB = Tablebases::root_probe_wdl(rootPos, rootMoves, TB::Score);
|
TB::RootInTB = Tablebases::root_probe_wdl(rootPos, rootMoves, TB::Score);
|
||||||
|
|
||||||
// Only probe during search if winning
|
// Only probe during search if winning
|
||||||
|
@ -304,7 +303,7 @@ void MainThread::search() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// When playing in 'nodes as time' mode, subtract the searched nodes from
|
// When playing in 'nodes as time' mode, subtract the searched nodes from
|
||||||
// the available ones before to exit.
|
// the available ones before exiting.
|
||||||
if (Limits.npmsec)
|
if (Limits.npmsec)
|
||||||
Time.availableNodes += Limits.inc[us] - Threads.nodes_searched();
|
Time.availableNodes += Limits.inc[us] - Threads.nodes_searched();
|
||||||
|
|
||||||
|
@ -356,7 +355,7 @@ void MainThread::search() {
|
||||||
|
|
||||||
// Thread::search() is the main iterative deepening loop. It calls search()
|
// Thread::search() is the main iterative deepening loop. It calls search()
|
||||||
// repeatedly with increasing depth until the allocated thinking time has been
|
// repeatedly with increasing depth until the allocated thinking time has been
|
||||||
// consumed, user stops the search, or the maximum search depth is reached.
|
// consumed, the user stops the search, or the maximum search depth is reached.
|
||||||
|
|
||||||
void Thread::search() {
|
void Thread::search() {
|
||||||
|
|
||||||
|
@ -390,11 +389,11 @@ void Thread::search() {
|
||||||
|
|
||||||
multiPV = std::min(multiPV, rootMoves.size());
|
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 the target depth is reached.
|
||||||
while (++rootDepth < DEPTH_MAX && !Signals.stop && (!Limits.depth || rootDepth <= Limits.depth))
|
while (++rootDepth < DEPTH_MAX && !Signals.stop && (!Limits.depth || rootDepth <= Limits.depth))
|
||||||
{
|
{
|
||||||
// Set up the new depth for the helper threads skipping in average each
|
// Set up the new depths for the helper threads skipping on average every
|
||||||
// 2nd ply (using a half density map similar to a Hadamard matrix).
|
// 2nd ply (using a half-density map similar to a Hadamard matrix).
|
||||||
if (!mainThread)
|
if (!mainThread)
|
||||||
{
|
{
|
||||||
int d = rootDepth + rootPos.game_ply();
|
int d = rootDepth + rootPos.game_ply();
|
||||||
|
@ -452,14 +451,14 @@ void Thread::search() {
|
||||||
// search the already searched PV lines are preserved.
|
// search the already searched PV lines are preserved.
|
||||||
std::stable_sort(rootMoves.begin() + PVIdx, rootMoves.end());
|
std::stable_sort(rootMoves.begin() + PVIdx, rootMoves.end());
|
||||||
|
|
||||||
// Write PV back to transposition table in case the relevant
|
// Write PV back to the transposition table in case the relevant
|
||||||
// entries have been overwritten during the search.
|
// entries have been overwritten during the search.
|
||||||
for (size_t i = 0; i <= PVIdx; ++i)
|
for (size_t i = 0; i <= PVIdx; ++i)
|
||||||
rootMoves[i].insert_pv_in_tt(rootPos);
|
rootMoves[i].insert_pv_in_tt(rootPos);
|
||||||
|
|
||||||
// If search has been stopped break immediately. Sorting and
|
// If search has been stopped, break immediately. Sorting and
|
||||||
// writing PV back to TT is safe because RootMoves is still
|
// writing PV back to TT is safe because RootMoves is still
|
||||||
// valid, although it refers to previous iteration.
|
// valid, although it refers to the previous iteration.
|
||||||
if (Signals.stop)
|
if (Signals.stop)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -536,8 +535,8 @@ void Thread::search() {
|
||||||
if (rootDepth > 4 * ONE_PLY && multiPV == 1)
|
if (rootDepth > 4 * ONE_PLY && multiPV == 1)
|
||||||
Time.pv_instability(mainThread->bestMoveChanges);
|
Time.pv_instability(mainThread->bestMoveChanges);
|
||||||
|
|
||||||
// Stop the search if only one legal move is available or all
|
// Stop the search if only one legal move is available, or if all
|
||||||
// of the available time has been used or we matched an easyMove
|
// of the available time has been used, or if we matched an easyMove
|
||||||
// from the previous search and just did a fast verification.
|
// from the previous search and just did a fast verification.
|
||||||
if ( rootMoves.size() == 1
|
if ( rootMoves.size() == 1
|
||||||
|| Time.elapsed() > Time.available() * ( 640 - 160 * !mainThread->failedLow
|
|| Time.elapsed() > Time.available() * ( 640 - 160 * !mainThread->failedLow
|
||||||
|
@ -610,7 +609,7 @@ namespace {
|
||||||
bestValue = -VALUE_INFINITE;
|
bestValue = -VALUE_INFINITE;
|
||||||
ss->ply = (ss-1)->ply + 1;
|
ss->ply = (ss-1)->ply + 1;
|
||||||
|
|
||||||
// Check for available remaining time
|
// Check for the available remaining time
|
||||||
if (thisThread->resetCalls.load(std::memory_order_relaxed))
|
if (thisThread->resetCalls.load(std::memory_order_relaxed))
|
||||||
{
|
{
|
||||||
thisThread->resetCalls = false;
|
thisThread->resetCalls = false;
|
||||||
|
@ -853,7 +852,7 @@ moves_loop: // When in check search starts from here
|
||||||
|
|
||||||
Square prevSq = to_sq((ss-1)->currentMove);
|
Square prevSq = to_sq((ss-1)->currentMove);
|
||||||
Move cm = thisThread->counterMoves[pos.piece_on(prevSq)][prevSq];
|
Move cm = thisThread->counterMoves[pos.piece_on(prevSq)][prevSq];
|
||||||
const CounterMovesStats& cmh = CounterMovesHistory[pos.piece_on(prevSq)][prevSq];
|
const CounterMoveStats& cmh = CounterMoveHistory[pos.piece_on(prevSq)][prevSq];
|
||||||
|
|
||||||
MovePicker mp(pos, ttMove, depth, thisThread->history, cmh, cm, ss);
|
MovePicker mp(pos, ttMove, depth, thisThread->history, cmh, cm, ss);
|
||||||
CheckInfo ci(pos);
|
CheckInfo ci(pos);
|
||||||
|
@ -1006,9 +1005,10 @@ moves_loop: // When in check search starts from here
|
||||||
+ cmh[pos.piece_on(to_sq(move))][to_sq(move)]) / 14980;
|
+ cmh[pos.piece_on(to_sq(move))][to_sq(move)]) / 14980;
|
||||||
r = std::max(DEPTH_ZERO, r - rDecrease * ONE_PLY);
|
r = std::max(DEPTH_ZERO, r - rDecrease * ONE_PLY);
|
||||||
|
|
||||||
// Decrease reduction for moves that escape a capture. Filter out castling
|
// Decrease reduction for moves that escape a capture. Filter out
|
||||||
// moves because are coded as "king captures rook" and break make_move().
|
// castling moves, because they are coded as "king captures rook" and
|
||||||
// Also use see() instead of see_sign() because destination square is empty.
|
// hence break make_move(). Also use see() instead of see_sign(),
|
||||||
|
// because the destination square is empty.
|
||||||
if ( r
|
if ( r
|
||||||
&& type_of(move) == NORMAL
|
&& type_of(move) == NORMAL
|
||||||
&& type_of(pos.piece_on(to_sq(move))) != PAWN
|
&& type_of(pos.piece_on(to_sq(move))) != PAWN
|
||||||
|
@ -1024,7 +1024,7 @@ moves_loop: // When in check search starts from here
|
||||||
else
|
else
|
||||||
doFullDepthSearch = !PvNode || moveCount > 1;
|
doFullDepthSearch = !PvNode || moveCount > 1;
|
||||||
|
|
||||||
// Step 16. Full depth search, when LMR is skipped or fails high
|
// Step 16. Full depth search when LMR is skipped or fails high
|
||||||
if (doFullDepthSearch)
|
if (doFullDepthSearch)
|
||||||
value = newDepth < ONE_PLY ?
|
value = newDepth < ONE_PLY ?
|
||||||
givesCheck ? -qsearch<NonPV, true>(pos, ss+1, -(alpha+1), -alpha, DEPTH_ZERO)
|
givesCheck ? -qsearch<NonPV, true>(pos, ss+1, -(alpha+1), -alpha, DEPTH_ZERO)
|
||||||
|
@ -1033,7 +1033,7 @@ moves_loop: // When in check search starts from here
|
||||||
|
|
||||||
// For PV nodes only, do a full PV search on the first move or after a fail
|
// For PV nodes only, do a full PV search on the first move or after a fail
|
||||||
// high (in the latter case search only if value < beta), otherwise let the
|
// high (in the latter case search only if value < beta), otherwise let the
|
||||||
// parent node fail low with value <= alpha and to try another move.
|
// parent node fail low with value <= alpha and try another move.
|
||||||
if (PvNode && (moveCount == 1 || (value > alpha && (RootNode || value < beta))))
|
if (PvNode && (moveCount == 1 || (value > alpha && (RootNode || value < beta))))
|
||||||
{
|
{
|
||||||
(ss+1)->pv = pv;
|
(ss+1)->pv = pv;
|
||||||
|
@ -1050,7 +1050,7 @@ moves_loop: // When in check search starts from here
|
||||||
|
|
||||||
assert(value > -VALUE_INFINITE && value < VALUE_INFINITE);
|
assert(value > -VALUE_INFINITE && value < VALUE_INFINITE);
|
||||||
|
|
||||||
// Step 18. Check for new best move
|
// Step 18. Check for a new best move
|
||||||
// Finished searching the move. If a stop occurred, the return value of
|
// Finished searching the move. If a stop occurred, the return value of
|
||||||
// the search cannot be trusted, and we return immediately without
|
// the search cannot be trusted, and we return immediately without
|
||||||
// updating best move, PV and TT.
|
// updating best move, PV and TT.
|
||||||
|
@ -1118,7 +1118,7 @@ moves_loop: // When in check search starts from here
|
||||||
quietsSearched[quietCount++] = move;
|
quietsSearched[quietCount++] = move;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Following condition would detect a stop only after move loop has been
|
// The following condition would detect a stop only after move loop has been
|
||||||
// completed. But in this case bestValue is valid because we have fully
|
// completed. But in this case bestValue is valid because we have fully
|
||||||
// searched our subtree, and we can anyhow save the result in TT.
|
// searched our subtree, and we can anyhow save the result in TT.
|
||||||
/*
|
/*
|
||||||
|
@ -1128,7 +1128,7 @@ moves_loop: // When in check search starts from here
|
||||||
|
|
||||||
// Step 20. Check for mate and stalemate
|
// Step 20. Check for mate and stalemate
|
||||||
// All legal moves have been searched and if there are no legal moves, it
|
// All legal moves have been searched and if there are no legal moves, it
|
||||||
// must be mate or stalemate. If we are in a singular extension search then
|
// must be a mate or a stalemate. If we are in a singular extension search then
|
||||||
// return a fail low score.
|
// return a fail low score.
|
||||||
if (!moveCount)
|
if (!moveCount)
|
||||||
bestValue = excludedMove ? alpha
|
bestValue = excludedMove ? alpha
|
||||||
|
@ -1148,7 +1148,7 @@ moves_loop: // When in check search starts from here
|
||||||
{
|
{
|
||||||
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];
|
CounterMoveStats& prevCmh = CounterMoveHistory[pos.piece_on(prevPrevSq)][prevPrevSq];
|
||||||
prevCmh.update(pos.piece_on(prevSq), prevSq, bonus);
|
prevCmh.update(pos.piece_on(prevSq), prevSq, bonus);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1334,7 +1334,7 @@ moves_loop: // When in check search starts from here
|
||||||
|
|
||||||
assert(value > -VALUE_INFINITE && value < VALUE_INFINITE);
|
assert(value > -VALUE_INFINITE && value < VALUE_INFINITE);
|
||||||
|
|
||||||
// Check for new best move
|
// Check for a new best move
|
||||||
if (value > bestValue)
|
if (value > bestValue)
|
||||||
{
|
{
|
||||||
bestValue = value;
|
bestValue = value;
|
||||||
|
@ -1425,7 +1425,7 @@ moves_loop: // When in check search starts from here
|
||||||
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];
|
CounterMoveStats& cmh = CounterMoveHistory[pos.piece_on(prevSq)][prevSq];
|
||||||
Thread* thisThread = pos.this_thread();
|
Thread* thisThread = pos.this_thread();
|
||||||
|
|
||||||
thisThread->history.update(pos.moved_piece(move), to_sq(move), bonus);
|
thisThread->history.update(pos.moved_piece(move), to_sq(move), bonus);
|
||||||
|
@ -1451,7 +1451,7 @@ moves_loop: // When in check search starts from here
|
||||||
&& 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];
|
CounterMoveStats& prevCmh = CounterMoveHistory[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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1472,8 +1472,8 @@ moves_loop: // When in check search starts from here
|
||||||
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 is deterministic and bigger for weaker levels, and one is
|
||||||
// then we choose the move with the resulting highest score.
|
// random. 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
|
||||||
|
@ -1603,7 +1603,7 @@ void RootMove::insert_pv_in_tt(Position& pos) {
|
||||||
|
|
||||||
|
|
||||||
/// RootMove::extract_ponder_from_tt() is called in case we have no ponder move
|
/// RootMove::extract_ponder_from_tt() is called in case we have no ponder move
|
||||||
/// before exiting the search, for instance in case we stop the search during a
|
/// before exiting the search, for instance, in case we stop the search during a
|
||||||
/// fail high at root. We try hard to have a ponder move to return to the GUI,
|
/// fail high at root. We try hard to have a ponder move to return to the GUI,
|
||||||
/// otherwise in case of 'ponder on' we have nothing to think on.
|
/// otherwise in case of 'ponder on' we have nothing to think on.
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
This file may be redistributed and/or modified without restrictions.
|
This file may be redistributed and/or modified without restrictions.
|
||||||
|
|
||||||
tbcore.c contains engine-independent routines of the tablebase probing code.
|
tbcore.c contains engine-independent routines of the tablebase probing code.
|
||||||
This file should not need to much adaptation to add tablebase probing to
|
This file should not need too much adaptation to add tablebase probing to
|
||||||
a particular engine, provided the engine is written in C or C++.
|
a particular engine, provided the engine is written in C or C++.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,7 @@ using namespace Search;
|
||||||
|
|
||||||
ThreadPool Threads; // Global object
|
ThreadPool Threads; // Global object
|
||||||
|
|
||||||
/// Thread constructor launch the thread and then wait until it goes to sleep
|
/// Thread constructor launches the thread and then waits until it goes to sleep
|
||||||
/// in idle_loop().
|
/// in idle_loop().
|
||||||
|
|
||||||
Thread::Thread() {
|
Thread::Thread() {
|
||||||
|
@ -48,7 +48,7 @@ Thread::Thread() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Thread destructor wait for thread termination before returning
|
/// Thread destructor waits for thread termination before returning
|
||||||
|
|
||||||
Thread::~Thread() {
|
Thread::~Thread() {
|
||||||
|
|
||||||
|
@ -60,7 +60,8 @@ Thread::~Thread() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Thread::wait_for_search_finished() wait on sleep condition until not searching
|
/// Thread::wait_for_search_finished() waits on sleep condition
|
||||||
|
/// until not searching
|
||||||
|
|
||||||
void Thread::wait_for_search_finished() {
|
void Thread::wait_for_search_finished() {
|
||||||
|
|
||||||
|
@ -69,7 +70,7 @@ void Thread::wait_for_search_finished() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Thread::wait() wait on sleep condition until condition is true
|
/// Thread::wait() waits on sleep condition until condition is true
|
||||||
|
|
||||||
void Thread::wait(std::atomic_bool& condition) {
|
void Thread::wait(std::atomic_bool& condition) {
|
||||||
|
|
||||||
|
@ -78,7 +79,7 @@ void Thread::wait(std::atomic_bool& condition) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Thread::start_searching() wake up the thread that will start the search
|
/// Thread::start_searching() wakes up the thread that will start the search
|
||||||
|
|
||||||
void Thread::start_searching(bool resume) {
|
void Thread::start_searching(bool resume) {
|
||||||
|
|
||||||
|
@ -115,7 +116,7 @@ void Thread::idle_loop() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// ThreadPool::init() create and launch requested threads, that will go
|
/// ThreadPool::init() creates and launches requested threads that will go
|
||||||
/// immediately to sleep. We cannot use a constructor because Threads is a
|
/// immediately to sleep. We cannot use a constructor because Threads is a
|
||||||
/// static object and we need a fully initialized engine at this point due to
|
/// static object and we need a fully initialized engine at this point due to
|
||||||
/// allocation of Endgames in the Thread constructor.
|
/// allocation of Endgames in the Thread constructor.
|
||||||
|
@ -127,9 +128,9 @@ void ThreadPool::init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// ThreadPool::exit() terminate threads before the program exits. Cannot be
|
/// ThreadPool::exit() terminates threads before the program exits. Cannot be
|
||||||
/// done in destructor because threads must be terminated before deleting any
|
/// done in destructor because threads must be terminated before deleting any
|
||||||
/// static objects, so while still in main().
|
/// static objects while still in main().
|
||||||
|
|
||||||
void ThreadPool::exit() {
|
void ThreadPool::exit() {
|
||||||
|
|
||||||
|
@ -156,7 +157,7 @@ void ThreadPool::read_uci_options() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// ThreadPool::nodes_searched() return the number of nodes searched
|
/// ThreadPool::nodes_searched() returns the number of nodes searched
|
||||||
|
|
||||||
int64_t ThreadPool::nodes_searched() {
|
int64_t ThreadPool::nodes_searched() {
|
||||||
|
|
||||||
|
@ -167,8 +168,8 @@ int64_t ThreadPool::nodes_searched() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// ThreadPool::start_thinking() wake up the main thread sleeping in idle_loop()
|
/// ThreadPool::start_thinking() wakes up the main thread sleeping in idle_loop()
|
||||||
/// and start a new search, then return immediately.
|
/// and starts a new search, then returns immediately.
|
||||||
|
|
||||||
void ThreadPool::start_thinking(const Position& pos, const LimitsType& limits,
|
void ThreadPool::start_thinking(const Position& pos, const LimitsType& limits,
|
||||||
StateStackPtr& states) {
|
StateStackPtr& states) {
|
||||||
|
|
|
@ -36,7 +36,7 @@
|
||||||
#include "thread_win32.h"
|
#include "thread_win32.h"
|
||||||
|
|
||||||
|
|
||||||
/// Thread struct keeps together all the thread related stuff. We also use
|
/// Thread struct keeps together all the thread-related stuff. We also use
|
||||||
/// per-thread pawn and material hash tables so that once we get a pointer to an
|
/// per-thread pawn and material hash tables so that once we get a pointer to an
|
||||||
/// entry its life time is unlimited and we don't have to care about someone
|
/// entry its life time is unlimited and we don't have to care about someone
|
||||||
/// changing the entry under our feet.
|
/// changing the entry under our feet.
|
||||||
|
@ -67,7 +67,7 @@ public:
|
||||||
Search::RootMoveVector rootMoves;
|
Search::RootMoveVector rootMoves;
|
||||||
Depth rootDepth;
|
Depth rootDepth;
|
||||||
HistoryStats history;
|
HistoryStats history;
|
||||||
MovesStats counterMoves;
|
MoveStats counterMoves;
|
||||||
Depth completedDepth;
|
Depth completedDepth;
|
||||||
std::atomic_bool resetCalls;
|
std::atomic_bool resetCalls;
|
||||||
};
|
};
|
||||||
|
@ -84,7 +84,7 @@ struct MainThread : public Thread {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/// ThreadPool struct handles all the threads related stuff like init, starting,
|
/// ThreadPool struct handles all the threads-related stuff like init, starting,
|
||||||
/// parking and, most importantly, launching a thread. All the access to threads
|
/// parking and, most importantly, launching a thread. All the access to threads
|
||||||
/// data is done through this class.
|
/// data is done through this class.
|
||||||
|
|
||||||
|
|
|
@ -25,11 +25,11 @@
|
||||||
/// relies on libwinpthread. Currently libwinpthread implements mutexes directly
|
/// relies on libwinpthread. Currently libwinpthread implements mutexes directly
|
||||||
/// on top of Windows semaphores. Semaphores, being kernel objects, require kernel
|
/// on top of Windows semaphores. Semaphores, being kernel objects, require kernel
|
||||||
/// mode transition in order to lock or unlock, which is very slow compared to
|
/// mode transition in order to lock or unlock, which is very slow compared to
|
||||||
/// interlocked operations (about 30% slower on bench test). To workaround this
|
/// interlocked operations (about 30% slower on bench test). To work around this
|
||||||
/// issue, we define our wrappers to the low level Win32 calls. We use critical
|
/// issue, we define our wrappers to the low level Win32 calls. We use critical
|
||||||
/// sections to support Windows XP and older versions. Unfortunately, cond_wait()
|
/// sections to support Windows XP and older versions. Unfortunately, cond_wait()
|
||||||
/// is racy between unlock() and WaitForSingleObject() but they have the same
|
/// is racy between unlock() and WaitForSingleObject() but they have the same
|
||||||
/// speed performance of SRW locks.
|
/// speed performance as the SRW locks.
|
||||||
|
|
||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
|
|
@ -40,7 +40,7 @@ namespace {
|
||||||
// move_importance() is a skew-logistic function based on naive statistical
|
// move_importance() is a skew-logistic function based on naive statistical
|
||||||
// analysis of "how many games are still undecided after n half-moves". Game
|
// analysis of "how many games are still undecided after n half-moves". Game
|
||||||
// is considered "undecided" as long as neither side has >275cp advantage.
|
// is considered "undecided" as long as neither side has >275cp advantage.
|
||||||
// Data was extracted from CCRL game database with some simple filtering criteria.
|
// Data was extracted from the CCRL game database with some simple filtering criteria.
|
||||||
|
|
||||||
double move_importance(int ply) {
|
double move_importance(int ply) {
|
||||||
|
|
||||||
|
@ -66,7 +66,7 @@ namespace {
|
||||||
double ratio1 = (TMaxRatio * moveImportance) / (TMaxRatio * moveImportance + otherMovesImportance);
|
double ratio1 = (TMaxRatio * moveImportance) / (TMaxRatio * moveImportance + otherMovesImportance);
|
||||||
double ratio2 = (moveImportance + TStealRatio * otherMovesImportance) / (moveImportance + otherMovesImportance);
|
double ratio2 = (moveImportance + TStealRatio * otherMovesImportance) / (moveImportance + otherMovesImportance);
|
||||||
|
|
||||||
return int(myTime * std::min(ratio1, ratio2)); // Intel C++ asks an explicit cast
|
return int(myTime * std::min(ratio1, ratio2)); // Intel C++ asks for an explicit cast
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
@ -91,7 +91,7 @@ void TimeManagement::init(Search::LimitsType& limits, Color us, int ply)
|
||||||
// If we have to play in 'nodes as time' mode, then convert from time
|
// If we have to play in 'nodes as time' mode, then convert from time
|
||||||
// to nodes, and use resulting values in time management formulas.
|
// to nodes, and use resulting values in time management formulas.
|
||||||
// WARNING: Given npms (nodes per millisecond) must be much lower then
|
// WARNING: Given npms (nodes per millisecond) must be much lower then
|
||||||
// real engine speed to avoid time losses.
|
// the real engine speed to avoid time losses.
|
||||||
if (npmsec)
|
if (npmsec)
|
||||||
{
|
{
|
||||||
if (!availableNodes) // Only once at game start
|
if (!availableNodes) // Only once at game start
|
||||||
|
|
Loading…
Add table
Reference in a new issue