Value DrawValue[COLOR_NB];
HistoryStats History;
CounterMovesHistoryStats CounterMovesHistory;
- GainsStats Gains;
MovesStats Countermoves;
template <NodeType NT, bool SpNode>
}
+/// Search::reset() clears all search memory, to obtain reproducible search results
+
+void Search::reset () {
+
+ TT.clear();
+ History.clear();
+ CounterMovesHistory.clear();
+ Countermoves.clear();
+}
+
+
/// 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.
template<bool Root>
Move easyMove = EasyMove.get(pos.key());
EasyMove.clear();
- std::memset(ss-2, 0, 5 * sizeof(Stack));
+ std::memset(stack, 0, 5 * sizeof(Stack));
depth = DEPTH_ZERO;
BestMoveChanges = 0;
beta = VALUE_INFINITE;
TT.new_search();
- History.clear();
- CounterMovesHistory.clear();
- Gains.clear();
- Countermoves.clear();
size_t multiPV = Options["MultiPV"];
Skill skill(Options["Skill Level"]);
Depth extension, newDepth, predictedDepth;
Value bestValue, value, ttValue, eval, nullValue, futilityValue;
bool ttHit, inCheck, givesCheck, singularExtensionNode, improving;
- bool captureOrPromotion, dangerous, doFullDepthSearch;
+ bool captureOrPromotion, doFullDepthSearch;
int moveCount, quietCount;
// Step 1. Initialize node
goto moves_loop;
}
- moveCount = quietCount = 0;
+ moveCount = quietCount = ss->moveCount = 0;
bestValue = -VALUE_INFINITE;
ss->ply = (ss-1)->ply + 1;
}
}
- // Step 5. Evaluate the position statically and update parent's gain statistics
+ // Step 5. Evaluate the position statically
if (inCheck)
{
ss->staticEval = eval = VALUE_NONE;
if (ss->skipEarlyPruning)
goto moves_loop;
- if ( !pos.captured_piece_type()
- && ss->staticEval != VALUE_NONE
- && (ss-1)->staticEval != VALUE_NONE
- && (move = (ss-1)->currentMove) != MOVE_NULL
- && move != MOVE_NONE
- && type_of(move) == NORMAL)
- {
- Square to = to_sq(move);
- Gains.update(pos.piece_on(to), to, -(ss-1)->staticEval - ss->staticEval);
- }
-
// Step 6. Razoring (skipped when in check)
if ( !PvNode
&& depth < 4 * ONE_PLY
&& eval + razor_margin(depth) <= alpha
- && ttMove == MOVE_NONE
- && !pos.pawn_on_7th(pos.side_to_move()))
+ && ttMove == MOVE_NONE)
{
if ( depth <= ONE_PLY
&& eval + razor_margin(3 * ONE_PLY) <= alpha)
assert((ss-1)->currentMove != MOVE_NONE);
assert((ss-1)->currentMove != MOVE_NULL);
- MovePicker mp(pos, ttMove, History, CounterMovesHistory, pos.captured_piece_type());
+ MovePicker mp(pos, ttMove, History, CounterMovesHistory, PieceValue[MG][pos.captured_piece_type()]);
CheckInfo ci(pos);
while ((move = mp.next_move<false>()) != MOVE_NONE)
&& !ttMove
&& (PvNode || ss->staticEval + 256 >= beta))
{
- Depth d = 2 * (depth - 2 * ONE_PLY) - (PvNode ? DEPTH_ZERO : depth / 2);
+ Depth d = depth - 2 * ONE_PLY - (PvNode ? DEPTH_ZERO : depth / 4);
ss->skipEarlyPruning = true;
- search<PvNode ? PV : NonPV, false>(pos, ss, alpha, beta, d / 2, true);
+ search<PvNode ? PV : NonPV, false>(pos, ss, alpha, beta, d, true);
ss->skipEarlyPruning = false;
tte = TT.probe(posKey, ttHit);
if (!pos.legal(move, ci.pinned))
continue;
- moveCount = ++splitPoint->moveCount;
+ ss->moveCount = moveCount = ++splitPoint->moveCount;
splitPoint->spinlock.release();
}
else
- ++moveCount;
+ ss->moveCount = ++moveCount;
if (RootNode)
{
captureOrPromotion = pos.capture_or_promotion(move);
givesCheck = type_of(move) == NORMAL && !ci.dcCandidates
- ? ci.checkSq[type_of(pos.piece_on(from_sq(move)))] & to_sq(move)
+ ? ci.checkSquares[type_of(pos.piece_on(from_sq(move)))] & to_sq(move)
: pos.gives_check(move, ci);
- dangerous = givesCheck
- || type_of(move) != NORMAL
- || pos.advanced_pawn_push(move);
-
// Step 12. Extend checks
if (givesCheck && pos.see_sign(move) >= VALUE_ZERO)
extension = ONE_PLY;
if ( !RootNode
&& !captureOrPromotion
&& !inCheck
- && !dangerous
+ && !givesCheck
+ && !pos.advanced_pawn_push(move)
&& bestValue > VALUE_MATED_IN_MAX_PLY)
{
// Move count based pruning
// Futility pruning: parent node
if (predictedDepth < 7 * ONE_PLY)
{
- futilityValue = ss->staticEval + futility_margin(predictedDepth)
- + 128 + Gains[pos.moved_piece(move)][to_sq(move)];
+ futilityValue = ss->staticEval + futility_margin(predictedDepth) + 256;
if (futilityValue <= alpha)
{
// Check for legality just before making the move
if (!RootNode && !SpNode && !pos.legal(move, ci.pinned))
{
- moveCount--;
+ ss->moveCount = --moveCount;
continue;
}
[pos.piece_on(to_sq(move))][to_sq(move)] <= VALUE_ZERO))
ss->reduction += ONE_PLY;
- if (move == countermove)
+ if ( History[pos.piece_on(to_sq(move))][to_sq(move)] > VALUE_ZERO
+ && CounterMovesHistory[pos.piece_on(prevMoveSq)][prevMoveSq]
+ [pos.piece_on(to_sq(move))][to_sq(move)] > VALUE_ZERO)
ss->reduction = std::max(DEPTH_ZERO, ss->reduction - ONE_PLY);
// Decrease reduction for moves that escape a capture
value = -search<NonPV, false>(pos, ss+1, -(alpha+1), -alpha, d, true);
- // Re-search at intermediate depth if reduction is very high
- if (value > alpha && ss->reduction >= 4 * ONE_PLY)
- {
- Depth d2 = std::max(newDepth - 2 * ONE_PLY, ONE_PLY);
- value = -search<NonPV, false>(pos, ss+1, -(alpha+1), -alpha, d2, true);
- }
-
doFullDepthSearch = (value > alpha && ss->reduction != DEPTH_ZERO);
ss->reduction = DEPTH_ZERO;
}
assert(is_ok(move));
givesCheck = type_of(move) == NORMAL && !ci.dcCandidates
- ? ci.checkSq[type_of(pos.piece_on(from_sq(move)))] & to_sq(move)
+ ? ci.checkSquares[type_of(pos.piece_on(from_sq(move)))] & to_sq(move)
: pos.gives_check(move, ci);
// Futility pruning
cmh.update(pos.moved_piece(quiets[i]), to_sq(quiets[i]), -bonus);
}
- // Extra penalty for TT move in previous ply when it gets refuted
- if (is_ok((ss-2)->currentMove) && (ss-1)->currentMove == (ss-1)->ttMove)
+ // Extra penalty for PV move in previous ply when it gets refuted
+ if (is_ok((ss-2)->currentMove) && (ss-1)->moveCount == 1 && !pos.captured_piece_type())
{
Square prevPrevSq = to_sq((ss-2)->currentMove);
HistoryStats& ttMoveCmh = CounterMovesHistory[pos.piece_on(prevPrevSq)][prevPrevSq];
else
assert(false);
+ spinlock.acquire();
assert(searching);
searching = false;
// After releasing the lock we can't access any SplitPoint related data
// in a safe way because it could have been released under our feet by
// the sp master.
+ spinlock.release();
sp->spinlock.release();
// Try to late join to another split point if none of its slaves has