template <NodeType NT>
Value qsearch(Position& pos, SearchStack* ss, Value alpha, Value beta, Depth depth);
- template <bool PvNode>
- Depth extension(const Position& pos, Move m, bool captureOrPromotion, bool moveIsCheck, bool* dangerous);
-
bool check_is_dangerous(Position &pos, Move move, Value futilityBase, Value beta, Value *bValue);
bool connected_moves(const Position& pos, Move m1, Move m2);
Value value_to_tt(Value v, int ply);
return os;
}
+ // extension() decides whether a move should be searched with normal depth,
+ // or with extended depth. Certain classes of moves (checking moves, in
+ // particular) are searched with bigger depth than ordinary moves and in
+ // any case are marked as 'dangerous'. Note that also if a move is not
+ // extended, as example because the corresponding UCI option is set to zero,
+ // the move is marked as 'dangerous' so, at least, we avoid to prune it.
+ template <bool PvNode>
+ FORCE_INLINE Depth extension(const Position& pos, Move m, bool captureOrPromotion,
+ bool moveIsCheck, bool* dangerous) {
+ assert(m != MOVE_NONE);
+
+ Depth result = DEPTH_ZERO;
+ *dangerous = moveIsCheck;
+
+ if (moveIsCheck && pos.see_sign(m) >= 0)
+ result += CheckExtension[PvNode];
+
+ if (pos.type_of_piece_on(move_from(m)) == PAWN)
+ {
+ Color c = pos.side_to_move();
+ if (relative_rank(c, move_to(m)) == RANK_7)
+ {
+ result += PawnPushTo7thExtension[PvNode];
+ *dangerous = true;
+ }
+ if (pos.pawn_is_passed(c, move_to(m)))
+ {
+ result += PassedPawnExtension[PvNode];
+ *dangerous = true;
+ }
+ }
+
+ if ( captureOrPromotion
+ && pos.type_of_piece_on(move_to(m)) != PAWN
+ && ( pos.non_pawn_material(WHITE) + pos.non_pawn_material(BLACK)
+ - pos.midgame_value_of_piece_on(move_to(m)) == VALUE_ZERO)
+ && !move_is_special(m))
+ {
+ result += PawnEndgameExtension[PvNode];
+ *dangerous = true;
+ }
+
+ return Min(result, ONE_PLY);
+ }
+
} // namespace
if (StopRequest)
break;
- assert(value >= alpha);
-
// In case of failing high/low increase aspiration window and research,
// otherwise exit the fail high/low loop.
if (value >= beta)
Value refinedValue, nullValue, futilityBase, futilityValueScaled; // Non-PV specific
bool isPvMove, inCheck, singularExtensionNode, givesCheck, captureOrPromotion, dangerous;
int moveCount = 0, playedMoveCount = 0;
- int threadID = pos.thread();
+ Thread& thread = Threads[pos.thread()];
SplitPoint* sp = NULL;
refinedValue = bestValue = value = -VALUE_INFINITE;
ss->ply = (ss-1)->ply + 1;
// Used to send selDepth info to GUI
- if (PvNode && Threads[threadID].maxPly < ss->ply)
- Threads[threadID].maxPly = ss->ply;
+ if (PvNode && thread.maxPly < ss->ply)
+ thread.maxPly = ss->ply;
if (SpNode)
{
threatMove = sp->threatMove;
goto split_point_start;
}
- else if (RootNode)
- bestValue = alpha;
// Step 1. Initialize node and poll. Polling can abort search
ss->currentMove = ss->bestMove = threatMove = (ss+1)->excludedMove = MOVE_NONE;
(ss+1)->skipNullMove = false; (ss+1)->reduction = DEPTH_ZERO;
(ss+2)->killers[0] = (ss+2)->killers[1] = MOVE_NONE;
- if (threadID == 0 && ++NodesSincePoll > NodesBetweenPolls)
+ if (pos.thread() == 0 && ++NodesSincePoll > NodesBetweenPolls)
{
NodesSincePoll = 0;
poll(pos);
// Step 2. Check for aborted search and immediate draw
if (( StopRequest
- || Threads[threadID].cutoff_occurred()
- || pos.is_draw()
+ || pos.is_draw<false>()
|| ss->ply > PLY_MAX) && !RootNode)
return VALUE_DRAW;
// At PV nodes we check for exact scores, while at non-PV nodes we check for
// a fail high/low. Biggest advantage at probing at PV nodes is to have a
// smooth experience in analysis mode.
- if ( !RootNode
- && tte
- && (PvNode ? tte->depth() >= depth && tte->type() == VALUE_TYPE_EXACT
- : ok_to_use_TT(tte, depth, beta, ss->ply)))
+ if (tte && (PvNode ? tte->depth() >= depth && tte->type() == VALUE_TYPE_EXACT
+ : ok_to_use_TT(tte, depth, beta, ss->ply)))
{
TT.refresh(tte);
ss->bestMove = ttMove; // Can be MOVE_NONE
// Loop through all pseudo-legal moves until no moves remain or a beta cutoff occurs
while ( bestValue < beta
&& (move = mp.get_next_move()) != MOVE_NONE
- && !Threads[threadID].cutoff_occurred())
+ && !thread.cutoff_occurred())
{
assert(move_is_ok(move));
bool doFullDepthSearch = true;
alpha = SpNode ? sp->alpha : alpha;
- if ( depth >= 3 * ONE_PLY
+ if ( depth > 3 * ONE_PLY
&& !captureOrPromotion
&& !dangerous
&& !move_is_castle(move)
alpha = sp->alpha;
}
- if (value > bestValue && !(SpNode && Threads[threadID].cutoff_occurred()))
+ if (value > bestValue && !(SpNode && thread.cutoff_occurred()))
{
bestValue = value;
&& !SpNode
&& depth >= Threads.min_split_depth()
&& bestValue < beta
- && Threads.available_slave_exists(threadID)
+ && Threads.available_slave_exists(pos.thread())
&& !StopRequest
- && !Threads[threadID].cutoff_occurred())
+ && !thread.cutoff_occurred())
Threads.split<FakeSplit>(pos, ss, &alpha, beta, &bestValue, depth,
threatMove, moveCount, &mp, PvNode);
}
// Step 21. Update tables
// If the search is not aborted, update the transposition table,
// history counters, and killer moves.
- if (!SpNode && !StopRequest && !Threads[threadID].cutoff_occurred())
+ if (!SpNode && !StopRequest && !thread.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->is_slave[threadID] = false;
+ sp->is_slave[pos.thread()] = false;
sp->nodes += pos.nodes_searched();
lock_release(&(sp->lock));
}
ss->ply = (ss-1)->ply + 1;
// Check for an instant draw or maximum ply reached
- if (ss->ply > PLY_MAX || pos.is_draw())
+ if (pos.is_draw<true>() || ss->ply > PLY_MAX)
return VALUE_DRAW;
// Decide whether or not to include checks, this fixes also the type of
else
ss->eval = bestValue = evaluate(pos, evalMargin);
- update_gains(pos, (ss-1)->currentMove, (ss-1)->eval, ss->eval);
-
// Stand pat. Return immediately if static value is at least beta
if (bestValue >= beta)
{
// to search the moves. Because the depth is <= 0 here, only captures,
// queen promotions and checks (only if depth >= DEPTH_QS_CHECKS) will
// be generated.
- MovePicker mp(pos, ttMove, depth, H);
+ MovePicker mp(pos, ttMove, depth, H, move_to((ss-1)->currentMove));
CheckInfo ci(pos);
Bitboard pinned = pos.pinned_pieces(pos.side_to_move());
}
- // extension() decides whether a move should be searched with normal depth,
- // or with extended depth. Certain classes of moves (checking moves, in
- // particular) are searched with bigger depth than ordinary moves and in
- // any case are marked as 'dangerous'. Note that also if a move is not
- // extended, as example because the corresponding UCI option is set to zero,
- // the move is marked as 'dangerous' so, at least, we avoid to prune it.
- template <bool PvNode>
- Depth extension(const Position& pos, Move m, bool captureOrPromotion,
- bool moveIsCheck, bool* dangerous) {
-
- assert(m != MOVE_NONE);
-
- Depth result = DEPTH_ZERO;
- *dangerous = moveIsCheck;
-
- if (moveIsCheck && pos.see_sign(m) >= 0)
- result += CheckExtension[PvNode];
-
- if (pos.type_of_piece_on(move_from(m)) == PAWN)
- {
- Color c = pos.side_to_move();
- if (relative_rank(c, move_to(m)) == RANK_7)
- {
- result += PawnPushTo7thExtension[PvNode];
- *dangerous = true;
- }
- if (pos.pawn_is_passed(c, move_to(m)))
- {
- result += PassedPawnExtension[PvNode];
- *dangerous = true;
- }
- }
-
- if ( captureOrPromotion
- && pos.type_of_piece_on(move_to(m)) != PAWN
- && ( pos.non_pawn_material(WHITE) + pos.non_pawn_material(BLACK)
- - pos.midgame_value_of_piece_on(move_to(m)) == VALUE_ZERO)
- && !move_is_special(m))
- {
- result += PawnEndgameExtension[PvNode];
- *dangerous = true;
- }
-
- return Min(result, ONE_PLY);
- }
-
-
// connected_threat() tests whether it is safe to forward prune a move or if
// is somehow connected to the threat move returned by null search.
&& pos.move_is_pl(tte->move())
&& pos.pl_move_is_legal(tte->move(), pos.pinned_pieces(pos.side_to_move()))
&& ply < PLY_MAX
- && (!pos.is_draw() || ply < 2))
+ && (!pos.is_draw<false>() || ply < 2))
{
pv[ply] = tte->move();
pos.do_move(pv[ply++], *st++);