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
-*Copying.txt*
+*Copying.txt*.
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==========================="
<< "\nTotal time (ms) : " << elapsed
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
};
// which attack a square in the kingRing of the enemy king.
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
// weights of the individual piece types are given by the elements in the
// KingAttackWeights array.
const Score RookOnFile[2] = { S(19, 10), S(43, 21) };
// 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] = {
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
// 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] = {
{ 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
};
// 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) };
// Passed[mg/eg][Rank] contains midgame and endgame bonuses for passed pawns.
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.
template<Color Us>
&& (pos.pieces(PAWN) & (s + pawn_push(Us))))
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)
score -= BishopPawns * ei.pi->pawns_on_same_color_squares(Us, s);
if (ei.pi->semiopen_file(Us, 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)
{
Square ksq = pos.square<KING>(Us);
if (DoTrace)
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);
}
}
// 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)];
}
}
- // evaluate_threats() assigns bonuses according to the type of attacking piece
- // and the type of attacked one.
+ // evaluate_threats() assigns bonuses according to the types of the attacking
+ // and the attacked pieces.
template<Color Us, bool DoTrace>
Score evaluate_threats(const Position& pos, const EvalInfo& ei) {
// assign a smaller bonus if the block square isn't attacked.
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.
if (defendedSquares == squaresToQueen)
k += 6;
// 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.
Score evaluate_initiative(const Position& pos, int asymmetry, Value eg) {
if (pos.opposite_bishops())
{
// 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
&& pos.non_pawn_material(BLACK) == BishopValueMg)
sf = more_than_one(pos.pieces(PAWN)) ? ScaleFactor(31) : ScaleFactor(9);
// 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
- // are few moves e.g. the possible captures.
+ // are few moves, e.g., the possible captures.
Move pick_best(ExtMove* begin, ExtMove* end)
{
std::swap(*begin, *std::max_element(begin, end));
/// Constructors of the MovePicker class. As arguments we pass information
/// 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
-/// 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.
MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const HistoryStats& h,
- const CounterMovesStats& cmh, Move cm, Search::Stack* s)
- : pos(p), history(h), counterMovesHistory(&cmh), ss(s), countermove(cm), depth(d) {
+ const CounterMoveStats& cmh, Move cm, Search::Stack* s)
+ : pos(p), history(h), counterMoveHistory(&cmh), ss(s), countermove(cm), depth(d) {
assert(d > DEPTH_ZERO);
MovePicker::MovePicker(const Position& p, Move ttm, Depth d,
const HistoryStats& h, Square s)
- : pos(p), history(h), counterMovesHistory(nullptr) {
+ : pos(p), history(h), counterMoveHistory(nullptr) {
assert(d <= DEPTH_ZERO);
}
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());
void MovePicker::score<CAPTURES>() {
// Winning and equal captures in the main search are ordered by MVV, preferring
// 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.
- // 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
// has been picked up, saving some SEE calls in case we get a cutoff.
for (auto& m : *this)
for (auto& m : *this)
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<>
void MovePicker::score<EVASIONS>() {
- // Try winning and equal captures captures ordered by MVV/LVA, then non-captures
- // ordered by history value, then bad-captures and quiet moves with a negative
- // SEE ordered by SEE value.
+ // Try winning and equal captures ordered by MVV/LVA, then non-captures ordered
+ // by history value, then bad captures and quiet moves with a negative SEE ordered
+ // by SEE value.
Value see;
for (auto& m : *this)
}
-/// 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.
void MovePicker::generate_next_stage() {
T table[PIECE_NB][SQUARE_NB];
};
-typedef Stats<Move> MovesStats;
+typedef Stats<Move> MoveStats;
typedef Stats<Value, false> HistoryStats;
-typedef Stats<Value, true> CounterMovesStats;
-typedef Stats<CounterMovesStats> CounterMovesHistoryStats;
+typedef Stats<Value, true> CounterMoveStats;
+typedef Stats<CounterMoveStats> CounterMoveHistoryStats;
/// MovePicker class is used to pick one pseudo legal move at a time from the
MovePicker(const Position&, Move, Depth, const HistoryStats&, Square);
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();
const Position& pos;
const HistoryStats& history;
- const CounterMovesStats* counterMovesHistory;
+ const CounterMoveStats* counterMoveHistory;
Search::Stack* ss;
Move countermove;
Depth depth;
// Backward pawn penalty by opposed flag
const Score Backward[2] = { S(67, 42), S(49, 24) };
-
+
// Unsupported pawn penalty for pawns which are neither isolated or backward,
// by number of pawns it supports [less than 2 / exactly 2].
const Score Unsupported[2] = { S(20, 10), S(25, 15) };
// Connected pawn bonus by opposed, phalanx, twice supported and rank
Score Connected[2][2][2][RANK_NB];
-
+
// Doubled pawn penalty by file
const Score Doubled[FILE_NB] = {
S(13, 43), S(20, 48), S(23, 48), S(23, 48),
namespace {
- // Different node types, used as template parameter
+ // Different node types, used as a template parameter
enum NodeType { Root, PV, NonPV };
// Razoring and futility margin based on depth
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 {
Skill(int l) : level(l) {}
bool enabled() const { return level < 20; }
Move best = MOVE_NONE;
};
- // EasyMoveManager struct is used to detect a so called 'easy move'; when PV is
- // stable across multiple search iterations we can fast return the best move.
+ // EasyMoveManager structure is used to detect an 'easy move'. When the PV is
+ // stable across multiple search iterations, we can quickly return the best move.
struct EasyMoveManager {
void clear() {
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;
if (!std::equal(newPv.begin(), newPv.begin() + 3, pv))
EasyMoveManager EasyMove;
Value DrawValue[COLOR_NB];
- CounterMovesHistoryStats CounterMovesHistory;
+ CounterMoveHistoryStats CounterMoveHistory;
template <NodeType NT>
Value search(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth, bool cutNode);
}
-/// 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() {
TT.clear();
- CounterMovesHistory.clear();
+ CounterMoveHistory.clear();
for (Thread* th : Threads)
{
/// 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>
uint64_t Search::perft(Position& pos, Depth depth) {
/// 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 "bestmove" to output.
+/// the UCI 'go' command. It searches from the root position and outputs the "bestmove".
void MainThread::search() {
if (TB::Cardinality >= rootPos.count<ALL_PIECES>(WHITE)
+ rootPos.count<ALL_PIECES>(BLACK))
{
- // If the current root position is in the tablebases then RootMoves
- // contains only moves that preserve the draw or win.
+ // If the current root position is in the tablebases, then RootMoves
+ // contains only moves that preserve the draw or the win.
TB::RootInTB = Tablebases::root_probe(rootPos, rootMoves, TB::Score);
if (TB::RootInTB)
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);
// Only probe during search if winning
}
// 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)
Time.availableNodes += Limits.inc[us] - Threads.nodes_searched();
// Thread::search() is the main iterative deepening loop. It calls search()
// 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() {
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))
{
- // Set up the new depth for the helper threads skipping in average each
- // 2nd ply (using a half density map similar to a Hadamard matrix).
+ // 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).
if (!mainThread)
{
int d = rootDepth + rootPos.game_ply();
// search the already searched PV lines are preserved.
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.
for (size_t i = 0; i <= PVIdx; ++i)
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
- // valid, although it refers to previous iteration.
+ // valid, although it refers to the previous iteration.
if (Signals.stop)
break;
if (rootDepth > 4 * ONE_PLY && multiPV == 1)
Time.pv_instability(mainThread->bestMoveChanges);
- // Stop the search if only one legal move is available or all
- // of the available time has been used or we matched an easyMove
+ // Stop the search if only one legal move is available, or if all
+ // of the available time has been used, or if we matched an easyMove
// from the previous search and just did a fast verification.
if ( rootMoves.size() == 1
- || Time.elapsed() > Time.available() * ( 640 - 160 * !mainThread->failedLow
- - 126 * (bestValue >= mainThread->previousMoveScore)
+ || Time.elapsed() > Time.available() * ( 640 - 160 * !mainThread->failedLow
+ - 126 * (bestValue >= mainThread->previousMoveScore)
- 124 * (bestValue >= mainThread->previousMoveScore && !mainThread->failedLow))/640
|| ( mainThread->easyMovePlayed = ( rootMoves[0].pv[0] == easyMove
&& mainThread->bestMoveChanges < 0.03
bestValue = -VALUE_INFINITE;
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))
{
thisThread->resetCalls = false;
Square prevSq = to_sq((ss-1)->currentMove);
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);
CheckInfo ci(pos);
// Decrease reduction for moves with a good history and
// increase reduction for moves with a bad history
- int rDecrease = ( thisThread->history[pos.piece_on(to_sq(move))][to_sq(move)]
+ int rDecrease = ( thisThread->history[pos.piece_on(to_sq(move))][to_sq(move)]
+ cmh[pos.piece_on(to_sq(move))][to_sq(move)]) / 14980;
r = std::max(DEPTH_ZERO, r - rDecrease * ONE_PLY);
- // Decrease reduction for moves that escape a capture. Filter out castling
- // moves because are coded as "king captures rook" and break make_move().
- // Also use see() instead of see_sign() because destination square is empty.
+ // Decrease reduction for moves that escape a capture. Filter out
+ // castling moves, because they are coded as "king captures rook" and
+ // hence break make_move(). Also use see() instead of see_sign(),
+ // because the destination square is empty.
if ( r
&& type_of(move) == NORMAL
&& type_of(pos.piece_on(to_sq(move))) != PAWN
else
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)
value = newDepth < ONE_PLY ?
givesCheck ? -qsearch<NonPV, true>(pos, ss+1, -(alpha+1), -alpha, DEPTH_ZERO)
// 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
- // 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))))
{
(ss+1)->pv = pv;
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
// the search cannot be trusted, and we return immediately without
// updating best move, PV and TT.
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
// searched our subtree, and we can anyhow save the result in TT.
/*
// Step 20. Check for mate and stalemate
// 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.
if (!moveCount)
bestValue = excludedMove ? alpha
{
Value bonus = Value((depth / ONE_PLY) * (depth / ONE_PLY) + depth / ONE_PLY - 1);
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);
}
assert(value > -VALUE_INFINITE && value < VALUE_INFINITE);
- // Check for new best move
+ // Check for a new best move
if (value > bestValue)
{
bestValue = value;
Value bonus = Value((depth / ONE_PLY) * (depth / ONE_PLY) + depth / ONE_PLY - 1);
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();
thisThread->history.update(pos.moved_piece(move), to_sq(move), bonus);
&& is_ok((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);
}
}
int maxScore = -VALUE_INFINITE;
// 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,
- // then we choose the move with the resulting highest score.
+ // weakness. One is deterministic and bigger for weaker levels, and one is
+ // random. Then we choose the move with the resulting highest score.
for (size_t i = 0; i < multiPV; ++i)
{
// This is our magic formula
/// 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,
/// otherwise in case of 'ponder on' we have nothing to think on.
This file may be redistributed and/or modified without restrictions.
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++.
*/
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().
Thread::Thread() {
}
-/// Thread destructor wait for thread termination before returning
+/// Thread destructor waits for thread termination before returning
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() {
}
-/// 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) {
}
-/// 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) {
}
-/// 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
/// static object and we need a fully initialized engine at this point due to
/// allocation of Endgames in the Thread constructor.
}
-/// 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
-/// static objects, so while still in main().
+/// static objects while still in main().
void ThreadPool::exit() {
}
-/// ThreadPool::nodes_searched() return the number of nodes searched
+/// ThreadPool::nodes_searched() returns the number of nodes searched
int64_t ThreadPool::nodes_searched() {
}
-/// ThreadPool::start_thinking() wake up the main thread sleeping in idle_loop()
-/// and start a new search, then return immediately.
+/// ThreadPool::start_thinking() wakes up the main thread sleeping in idle_loop()
+/// and starts a new search, then returns immediately.
void ThreadPool::start_thinking(const Position& pos, const LimitsType& limits,
StateStackPtr& states) {
#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
/// entry its life time is unlimited and we don't have to care about someone
/// changing the entry under our feet.
Search::RootMoveVector rootMoves;
Depth rootDepth;
HistoryStats history;
- MovesStats counterMoves;
+ MoveStats counterMoves;
Depth completedDepth;
std::atomic_bool resetCalls;
};
};
-/// 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
/// data is done through this class.
/// relies on libwinpthread. Currently libwinpthread implements mutexes directly
/// 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
-/// 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
/// sections to support Windows XP and older versions. Unfortunately, cond_wait()
/// 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 <mutex>
// move_importance() is a skew-logistic function based on naive statistical
// analysis of "how many games are still undecided after n half-moves". Game
// 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 ratio1 = (TMaxRatio * moveImportance) / (TMaxRatio * 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
// If we have to play in 'nodes as time' mode, then convert from time
// to nodes, and use resulting values in time management formulas.
// 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 (!availableNodes) // Only once at game start