/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
bool thread_should_stop(int threadID) const;
void wake_sleeping_threads();
void put_threads_to_sleep();
bool thread_should_stop(int threadID) const;
void wake_sleeping_threads();
void put_threads_to_sleep();
bool split(const Position& pos, SearchStack* ss, int ply, Value* alpha, const Value beta, Value* bestValue,
Depth depth, bool mateThreat, int* moves, MovePicker* mp, int master, bool pvNode);
private:
bool split(const Position& pos, SearchStack* ss, int ply, Value* alpha, const Value beta, Value* bestValue,
Depth depth, bool mateThreat, int* moves, MovePicker* mp, int master, bool pvNode);
private:
- int RootMoveNumber, SearchStartTime, MaxNodes, MaxDepth;
- int MaxSearchTime, AbsoluteMaxSearchTime, ExtraSearchTime, ExactMaxTime;
+ int SearchStartTime, MaxNodes, MaxDepth, MaxSearchTime;
+ int AbsoluteMaxSearchTime, ExtraSearchTime, ExactMaxTime;
bool UseTimeManagement, InfiniteSearch, PonderSearch, StopOnPonderhit;
bool UseTimeManagement, InfiniteSearch, PonderSearch, StopOnPonderhit;
- bool AbortSearch, Quit, AspirationFailLow;
-
- // Show current line?
- bool ShowCurrentLine;
+ bool FirstRootMove, AbortSearch, Quit, AspirationFailLow;
- Value root_search(Position& pos, SearchStack ss[], RootMoveList& rml, Value& oldAlpha, Value& beta);
+ Value root_search(Position& pos, SearchStack ss[], RootMoveList& rml, Value* alphaPtr, Value* betaPtr);
Value search_pv(Position& pos, SearchStack ss[], Value alpha, Value beta, Depth depth, int ply, int threadID);
Value search(Position& pos, SearchStack ss[], Value beta, Depth depth, int ply, bool allowNullmove, int threadID, Move excludedMove = MOVE_NONE);
Value qsearch(Position& pos, SearchStack ss[], Value alpha, Value beta, Depth depth, int ply, int threadID);
Value search_pv(Position& pos, SearchStack ss[], Value alpha, Value beta, Depth depth, int ply, int threadID);
Value search(Position& pos, SearchStack ss[], Value beta, Depth depth, int ply, bool allowNullmove, int threadID, Move excludedMove = MOVE_NONE);
Value qsearch(Position& pos, SearchStack ss[], Value alpha, Value beta, Depth depth, int ply, int threadID);
// Initialize global search variables
StopOnPonderhit = AbortSearch = Quit = AspirationFailLow = false;
// Initialize global search variables
StopOnPonderhit = AbortSearch = Quit = AspirationFailLow = false;
if (get_option_value_string("Book File") != OpeningBook.file_name())
OpeningBook.open(get_option_value_string("Book File"));
if (get_option_value_string("Book File") != OpeningBook.file_name())
OpeningBook.open(get_option_value_string("Book File"));
MinimumSplitDepth = get_option_value_int("Minimum Split Depth") * OnePly;
MaxThreadsPerSplitPoint = get_option_value_int("Maximum Number of Threads per Split Point");
MinimumSplitDepth = get_option_value_int("Minimum Split Depth") * OnePly;
MaxThreadsPerSplitPoint = get_option_value_int("Maximum Number of Threads per Split Point");
MultiPV = get_option_value_int("MultiPV");
Chess960 = get_option_value_bool("UCI_Chess960");
UseLogFile = get_option_value_bool("Use Search Log");
MultiPV = get_option_value_int("MultiPV");
Chess960 = get_option_value_bool("UCI_Chess960");
UseLogFile = get_option_value_bool("Use Search Log");
for (int i = 1; i < 64; i++) // i == depth (OnePly = 1)
for (int j = 1; j < 64; j++) // j == moveNumber
{
for (int i = 1; i < 64; i++) // i == depth (OnePly = 1)
for (int j = 1; j < 64; j++) // j == moveNumber
{
- double pvRed = 0.5 + log(double(i)) * log(double(j)) / 6.0;
- double nonPVRed = 0.5 + log(double(i)) * log(double(j)) / 3.0;
+ double pvRed = log(double(i)) * log(double(j)) / 3.0;
+ double nonPVRed = log(double(i)) * log(double(j)) / 1.5;
PVReductionMatrix[i][j] = (int8_t) ( pvRed >= 1.0 ? floor( pvRed * int(OnePly)) : 0);
NonPVReductionMatrix[i][j] = (int8_t) (nonPVRed >= 1.0 ? floor(nonPVRed * int(OnePly)) : 0);
}
PVReductionMatrix[i][j] = (int8_t) ( pvRed >= 1.0 ? floor( pvRed * int(OnePly)) : 0);
NonPVReductionMatrix[i][j] = (int8_t) (nonPVRed >= 1.0 ? floor(nonPVRed * int(OnePly)) : 0);
}
- // Search to the current depth, rml is updated and sorted
- value = root_search(p, ss, rml, alpha, beta);
+ // Search to the current depth, rml is updated and sorted, alpha and beta could change
+ value = root_search(p, ss, rml, &alpha, &beta);
// Write PV to transposition table, in case the relevant entries have
// been overwritten during the search.
// Write PV to transposition table, in case the relevant entries have
// been overwritten during the search.
// scheme, prints some information to the standard output and handles
// the fail low/high loops.
// scheme, prints some information to the standard output and handles
// the fail low/high loops.
- Value root_search(Position& pos, SearchStack ss[], RootMoveList& rml, Value& oldAlpha, Value& beta) {
+ Value root_search(Position& pos, SearchStack ss[], RootMoveList& rml, Value* alphaPtr, Value* betaPtr) {
bool isCheck, moveIsCheck, captureOrPromotion, dangerous;
bool isCheck, moveIsCheck, captureOrPromotion, dangerous;
isCheck = pos.is_check();
// Step 1. Initialize node and poll (omitted at root, but I can see no good reason for this, FIXME)
isCheck = pos.is_check();
// Step 1. Initialize node and poll (omitted at root, but I can see no good reason for this, FIXME)
// Step 10. Loop through all moves in the root move list
for (int i = 0; i < rml.move_count() && !AbortSearch; i++)
{
// Step 10. Loop through all moves in the root move list
for (int i = 0; i < rml.move_count() && !AbortSearch; i++)
{
print_pv_info(pos, ss, alpha, beta, value);
// Prepare for a research after a fail high, each time with a wider window
print_pv_info(pos, ss, alpha, beta, value);
// Prepare for a research after a fail high, each time with a wider window
rml.set_move_nodes(i, TM.nodes_searched() - nodes);
assert(value >= -VALUE_INFINITE && value <= VALUE_INFINITE);
rml.set_move_nodes(i, TM.nodes_searched() - nodes);
assert(value >= -VALUE_INFINITE && value <= VALUE_INFINITE);
// Print information to the standard output
print_pv_info(pos, ss, alpha, beta, value);
// Print information to the standard output
print_pv_info(pos, ss, alpha, beta, value);
// Initialize a MovePicker object for the current position
mateThreat = pos.has_mate_threat(opposite_color(pos.side_to_move()));
MovePicker mp = MovePicker(pos, ttMove, depth, H, &ss[ply]);
CheckInfo ci(pos);
// Initialize a MovePicker object for the current position
mateThreat = pos.has_mate_threat(opposite_color(pos.side_to_move()));
MovePicker mp = MovePicker(pos, ttMove, depth, H, &ss[ply]);
CheckInfo ci(pos);
if (tte && ok_to_use_TT(tte, depth, beta, ply))
{
if (tte && ok_to_use_TT(tte, depth, beta, ply))
{
ss[ply].currentMove = ttMove; // Can be MOVE_NONE
return value_from_tt(tte->value(), ply);
}
ss[ply].currentMove = ttMove; // Can be MOVE_NONE
return value_from_tt(tte->value(), ply);
}
// Step 7. Static null move pruning
// We're betting that the opponent doesn't have a move that will reduce
// Step 7. Static null move pruning
// We're betting that the opponent doesn't have a move that will reduce
- // the score by more than fuility_margin(depth) if we do a null move.
- if ( !isCheck
- && allowNullmove
- && depth < RazorDepth
- && refinedValue - futility_margin(depth, 0) >= beta)
+ // the score by more than futility_margin(depth) if we do a null move.
+ if ( allowNullmove
+ && depth < RazorDepth
+ && !isCheck
+ && !value_is_mate(beta)
+ && ok_to_do_nullmove(pos)
+ && refinedValue >= beta + futility_margin(depth, 0))
return refinedValue - futility_margin(depth, 0);
// Step 8. Null move search with verification search
return refinedValue - futility_margin(depth, 0);
// Step 8. Null move search with verification search
nullValue = -search(pos, ss, -(beta-1), depth-R*OnePly, ply+1, false, threadID);
pos.undo_null_move();
if (nullValue >= beta)
{
nullValue = -search(pos, ss, -(beta-1), depth-R*OnePly, ply+1, false, threadID);
pos.undo_null_move();
if (nullValue >= beta)
{
// Do zugzwang verification search
Value v = search(pos, ss, beta, depth-5*OnePly, ply, false, threadID);
if (v >= beta)
// Do zugzwang verification search
Value v = search(pos, ss, beta, depth-5*OnePly, ply, false, threadID);
if (v >= beta)
} else {
// The null move failed low, which means that we may be faced with
// some kind of threat. If the previous move was reduced, check if
} else {
// The null move failed low, which means that we may be faced with
// some kind of threat. If the previous move was reduced, check if
// Initialize a MovePicker object for the current position
MovePicker mp = MovePicker(pos, ttMove, depth, H, &ss[ply], beta);
CheckInfo ci(pos);
// Initialize a MovePicker object for the current position
MovePicker mp = MovePicker(pos, ttMove, depth, H, &ss[ply], beta);
CheckInfo ci(pos);
// Value based pruning
Depth predictedDepth = newDepth - nonpv_reduction(depth, moveCount); // We illogically ignore reduction condition depth >= 3*OnePly
futilityValueScaled = ss[ply].eval + futility_margin(predictedDepth, moveCount)
// Value based pruning
Depth predictedDepth = newDepth - nonpv_reduction(depth, moveCount); // We illogically ignore reduction condition depth >= 3*OnePly
futilityValueScaled = ss[ply].eval + futility_margin(predictedDepth, moveCount)
// Step 13. Make the move
pos.do_move(move, st, ci, moveIsCheck);
// Step 13. Make the move
pos.do_move(move, st, ci, moveIsCheck);
- // Step 14. Reduced search
- // if the move fails high will be re-searched at full depth.
+ // Step 14. Reduced search, if the move fails high
+ // will be re-searched at full depth.
// Step 20. Update tables
// If the search is not aborted, update the transposition table,
// Step 20. Update tables
// If the search is not aborted, update the transposition table,
// Initialize a MovePicker object for the current position, and prepare
// to search the moves. Because the depth is <= 0 here, only captures,
// Initialize a MovePicker object for the current position, and prepare
// to search the moves. Because the depth is <= 0 here, only captures,
enoughMaterial = pos.non_pawn_material(pos.side_to_move()) > RookValueMidgame;
futilityBase = staticValue + FutilityMarginQS + ei.futilityMargin[pos.side_to_move()];
enoughMaterial = pos.non_pawn_material(pos.side_to_move()) > RookValueMidgame;
futilityBase = staticValue + FutilityMarginQS + ei.futilityMargin[pos.side_to_move()];
&& !pos.move_is_capture(move)
&& pos.type_of_piece_on(move_from(move)) != KING
&& !pos.can_castle(pos.side_to_move());
&& !pos.move_is_capture(move)
&& pos.type_of_piece_on(move_from(move)) != KING
&& !pos.can_castle(pos.side_to_move());
// All legal moves have been searched. A special case: If we're in check
// and no legal moves were found, it is checkmate.
// All legal moves have been searched. A special case: If we're in check
// and no legal moves were found, it is checkmate.
// Value based pruning
Depth predictedDepth = newDepth - nonpv_reduction(sp->depth, moveCount);
futilityValueScaled = ss[sp->ply].eval + futility_margin(predictedDepth, moveCount)
// Value based pruning
Depth predictedDepth = newDepth - nonpv_reduction(sp->depth, moveCount);
futilityValueScaled = ss[sp->ply].eval + futility_margin(predictedDepth, moveCount)
cout << "info nodes " << TM.nodes_searched() << " nps " << nps()
<< " time " << t << " hashfull " << TT.full() << endl;
cout << "info nodes " << TM.nodes_searched() << " nps " << nps()
<< " time " << t << " hashfull " << TT.full() << endl;
-
- // We only support current line printing in single thread mode
- if (ShowCurrentLine && TM.active_threads() == 1)
- {
- cout << "info currline";
- for (int p = 0; p < ply; p++)
- cout << " " << ss[p].currentMove;
-
- cout << endl;
- }
// instead of wasting CPU time polling for work.
while (AllThreadsShouldSleep || threadID >= ActiveThreads)
{
// instead of wasting CPU time polling for work.
while (AllThreadsShouldSleep || threadID >= ActiveThreads)
{
// If this thread is the master of a split point and all threads have
// finished their work at this split point, return from the idle loop.
// If this thread is the master of a split point and all threads have
// finished their work at this split point, return from the idle loop.
+ // Because sp->cpus is decremented under lock protection,
+ // be sure sp->lock has been released before to proceed.
+ lock_grab(&(sp->lock));
+ lock_release(&(sp->lock));
+