/*
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
void put_threads_to_sleep();
void idle_loop(int threadID, SplitPoint* waitSp);
bool split(const Position& pos, SearchStack* ss, int ply, Value* alpha, const Value beta, Value* bestValue,
void put_threads_to_sleep();
void idle_loop(int threadID, SplitPoint* waitSp);
bool split(const Position& pos, SearchStack* ss, int ply, Value* alpha, const Value beta, Value* bestValue,
- Depth depth, int* moves, MovePicker* mp, int master, bool pvNode);
+ Depth depth, bool mateThreat, int* moves, MovePicker* mp, int master, bool pvNode);
// Step 14. Reduced search
// Reduction lookup tables (initialized at startup) and their getter functions
// Step 14. Reduced search
// Reduction lookup tables (initialized at startup) and their getter functions
- int8_t PVReductionMatrix[64][64]; // [depth][moveNumber]
- int8_t NonPVReductionMatrix[64][64]; // [depth][moveNumber]
+ int8_t PVReductionMatrix[8][64][64]; // [depth][moveNumber]
+ int8_t NonPVReductionMatrix[8][64][64]; // [depth][moveNumber]
- inline Depth pv_reduction(Depth d, int mn) { return (Depth) PVReductionMatrix[Min(d / 2, 63)][Min(mn, 63)]; }
- inline Depth nonpv_reduction(Depth d, int mn) { return (Depth) NonPVReductionMatrix[Min(d / 2, 63)][Min(mn, 63)]; }
+ inline Depth pv_reduction(Depth d, int mn) { return (Depth) PVReductionMatrix[0][Min(d / 2, 63)][Min(mn, 63)]; }
+ inline Depth nonpv_reduction(Depth d, int mn) { return (Depth) NonPVReductionMatrix[0][Min(d / 2, 63)][Min(mn, 63)]; }
- 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;
+ 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;
-/// init_search() is called during startup. It initializes various lookup tables
-
-void init_search() {
+void init_reduction_tables(int8_t pvTable[64][64], int8_t nonPvTable[64][64], int pvInhib, int nonPvInhib)
+{
+ double pvBase = 1.001 - log(3.0) * log(16.0) / pvInhib;
+ double nonPvBase = 1.001 - log(3.0) * log(4.0) / nonPvInhib;
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;
- 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);
+ double pvRed = pvBase + log(double(i)) * log(double(j)) / pvInhib;
+ double nonPVRed = nonPvBase + log(double(i)) * log(double(j)) / nonPvInhib;
+
+ pvTable[i][j] = (int8_t) ( pvRed >= 1.0 ? floor( pvRed * int(OnePly)) : 0);
+ nonPvTable[i][j] = (int8_t) (nonPVRed >= 1.0 ? floor(nonPVRed * int(OnePly)) : 0);
+}
+
+// init_search() is called during startup. It initializes various lookup tables
+
+void init_search() {
+
+ for (int i = 0; i < 8; i++)
+ init_reduction_tables(PVReductionMatrix[i], NonPVReductionMatrix[i], 4.0 * pow(1.3, i), 2.0 * pow(1.3, i));
- // 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);
&& !AbortSearch
&& !TM.thread_should_stop(threadID)
&& TM.split(pos, ss, ply, &alpha, beta, &bestValue,
&& !AbortSearch
&& !TM.thread_should_stop(threadID)
&& TM.split(pos, ss, ply, &alpha, beta, &bestValue,
- depth, &moveCount, &mp, threadID, true))
+ depth, mateThreat, &moveCount, &mp, threadID, true))
Value rbeta = beta - razor_margin(depth);
Value v = qsearch(pos, ss, rbeta-1, rbeta, Depth(0), ply, threadID);
if (v < rbeta)
Value rbeta = beta - razor_margin(depth);
Value v = qsearch(pos, ss, rbeta-1, rbeta, Depth(0), ply, threadID);
if (v < rbeta)
// 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
&& !AbortSearch
&& !TM.thread_should_stop(threadID)
&& TM.split(pos, ss, ply, NULL, beta, &bestValue,
&& !AbortSearch
&& !TM.thread_should_stop(threadID)
&& TM.split(pos, ss, ply, NULL, beta, &bestValue,
- depth, &moveCount, &mp, threadID, false))
+ depth, mateThreat, &moveCount, &mp, threadID, false))
// splitting, we don't have to repeat all this work in sp_search(). We
// also don't need to store anything to the hash table here: This is taken
// care of after we return from the split point.
// splitting, we don't have to repeat all this work in sp_search(). We
// also don't need to store anything to the hash table here: This is taken
// care of after we return from the split point.
- ext = extension(pos, move, false, captureOrPromotion, moveIsCheck, false, false, &dangerous);
+ ext = extension(pos, move, false, captureOrPromotion, moveIsCheck, false, sp->mateThreat, &dangerous);
// don't have to repeat all this work in sp_search_pv(). We also don't
// need to store anything to the hash table here: This is taken care of
// after we return from the split point.
// don't have to repeat all this work in sp_search_pv(). We also don't
// need to store anything to the hash table here: This is taken care of
// after we return from the split point.
- ext = extension(pos, move, true, captureOrPromotion, moveIsCheck, false, false, &dangerous);
+ ext = extension(pos, move, true, captureOrPromotion, moveIsCheck, false, sp->mateThreat, &dangerous);
bool ThreadsManager::split(const Position& p, SearchStack* sstck, int ply,
Value* alpha, const Value beta, Value* bestValue,
bool ThreadsManager::split(const Position& p, SearchStack* sstck, int ply,
Value* alpha, const Value beta, Value* bestValue,
- Depth depth, int* moves, MovePicker* mp, int master, bool pvNode) {
+ Depth depth, bool mateThreat, int* moves, MovePicker* mp, int master, bool pvNode) {