using Eval::evaluate;
using namespace Search;
+// For some reason argument-dependent lookup (ADL) doesn't work for Android's
+// STLPort, so explicitly qualify following functions.
+using std::count;
+using std::find;
+
namespace {
// Set to true to force running with one thread. Used for debugging
const Depth RazorDepth = 4 * ONE_PLY;
// Dynamic razoring margin based on depth
- inline Value razor_margin(Depth d) { return Value(0x200 + 0x10 * int(d)); }
+ inline Value razor_margin(Depth d) { return Value(512 + 16 * int(d)); }
// Maximum depth for use of dynamic threat detection when null move fails low
const Depth ThreatDepth = 5 * ONE_PLY;
// At Non-PV nodes we do an internal iterative deepening search
// when the static evaluation is bigger then beta - IIDMargin.
- const Value IIDMargin = Value(0x100);
+ const Value IIDMargin = Value(256);
// Minimum depth for use of singular extension
const Depth SingularExtensionDepth[] = { 8 * ONE_PLY, 6 * ONE_PLY };
// Futility margin for quiescence search
- const Value FutilityMarginQS = Value(0x80);
+ const Value FutilityMarginQS = Value(128);
// Futility lookup tables (initialized at startup) and their access functions
Value FutilityMargins[16][64]; // [depth][moveNumber]
// 'dangerous' moves so that we avoid to prune it.
FORCE_INLINE bool is_dangerous(const Position& pos, Move m, bool captureOrPromotion) {
- // Test for a pawn pushed to 7th or a passed pawn move
- if (type_of(pos.piece_moved(m)) == PAWN)
- {
- Color c = pos.side_to_move();
- if ( relative_rank(c, to_sq(m)) == RANK_7
- || pos.pawn_is_passed(c, to_sq(m)))
- return true;
- }
+ // Test for a passed pawn move
+ if ( type_of(pos.piece_moved(m)) == PAWN
+ && pos.pawn_is_passed(pos.side_to_move(), to_sq(m)))
+ return true;
// Test for a capture that triggers a pawn endgame
- if ( captureOrPromotion
- && type_of(pos.piece_on(to_sq(m))) != PAWN
+ if ( captureOrPromotion
+ && type_of(pos.piece_on(to_sq(m))) != PAWN
+ && type_of(m) == NORMAL
&& ( pos.non_pawn_material(WHITE) + pos.non_pawn_material(BLACK)
- - PieceValueMidgame[pos.piece_on(to_sq(m))] == VALUE_ZERO)
- && !is_special(m))
+ - PieceValueMidgame[pos.piece_on(to_sq(m))] == VALUE_ZERO))
return true;
return false;
StateInfo st;
int64_t cnt = 0;
- MoveList<MV_LEGAL> ml(pos);
+ MoveList<LEGAL> ml(pos);
// At the last ply just return the number of moves (leaf nodes)
if (depth == ONE_PLY)
TT.refresh(tte);
ss->currentMove = ttMove; // Can be MOVE_NONE
- if ( ttValue >= beta
- && ttMove
+ if ( ttValue >= beta
+ && ttMove
&& !pos.is_capture_or_promotion(ttMove)
- && ttMove != ss->killers[0])
+ && ttMove != ss->killers[0])
{
ss->killers[1] = ss->killers[0];
ss->killers[0] = ttMove;
// Update gain for the parent non-capture move given the static position
// evaluation before and after the move.
- if ( (move = (ss-1)->currentMove) != MOVE_NULL
- && (ss-1)->eval != VALUE_NONE
- && ss->eval != VALUE_NONE
+ if ( (move = (ss-1)->currentMove) != MOVE_NULL
+ && (ss-1)->eval != VALUE_NONE
+ && ss->eval != VALUE_NONE
&& !pos.captured_piece_type()
- && !is_special(move))
+ && type_of(move) == NORMAL)
{
Square to = to_sq(move);
H.update_gain(pos.piece_on(to), to, -(ss-1)->eval - ss->eval);
ss->currentMove = MOVE_NULL;
// Null move dynamic reduction based on depth
- int R = 3 + (depth >= 5 * ONE_PLY ? depth / 8 : 0);
+ Depth R = 3 * ONE_PLY + depth / 4;
// Null move dynamic reduction based on value
if (refinedValue - PawnValueMidgame > beta)
- R++;
+ R += ONE_PLY;
pos.do_null_move<true>(st);
(ss+1)->skipNullMove = true;
- nullValue = depth-R*ONE_PLY < ONE_PLY ? -qsearch<NonPV>(pos, ss+1, -beta, -alpha, DEPTH_ZERO)
- : - search<NonPV>(pos, ss+1, -beta, -alpha, depth-R*ONE_PLY);
+ nullValue = depth-R < ONE_PLY ? -qsearch<NonPV>(pos, ss+1, -beta, -alpha, DEPTH_ZERO)
+ : - search<NonPV>(pos, ss+1, -beta, -alpha, depth-R);
(ss+1)->skipNullMove = false;
pos.do_null_move<false>(st);
// Do verification search at high depths
ss->skipNullMove = true;
- Value v = search<NonPV>(pos, ss, alpha, beta, depth-R*ONE_PLY);
+ Value v = search<NonPV>(pos, ss, alpha, beta, depth-R);
ss->skipNullMove = false;
if (v >= beta)
futilityBase = ss->eval + ss->evalMargin;
singularExtensionNode = !RootNode
&& !SpNode
- && depth >= SingularExtensionDepth[PvNode]
- && ttMove != MOVE_NONE
+ && depth >= SingularExtensionDepth[PvNode]
+ && ttMove != MOVE_NONE
&& !excludedMove // Recursive singular search is not allowed
&& (tte->type() & BOUND_LOWER)
- && tte->depth() >= depth - 3 * ONE_PLY;
+ && tte->depth() >= depth - 3 * ONE_PLY;
// Step 11. Loop through moves
// Loop through all pseudo-legal moves until no moves remain or a beta cutoff occurs
- while ( bestValue < beta
+ while ( bestValue < beta
&& (move = mp.next_move()) != MOVE_NONE
&& !thisThread->cutoff_occurred()
&& !Signals.stop)
ext = ONE_PLY;
else if (givesCheck && pos.see_sign(move) >= 0)
- ext = PvNode ? ONE_PLY : ONE_PLY / 2;
+ ext = ONE_PLY / 2;
// 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
// is singular and should be extended. To verify this we do a reduced search
// on all the other moves but the ttMove, if result is lower than ttValue minus
// a margin then we extend ttMove.
- if ( singularExtensionNode
+ if ( singularExtensionNode
&& !ext
- && move == ttMove
- && pos.pl_move_is_legal(move, ci.pinned))
+ && move == ttMove
+ && pos.pl_move_is_legal(move, ci.pinned))
{
if (abs(ttValue) < VALUE_KNOWN_WIN)
{
&& !inCheck
&& !dangerous
&& move != ttMove
- && !is_castle(move)
+ && type_of(move) != CASTLE
&& (bestValue > VALUE_MATED_IN_MAX_PLY || bestValue == -VALUE_INFINITE))
{
// Move count based pruning
// Step 15. Reduced depth search (LMR). If the move fails high will be
// re-searched at full depth.
- if ( depth > 3 * ONE_PLY
+ if ( depth > 3 * ONE_PLY
&& !isPvMove
&& !captureOrPromotion
&& !dangerous
- && !is_castle(move)
+ && type_of(move) != CASTLE
&& ss->killers[0] != move
&& ss->killers[1] != move)
{
// Step 19. Check for split
if ( !SpNode
- && depth >= Threads.min_split_depth()
- && bestValue < beta
- && Threads.available_slave_exists(thisThread)
+ && depth >= Threads.min_split_depth()
+ && bestValue < beta
+ && Threads.available_slave_exists(thisThread)
&& !Signals.stop
&& !thisThread->cutoff_occurred())
bestValue = Threads.split<FakeSplit>(pos, ss, alpha, beta, bestValue, &bestMove,
&& !givesCheck
&& move != ttMove
&& enoughMaterial
- && !is_promotion(move)
+ && type_of(move) != PROMOTION
&& !pos.is_passed_pawn_push(move))
{
futilityValue = futilityBase
+ PieceValueEndgame[pos.piece_on(to_sq(move))]
- + (is_enpassant(move) ? PawnValueEndgame : VALUE_ZERO);
+ + (type_of(move) == ENPASSANT ? PawnValueEndgame : VALUE_ZERO);
if (futilityValue < beta)
{
// Detect non-capture evasions that are candidate to be pruned
evasionPrunable = !PvNode
- && inCheck
- && bestValue > VALUE_MATED_IN_MAX_PLY
+ && inCheck
+ && bestValue > VALUE_MATED_IN_MAX_PLY
&& !pos.is_capture(move)
&& !pos.can_castle(pos.side_to_move());
if ( !PvNode
&& (!inCheck || evasionPrunable)
&& move != ttMove
- && !is_promotion(move)
+ && type_of(move) != PROMOTION
&& pos.see_sign(move) < 0)
continue;
while (b)
{
// Note that here we generate illegal "double move"!
- if (futilityBase + PieceValueEndgame[pos.piece_on(pop_1st_bit(&b))] >= beta)
+ if (futilityBase + PieceValueEndgame[pos.piece_on(pop_lsb(&b))] >= beta)
return true;
}
assert(is_searching);
is_searching = false;
- sp->allSlavesRunning = false;
sp->slavesMask &= ~(1ULL << idx);
sp->nodes += pos.nodes_searched();
// 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 ( Threads.use_sleeping_threads()
- && this != sp->master
+ if ( Threads.use_sleeping_threads()
+ && this != sp->master
&& !sp->master->is_searching)
sp->master->wake_up();
// our feet by the sp master. Also accessing other Thread objects is
// unsafe because if we are exiting there is a chance are already freed.
lock_release(sp->lock);
-
- // Try to reparent to the first split point, with still all slaves
- // running, where we are available as a possible slave.
- for (int i = 0; i < Threads.size(); i++)
- {
- Thread* th = &Threads[i];
- int spCnt = th->splitPointsCnt;
- SplitPoint* latest = &th->splitPoints[spCnt ? spCnt - 1 : 0];
-
- if ( this->is_available_to(th)
- && spCnt > 0
- && !th->cutoff_occurred()
- && latest->allSlavesRunning
- && more_than_one(latest->slavesMask))
- {
- lock_grab(latest->lock);
- lock_grab(Threads.splitLock);
-
- // Retest all under lock protection, we are in the middle
- // of a race storm here !
- if ( this->is_available_to(th)
- && spCnt == th->splitPointsCnt
- && !th->cutoff_occurred()
- && latest->allSlavesRunning
- && more_than_one(latest->slavesMask))
- {
- latest->slavesMask |= 1ULL << idx;
- curSplitPoint = latest;
- is_searching = true;
- }
-
- lock_release(Threads.splitLock);
- lock_release(latest->lock);
-
- break; // Exit anyhow, only one try (enough in 99% of cases)
- }
- }
}
}
}