namespace {
- // Different node types, used as template parameter
- enum NodeType { NonPV, PV };
-
- // Set to true to force running with one thread. Used for debugging.
+ // Set to true to force running with one thread. Used for debugging
const bool FakeSplit = false;
- // Lookup table to check if a Piece is a slider and its access function
- const bool Slidings[18] = { 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1 };
- inline bool piece_is_slider(Piece p) { return Slidings[p]; }
+ // Different node types, used as template parameter
+ enum NodeType { NonPV, PV };
// RootMove struct is used for moves at the root of the tree. For each root
// move, we store two scores, a node count, and a PV (really a refutation
// in the case of moves which fail low). Value pv_score is normally set at
// -VALUE_INFINITE for all non-pv moves, while non_pv_score is computed
// according to the order in which moves are returned by MovePicker.
-
struct RootMove {
RootMove();
Move pv[PLY_MAX_PLUS_2];
};
-
// RootMoveList struct is just a vector of RootMove objects,
// with an handful of methods above the standard ones.
-
struct RootMoveList : public std::vector<RootMove> {
typedef std::vector<RootMove> Base;
int bestMoveChanges;
};
+ // MovePickerExt template class extends MovePicker and allows to choose at compile
+ // time the proper moves source according to the type of node. In the default case
+ // we simply create and use a standard MovePicker object.
+ template<bool SpNode, bool Root> struct MovePickerExt : public MovePicker {
- // Overload operator<<() to make it easier to print moves in a coordinate
- // notation compatible with UCI protocol.
- std::ostream& operator<<(std::ostream& os, Move m) {
+ MovePickerExt(const Position& p, Move ttm, Depth d, const History& h, SearchStack* ss, Value b)
+ : MovePicker(p, ttm, d, h, ss, b) {}
- bool chess960 = (os.iword(0) != 0); // See set960()
- return os << move_to_uci(m, chess960);
- }
+ RootMoveList::iterator rm; // Dummy, needed to compile
+ };
+ // In case of a SpNode we use split point's shared MovePicker object as moves source
+ template<> struct MovePickerExt<true, false> : public MovePicker {
- // When formatting a move for std::cout we must know if we are in Chess960
- // or not. To keep using the handy operator<<() on the move the trick is to
- // embed this flag in the stream itself. Function-like named enum set960 is
- // used as a custom manipulator and the stream internal general-purpose array,
- // accessed through ios_base::iword(), is used to pass the flag to the move's
- // operator<<() that will read it to properly format castling moves.
- enum set960 {};
+ MovePickerExt(const Position& p, Move ttm, Depth d, const History& h, SearchStack* ss, Value b)
+ : MovePicker(p, ttm, d, h, ss, b), mp(ss->sp->mp) {}
- std::ostream& operator<< (std::ostream& os, const set960& f) {
+ Move get_next_move() { return mp->get_next_move(); }
- os.iword(0) = int(f);
- return os;
- }
+ RootMoveList::iterator rm; // Dummy, needed to compile
+ MovePicker* mp;
+ };
+
+ // In case of a Root node we use RootMoveList as moves source
+ template<> struct MovePickerExt<false, true> : public MovePicker {
+ MovePickerExt(const Position&, Move, Depth, const History&, SearchStack*, Value);
+ Move get_next_move();
- /// Adjustments
+ RootMoveList::iterator rm;
+ bool firstCall;
+ };
+
+
+ /// Constants
+
+ // Lookup table to check if a Piece is a slider and its access function
+ const bool Slidings[18] = { 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1 };
+ inline bool piece_is_slider(Piece p) { return Slidings[p]; }
// Step 6. Razoring
/// Namespace variables
- // Book
- Book OpeningBook;
-
// Root move list
RootMoveList Rml;
// Skill level adjustment
int SkillLevel;
bool SkillLevelEnabled;
- RKISS RK;
// Node counters, used only by thread[0] but try to keep in different cache
// lines (64 bytes each) from the heavy multi-thread read accessed variables.
void poll(const Position& pos);
void wait_for_stop_or_ponderhit();
+ // Overload operator<<() to make it easier to print moves in a coordinate
+ // notation compatible with UCI protocol.
+ std::ostream& operator<<(std::ostream& os, Move m) {
- // MovePickerExt is an extended MovePicker class used to choose at compile time
- // the proper move source according to the type of node.
- template<bool SpNode, bool Root> struct MovePickerExt;
-
- // In Root nodes use RootMoveList as source. Score and sort the root moves
- // before to search them.
- template<> struct MovePickerExt<false, true> : public MovePicker {
-
- MovePickerExt(const Position& p, Move ttm, Depth d, const History& h, SearchStack* ss, Value b)
- : MovePicker(p, ttm, d, h, ss, b), firstCall(true) {
- Move move;
- Value score = VALUE_ZERO;
-
- // Score root moves using standard ordering used in main search, the moves
- // are scored according to the order in which they are returned by MovePicker.
- // This is the second order score that is used to compare the moves when
- // the first orders pv_score of both moves are equal.
- while ((move = MovePicker::get_next_move()) != MOVE_NONE)
- for (rm = Rml.begin(); rm != Rml.end(); ++rm)
- if (rm->pv[0] == move)
- {
- rm->non_pv_score = score--;
- break;
- }
-
- Rml.sort();
- rm = Rml.begin();
- }
-
- Move get_next_move() {
-
- if (!firstCall)
- ++rm;
- else
- firstCall = false;
-
- return rm != Rml.end() ? rm->pv[0] : MOVE_NONE;
- }
-
- RootMoveList::iterator rm;
- bool firstCall;
- };
-
- // In SpNodes use split point's shared MovePicker object as move source
- template<> struct MovePickerExt<true, false> : public MovePicker {
-
- MovePickerExt(const Position& p, Move ttm, Depth d, const History& h, SearchStack* ss, Value b)
- : MovePicker(p, ttm, d, h, ss, b), mp(ss->sp->mp) {}
-
- Move get_next_move() { return mp->get_next_move(); }
-
- RootMoveList::iterator rm; // Dummy, needed to compile
- MovePicker* mp;
- };
+ bool chess960 = (os.iword(0) != 0); // See set960()
+ return os << move_to_uci(m, chess960);
+ }
- // Default case, create and use a MovePicker object as source
- template<> struct MovePickerExt<false, false> : public MovePicker {
+ // When formatting a move for std::cout we must know if we are in Chess960
+ // or not. To keep using the handy operator<<() on the move the trick is to
+ // embed this flag in the stream itself. Function-like named enum set960 is
+ // used as a custom manipulator and the stream internal general-purpose array,
+ // accessed through ios_base::iword(), is used to pass the flag to the move's
+ // operator<<() that will read it to properly format castling moves.
+ enum set960 {};
- MovePickerExt(const Position& p, Move ttm, Depth d, const History& h, SearchStack* ss, Value b)
- : MovePicker(p, ttm, d, h, ss, b) {}
+ std::ostream& operator<< (std::ostream& os, const set960& f) {
- RootMoveList::iterator rm; // Dummy, needed to compile
- };
+ os.iword(0) = int(f);
+ return os;
+ }
} // namespace
}
-/// perft() is our utility to verify move generation. All the legal moves up to
-/// given depth are generated and counted and the sum returned.
+/// 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.
int64_t perft(Position& pos, Depth depth) {
for (MoveStack* cur = mlist; cur != last; cur++)
{
m = cur->move;
- pos.do_move(m, st, ci, pos.move_is_check(m, ci));
+ pos.do_move(m, st, ci, pos.move_gives_check(m, ci));
sum += perft(pos, depth - ONE_PLY);
pos.undo_move(m);
}
bool think(Position& pos, const SearchLimits& limits, Move searchMoves[]) {
+ static Book book;
+
// Initialize global search-related variables
StopOnPonderhit = StopRequest = QuitRequest = AspirationFailLow = SendSearchedNodes = false;
NodesSincePoll = 0;
else
NodesBetweenPolls = 30000;
- // Look for a book move, only during games, not tests
- if (Limits.useTimeManagement() && Options["OwnBook"].value<bool>())
+ // Look for a book move
+ if (Options["OwnBook"].value<bool>())
{
- if (Options["Book File"].value<std::string>() != OpeningBook.name())
- OpeningBook.open(Options["Book File"].value<std::string>());
+ if (Options["Book File"].value<std::string>() != book.name())
+ book.open(Options["Book File"].value<std::string>());
- Move bookMove = OpeningBook.get_move(pos, Options["Best Book Move"].value<bool>());
+ Move bookMove = book.get_move(pos, Options["Best Book Move"].value<bool>());
if (bookMove != MOVE_NONE)
{
if (Limits.ponder)
// Read UCI options
UCIMultiPV = Options["MultiPV"].value<int>();
- SkillLevel = Options["Skill level"].value<int>();
+ SkillLevel = Options["Skill Level"].value<int>();
- ThreadsMgr.read_uci_options();
read_evaluation_uci_options(pos.side_to_move());
+ Threads.read_uci_options();
+
+ // If needed allocate pawn and material hash tables and adjust TT size
+ Threads.init_hash_tables();
+ TT.set_size(Options["Hash"].value<int>());
if (Options["Clear Hash"].value<bool>())
{
Options["Clear Hash"].set_value("false");
TT.clear();
}
- TT.set_size(Options["Hash"].value<int>());
// Do we have to play with skill handicap? In this case enable MultiPV that
// we will use behind the scenes to retrieve a set of possible moves.
MultiPV = (SkillLevelEnabled ? Max(UCIMultiPV, 4) : UCIMultiPV);
// Wake up needed threads and reset maxPly counter
- for (int i = 0; i < ThreadsMgr.active_threads(); i++)
+ for (int i = 0; i < Threads.size(); i++)
{
- ThreadsMgr[i].wake_up();
- ThreadsMgr[i].maxPly = 0;
+ Threads[i].wake_up();
+ Threads[i].maxPly = 0;
}
// Write to log file and keep it open to be accessed during the search
}
// This makes all the threads to go to sleep
- ThreadsMgr.set_active_threads(1);
+ Threads.set_size(1);
// If we are pondering or in infinite search, we shouldn't print the
// best move before we are told to do so.
if (Rml.size() == 0)
{
cout << "info depth 0 score "
- << value_to_uci(pos.is_check() ? -VALUE_MATE : VALUE_DRAW)
+ << value_to_uci(pos.in_check() ? -VALUE_MATE : VALUE_DRAW)
<< endl;
return MOVE_NONE;
// Retrieve max searched depth among threads
selDepth = 0;
- for (int i = 0; i < ThreadsMgr.active_threads(); i++)
- if (ThreadsMgr[i].maxPly > selDepth)
- selDepth = ThreadsMgr[i].maxPly;
+ for (int i = 0; i < Threads.size(); i++)
+ if (Threads[i].maxPly > selDepth)
+ selDepth = Threads[i].maxPly;
// Send PV line to GUI and to log file
for (int i = 0; i < Min(UCIMultiPV, (int)Rml.size()); i++)
assert(alpha >= -VALUE_INFINITE && alpha <= VALUE_INFINITE);
assert(beta > alpha && beta <= VALUE_INFINITE);
assert(PvNode || alpha == beta - 1);
- assert(pos.thread() >= 0 && pos.thread() < ThreadsMgr.active_threads());
+ assert(pos.thread() >= 0 && pos.thread() < Threads.size());
Move movesSearched[MAX_MOVES];
int64_t nodes;
ValueType vt;
Value bestValue, value, oldAlpha;
Value refinedValue, nullValue, futilityBase, futilityValueScaled; // Non-PV specific
- bool isPvMove, isCheck, singularExtensionNode, moveIsCheck, captureOrPromotion, dangerous, isBadCap;
+ bool isPvMove, inCheck, singularExtensionNode, givesCheck, captureOrPromotion, dangerous, isBadCap;
int moveCount = 0, playedMoveCount = 0;
int threadID = pos.thread();
SplitPoint* sp = NULL;
refinedValue = bestValue = value = -VALUE_INFINITE;
oldAlpha = alpha;
- isCheck = pos.is_check();
+ inCheck = pos.in_check();
ss->ply = (ss-1)->ply + 1;
// Used to send selDepth info to GUI
- if (PvNode && ThreadsMgr[threadID].maxPly < ss->ply)
- ThreadsMgr[threadID].maxPly = ss->ply;
+ if (PvNode && Threads[threadID].maxPly < ss->ply)
+ Threads[threadID].maxPly = ss->ply;
if (SpNode)
{
// Step 2. Check for aborted search and immediate draw
if (( StopRequest
- || ThreadsMgr.cutoff_at_splitpoint(threadID)
+ || Threads[threadID].cutoff_occurred()
|| pos.is_draw()
|| ss->ply > PLY_MAX) && !Root)
return VALUE_DRAW;
excludedMove = ss->excludedMove;
posKey = excludedMove ? pos.get_exclusion_key() : pos.get_key();
- tte = TT.retrieve(posKey);
+ tte = TT.probe(posKey);
ttMove = tte ? tte->move() : MOVE_NONE;
// At PV nodes we check for exact scores, while at non-PV nodes we check for
}
// Step 5. Evaluate the position statically and update parent's gain statistics
- if (isCheck)
+ if (inCheck)
ss->eval = ss->evalMargin = VALUE_NONE;
else if (tte)
{
// Step 6. Razoring (is omitted in PV nodes)
if ( !PvNode
&& depth < RazorDepth
- && !isCheck
+ && !inCheck
&& refinedValue + razor_margin(depth) < beta
&& ttMove == MOVE_NONE
&& abs(beta) < VALUE_MATE_IN_PLY_MAX
if ( !PvNode
&& !ss->skipNullMove
&& depth < RazorDepth
- && !isCheck
+ && !inCheck
&& refinedValue - futility_margin(depth, 0) >= beta
&& abs(beta) < VALUE_MATE_IN_PLY_MAX
&& pos.non_pawn_material(pos.side_to_move()))
if ( !PvNode
&& !ss->skipNullMove
&& depth > ONE_PLY
- && !isCheck
+ && !inCheck
&& refinedValue >= beta
&& abs(beta) < VALUE_MATE_IN_PLY_MAX
&& pos.non_pawn_material(pos.side_to_move()))
// Step 9. Internal iterative deepening
if ( depth >= IIDDepth[PvNode]
&& ttMove == MOVE_NONE
- && (PvNode || (!isCheck && ss->eval + IIDMargin >= beta)))
+ && (PvNode || (!inCheck && ss->eval + IIDMargin >= beta)))
{
Depth d = (PvNode ? depth - 2 * ONE_PLY : depth / 2);
ss->skipNullMove = false;
ttMove = ss->bestMove;
- tte = TT.retrieve(posKey);
+ tte = TT.probe(posKey);
}
split_point_start: // At split points actual search starts from here
// Loop through all legal moves until no moves remain or a beta cutoff occurs
while ( bestValue < beta
&& (move = mp.get_next_move()) != MOVE_NONE
- && !ThreadsMgr.cutoff_at_splitpoint(threadID))
+ && !Threads[threadID].cutoff_occurred())
{
assert(move_is_ok(move));
// At Root and at first iteration do a PV search on all the moves to score root moves
isPvMove = (PvNode && moveCount <= (Root ? depth <= ONE_PLY ? 1000 : MultiPV : 1));
- moveIsCheck = pos.move_is_check(move, ci);
+ givesCheck = pos.move_gives_check(move, ci);
captureOrPromotion = pos.move_is_capture_or_promotion(move);
// Step 11. Decide the new search depth
- ext = extension<PvNode>(pos, move, captureOrPromotion, moveIsCheck, &dangerous);
+ ext = extension<PvNode>(pos, move, captureOrPromotion, givesCheck, &dangerous);
// Singular extension search. If all moves but one fail low on a search of
// (alpha-s, beta-s), and just one fails high on (alpha, beta), then that move
// Step 12. Futility pruning (is omitted in PV nodes)
if ( !PvNode
&& !captureOrPromotion
- && !isCheck
+ && !inCheck
&& !dangerous
&& move != ttMove
&& !move_is_castle(move))
&& pos.see_sign(move) < 0;
// Step 13. Make the move
- pos.do_move(move, st, ci, moveIsCheck);
+ pos.do_move(move, st, ci, givesCheck);
if (!SpNode && !captureOrPromotion)
movesSearched[playedMoveCount++] = move;
alpha = sp->alpha;
}
- if (value > bestValue && !(SpNode && ThreadsMgr.cutoff_at_splitpoint(threadID)))
+ if (value > bestValue && !(SpNode && Threads[threadID].cutoff_occurred()))
{
bestValue = value;
sp->alpha = value;
}
else if (SpNode)
- sp->betaCutoff = true;
+ sp->is_betaCutoff = true;
if (value == value_mate_in(ss->ply + 1))
ss->mateKiller = move;
// Step 18. Check for split
if ( !Root
&& !SpNode
- && depth >= ThreadsMgr.min_split_depth()
- && ThreadsMgr.active_threads() > 1
+ && depth >= Threads.min_split_depth()
&& bestValue < beta
- && ThreadsMgr.available_thread_exists(threadID)
+ && Threads.available_slave_exists(threadID)
&& !StopRequest
- && !ThreadsMgr.cutoff_at_splitpoint(threadID))
- ThreadsMgr.split<FakeSplit>(pos, ss, &alpha, beta, &bestValue, depth,
- threatMove, moveCount, &mp, PvNode);
+ && !Threads[threadID].cutoff_occurred())
+ Threads.split<FakeSplit>(pos, ss, &alpha, beta, &bestValue, depth,
+ threatMove, moveCount, &mp, PvNode);
}
// Step 19. Check for mate and stalemate
// no legal moves, it must be mate or stalemate.
// If one move was excluded return fail low score.
if (!SpNode && !moveCount)
- return excludedMove ? oldAlpha : isCheck ? value_mated_in(ss->ply) : VALUE_DRAW;
+ return excludedMove ? oldAlpha : inCheck ? value_mated_in(ss->ply) : VALUE_DRAW;
// Step 20. Update tables
// If the search is not aborted, update the transposition table,
// history counters, and killer moves.
- if (!SpNode && !StopRequest && !ThreadsMgr.cutoff_at_splitpoint(threadID))
+ if (!SpNode && !StopRequest && !Threads[threadID].cutoff_occurred())
{
move = bestValue <= oldAlpha ? MOVE_NONE : ss->bestMove;
vt = bestValue <= oldAlpha ? VALUE_TYPE_UPPER
if (SpNode)
{
// Here we have the lock still grabbed
- sp->slaves[threadID] = 0;
+ sp->is_slave[threadID] = false;
sp->nodes += pos.nodes_searched();
lock_release(&(sp->lock));
}
assert(beta >= -VALUE_INFINITE && beta <= VALUE_INFINITE);
assert(PvNode || alpha == beta - 1);
assert(depth <= 0);
- assert(pos.thread() >= 0 && pos.thread() < ThreadsMgr.active_threads());
+ assert(pos.thread() >= 0 && pos.thread() < Threads.size());
StateInfo st;
Move ttMove, move;
Value bestValue, value, evalMargin, futilityValue, futilityBase;
- bool isCheck, enoughMaterial, moveIsCheck, evasionPrunable;
+ bool inCheck, enoughMaterial, givesCheck, evasionPrunable;
const TTEntry* tte;
Depth ttDepth;
Value oldAlpha = alpha;
// Decide whether or not to include checks, this fixes also the type of
// TT entry depth that we are going to use. Note that in qsearch we use
// only two types of depth in TT: DEPTH_QS_CHECKS or DEPTH_QS_NO_CHECKS.
- isCheck = pos.is_check();
- ttDepth = (isCheck || depth >= DEPTH_QS_CHECKS ? DEPTH_QS_CHECKS : DEPTH_QS_NO_CHECKS);
+ inCheck = pos.in_check();
+ ttDepth = (inCheck || depth >= DEPTH_QS_CHECKS ? DEPTH_QS_CHECKS : DEPTH_QS_NO_CHECKS);
// Transposition table lookup. At PV nodes, we don't use the TT for
// pruning, but only for move ordering.
- tte = TT.retrieve(pos.get_key());
+ tte = TT.probe(pos.get_key());
ttMove = (tte ? tte->move() : MOVE_NONE);
if (!PvNode && tte && ok_to_use_TT(tte, ttDepth, beta, ss->ply))
}
// Evaluate the position statically
- if (isCheck)
+ if (inCheck)
{
bestValue = futilityBase = -VALUE_INFINITE;
ss->eval = evalMargin = VALUE_NONE;
{
assert(move_is_ok(move));
- moveIsCheck = pos.move_is_check(move, ci);
+ givesCheck = pos.move_gives_check(move, ci);
// Futility pruning
if ( !PvNode
- && !isCheck
- && !moveIsCheck
+ && !inCheck
+ && !givesCheck
&& move != ttMove
&& enoughMaterial
&& !move_is_promotion(move)
}
// Detect non-capture evasions that are candidate to be pruned
- evasionPrunable = isCheck
+ evasionPrunable = inCheck
&& bestValue > VALUE_MATED_IN_PLY_MAX
&& !pos.move_is_capture(move)
&& !pos.can_castle(pos.side_to_move());
// Don't search moves with negative SEE values
if ( !PvNode
- && (!isCheck || evasionPrunable)
+ && (!inCheck || evasionPrunable)
&& move != ttMove
&& !move_is_promotion(move)
&& pos.see_sign(move) < 0)
// Don't search useless checks
if ( !PvNode
- && !isCheck
- && moveIsCheck
+ && !inCheck
+ && givesCheck
&& move != ttMove
&& !pos.move_is_capture_or_promotion(move)
&& ss->eval + PawnValueMidgame / 4 < beta
ss->currentMove = move;
// Make and search the move
- pos.do_move(move, st, ci, moveIsCheck);
+ pos.do_move(move, st, ci, givesCheck);
value = -qsearch<PvNode>(pos, ss+1, -beta, -alpha, depth-ONE_PLY);
pos.undo_move(move);
// All legal moves have been searched. A special case: If we're in check
// and no legal moves were found, it is checkmate.
- if (isCheck && bestValue == -VALUE_INFINITE)
+ if (inCheck && bestValue == -VALUE_INFINITE)
return value_mated_in(ss->ply);
// Update transposition table
assert(move_is_ok(m));
assert(threat && move_is_ok(threat));
- assert(!pos.move_is_check(m));
+ assert(!pos.move_gives_check(m));
assert(!pos.move_is_capture_or_promotion(m));
assert(!pos.move_is_passed_pawn_push(m));
assert(MultiPV > 1);
+ static RKISS rk;
+
// Rml list is already sorted by pv_score in descending order
int s;
int max_s = -VALUE_INFINITE;
// PRNG sequence should be non deterministic
for (int i = abs(get_system_time() % 50); i > 0; i--)
- RK.rand<unsigned>();
+ rk.rand<unsigned>();
// Choose best move. For each move's score we add two terms both dependent
// on wk, one deterministic and bigger for weaker moves, and one random,
break;
// This is our magical formula
- s += ((max - s) * wk + var * (RK.rand<unsigned>() % wk)) / 128;
+ s += ((max - s) * wk + var * (rk.rand<unsigned>() % wk)) / 128;
if (s > max_s)
{
pos.do_move(pv[0], *st++);
- while ( (tte = TT.retrieve(pos.get_key())) != NULL
+ while ( (tte = TT.probe(pos.get_key())) != NULL
&& tte->move() != MOVE_NONE
&& pos.move_is_legal(tte->move())
&& ply < PLY_MAX
do {
k = pos.get_key();
- tte = TT.retrieve(k);
+ tte = TT.probe(k);
// Don't overwrite existing correct entries
if (!tte || tte->move() != pv[ply])
{
- v = (pos.is_check() ? VALUE_NONE : evaluate(pos, m));
+ v = (pos.in_check() ? VALUE_NONE : evaluate(pos, m));
TT.store(k, VALUE_NONE, VALUE_TYPE_NONE, DEPTH_NONE, pv[ply], v, m);
}
pos.do_move(pv[ply], *st++);
return s.str();
}
+ // Specializations for MovePickerExt in case of Root node
+ MovePickerExt<false, true>::MovePickerExt(const Position& p, Move ttm, Depth d,
+ const History& h, SearchStack* ss, Value b)
+ : MovePicker(p, ttm, d, h, ss, b), firstCall(true) {
+ Move move;
+ Value score = VALUE_ZERO;
+
+ // Score root moves using standard ordering used in main search, the moves
+ // are scored according to the order in which they are returned by MovePicker.
+ // This is the second order score that is used to compare the moves when
+ // the first orders pv_score of both moves are equal.
+ while ((move = MovePicker::get_next_move()) != MOVE_NONE)
+ for (rm = Rml.begin(); rm != Rml.end(); ++rm)
+ if (rm->pv[0] == move)
+ {
+ rm->non_pv_score = score--;
+ break;
+ }
+
+ Rml.sort();
+ rm = Rml.begin();
+ }
+
+ Move MovePickerExt<false, true>::get_next_move() {
+
+ if (!firstCall)
+ ++rm;
+ else
+ firstCall = false;
+
+ return rm != Rml.end() ? rm->pv[0] : MOVE_NONE;
+ }
+
} // namespace
if (allThreadsShouldExit)
{
assert(!sp);
- threads[threadID].state = THREAD_TERMINATED;
+ threads[threadID].state = Thread::TERMINATED;
return;
}
// If we are not thinking, wait for a condition to be signaled
// instead of wasting CPU time polling for work.
while ( threadID >= activeThreads
- || threads[threadID].state == THREAD_INITIALIZING
- || (useSleepingThreads && threads[threadID].state == THREAD_AVAILABLE))
+ || threads[threadID].state == Thread::INITIALIZING
+ || (useSleepingThreads && threads[threadID].state == Thread::AVAILABLE))
{
assert(!sp || useSleepingThreads);
assert(threadID != 0 || useSleepingThreads);
- if (threads[threadID].state == THREAD_INITIALIZING)
- threads[threadID].state = THREAD_AVAILABLE;
+ if (threads[threadID].state == Thread::INITIALIZING)
+ threads[threadID].state = Thread::AVAILABLE;
// Grab the lock to avoid races with Thread::wake_up()
lock_grab(&threads[threadID].sleepLock);
// If we are master and all slaves have finished do not go to sleep
- for (i = 0; sp && i < activeThreads && !sp->slaves[i]; i++) {}
+ for (i = 0; sp && i < activeThreads && !sp->is_slave[i]; i++) {}
allFinished = (i == activeThreads);
if (allFinished || allThreadsShouldExit)
}
// Do sleep here after retesting sleep conditions
- if (threadID >= activeThreads || threads[threadID].state == THREAD_AVAILABLE)
+ if (threadID >= activeThreads || threads[threadID].state == Thread::AVAILABLE)
cond_wait(&threads[threadID].sleepCond, &threads[threadID].sleepLock);
lock_release(&threads[threadID].sleepLock);
}
// If this thread has been assigned work, launch a search
- if (threads[threadID].state == THREAD_WORKISWAITING)
+ if (threads[threadID].state == Thread::WORKISWAITING)
{
assert(!allThreadsShouldExit);
- threads[threadID].state = THREAD_SEARCHING;
+ threads[threadID].state = Thread::SEARCHING;
// Copy split point position and search stack and call search()
// with SplitPoint template parameter set to true.
else
search<NonPV, true, false>(pos, ss+1, tsp->alpha, tsp->beta, tsp->depth);
- assert(threads[threadID].state == THREAD_SEARCHING);
+ assert(threads[threadID].state == Thread::SEARCHING);
- threads[threadID].state = THREAD_AVAILABLE;
+ threads[threadID].state = Thread::AVAILABLE;
// Wake up master thread so to allow it to return from the idle loop in
// case we are the last slave of the split point.
if ( useSleepingThreads
&& threadID != tsp->master
- && threads[tsp->master].state == THREAD_AVAILABLE)
+ && threads[tsp->master].state == Thread::AVAILABLE)
threads[tsp->master].wake_up();
}
// If this thread is the master of a split point and all slaves have
// finished their work at this split point, return from the idle loop.
- for (i = 0; sp && i < activeThreads && !sp->slaves[i]; i++) {}
+ for (i = 0; sp && i < activeThreads && !sp->is_slave[i]; i++) {}
allFinished = (i == activeThreads);
if (allFinished)
// In helpful master concept a master can help only a sub-tree, and
// because here is all finished is not possible master is booked.
- assert(threads[threadID].state == THREAD_AVAILABLE);
+ assert(threads[threadID].state == Thread::AVAILABLE);
- threads[threadID].state = THREAD_SEARCHING;
+ threads[threadID].state = Thread::SEARCHING;
return;
}
}