// better than the second best move.
const Value EasyMoveMargin = Value(0x200);
- // Last seconds noise filtering (LSN)
- const bool UseLSNFiltering = true;
- const int LSNTime = 100; // In milliseconds
- const Value LSNValue = value_from_centipawns(200);
- bool loseOnTime = false;
-
/// Global variables
bool connected_moves(const Position& pos, Move m1, Move m2);
bool value_is_mate(Value value);
+ Value value_to_tt(Value v, int ply);
+ Value value_from_tt(Value v, int ply);
bool move_is_killer(Move m, SearchStack* ss);
bool ok_to_use_TT(const TTEntry* tte, Depth depth, Value beta, int ply);
bool connected_threat(const Position& pos, Move m, Move threat);
void update_gains(const Position& pos, Move move, Value before, Value after);
int current_search_time();
+ std::string value_to_uci(Value v);
int nps();
void poll();
void ponderhit();
// Init reductions array
for (hd = 1; hd < 64; hd++) for (mc = 1; mc < 64; mc++)
{
- double pvRed = log(double(hd)) * log(double(mc)) / 3.0;
- double nonPVRed = log(double(hd)) * log(double(mc)) / 1.5;
+ double pvRed = 0.33 + log(double(hd)) * log(double(mc)) / 4.5;
+ double nonPVRed = 0.33 + log(double(hd)) * log(double(mc)) / 2.25;
ReductionMatrix[PV][hd][mc] = (int8_t) ( pvRed >= 1.0 ? floor( pvRed * int(OnePly)) : 0);
ReductionMatrix[NonPV][hd][mc] = (int8_t) (nonPVRed >= 1.0 ? floor(nonPVRed * int(OnePly)) : 0);
}
void SearchStack::init() {
currentMove = threatMove = bestMove = MOVE_NONE;
- reduction = Depth(0);
- eval = VALUE_NONE;
}
// SearchStack::initKillers() initializes killers for a search stack entry
/// search-related global variables, and calls root_search(). It returns false
/// when a quit command is received during the search.
-bool think(const Position& pos, bool infinite, bool ponder, int side_to_move,
- int time[], int increment[], int movesToGo, int maxDepth,
- int maxNodes, int maxTime, Move searchMoves[]) {
+bool think(const Position& pos, bool infinite, bool ponder, int time[], int increment[],
+ int movesToGo, int maxDepth, int maxNodes, int maxTime, Move searchMoves[]) {
// Initialize global search variables
StopOnPonderhit = AbortSearch = Quit = AspirationFailLow = false;
}
}
- // Reset loseOnTime flag at the beginning of a new game
- if (button_was_pressed("New Game"))
- loseOnTime = false;
-
// Read UCI option values
TT.set_size(get_option_value_int("Hash"));
if (button_was_pressed("Clear Hash"))
TM.wake_sleeping_threads();
// Set thinking time
- int myTime = time[side_to_move];
- int myIncrement = increment[side_to_move];
+ int myTime = time[pos.side_to_move()];
+ int myIncrement = increment[pos.side_to_move()];
if (UseTimeManagement)
{
if (!movesToGo) // Sudden death time control
<< " increment: " << myIncrement
<< " moves to go: " << movesToGo << endl;
- // LSN filtering. Used only for developing purposes, disabled by default
- if ( UseLSNFiltering
- && loseOnTime)
- {
- // Step 2. If after last move we decided to lose on time, do it now!
- while (SearchStartTime + myTime + 1000 > get_system_time())
- /* wait here */;
- }
-
// We're ready to start thinking. Call the iterative deepening loop function
- Value v = id_loop(pos, searchMoves);
-
- if (UseLSNFiltering)
- {
- // Step 1. If this is sudden death game and our position is hopeless,
- // decide to lose on time.
- if ( !loseOnTime // If we already lost on time, go to step 3.
- && myTime < LSNTime
- && myIncrement == 0
- && movesToGo == 0
- && v < -LSNValue)
- {
- loseOnTime = true;
- }
- else if (loseOnTime)
- {
- // Step 3. Now after stepping over the time limit, reset flag for next match.
- loseOnTime = false;
- }
- }
+ id_loop(pos, searchMoves);
if (UseLogFile)
LogFile.close();
// so to output information also for iteration 1.
cout << "info depth " << 1
<< "\ninfo depth " << 1
- << " score " << value_to_string(rml.get_move_score(0))
+ << " score " << value_to_uci(rml.get_move_score(0))
<< " time " << current_search_time()
<< " nodes " << TM.nodes_searched()
<< " nps " << nps()
// Step 5. Evaluate the position statically
// At root we do this only to get reference value for child nodes
- if (!isCheck)
- ss->eval = evaluate(pos, ei);
+ ss->eval = isCheck ? VALUE_NONE : evaluate(pos, ei);
// Step 6. Razoring (omitted at root)
// Step 7. Static null move pruning (omitted at root)
for (int j = 0; j < Min(MultiPV, rml.move_count()); j++)
{
cout << "info multipv " << j + 1
- << " score " << value_to_string(rml.get_move_score(j))
+ << " score " << value_to_uci(rml.get_move_score(j))
<< " depth " << (j <= i ? Iteration : Iteration - 1)
<< " time " << current_search_time()
<< " nodes " << TM.nodes_searched()
refinedValue = refine_eval(tte, ss->eval, ply); // Enhance accuracy with TT value if possible
update_gains(pos, (ss-1)->currentMove, (ss-1)->eval, ss->eval);
}
+ else
+ ss->eval = VALUE_NONE;
// Step 6. Razoring (is omitted in PV nodes)
if ( !PvNode
if (nullValue >= value_mate_in(PLY_MAX))
nullValue = beta;
- // Do zugzwang verification search at high depths
if (depth < 6 * OnePly)
return nullValue;
+ // Do verification search at high depths
ss->skipNullMove = true;
- Value v = search<NonPV>(pos, ss, alpha, beta, depth-5*OnePly, ply);
+ Value v = search<NonPV>(pos, ss, alpha, beta, depth-R*OnePly, ply);
ss->skipNullMove = false;
if (v >= beta)
TM.incrementNodeCounter(pos.thread());
ss->bestMove = ss->currentMove = MOVE_NONE;
- ss->eval = VALUE_NONE;
// Check for an instant draw or maximum ply reached
if (pos.is_draw() || ply >= PLY_MAX - 1)
if (isCheck)
{
bestValue = futilityBase = -VALUE_INFINITE;
+ ss->eval = VALUE_NONE;
deepChecks = enoughMaterial = false;
}
else
}
- // value_is_mate() checks if the given value is a mate one
- // eventually compensated for the ply.
+ // value_is_mate() checks if the given value is a mate one eventually
+ // compensated for the ply.
bool value_is_mate(Value value) {
}
- // move_is_killer() checks if the given move is among the
- // killer moves of that ply.
+ // value_to_tt() adjusts a mate score from "plies to mate from the root" to
+ // "plies to mate from the current ply". Non-mate scores are unchanged.
+ // The function is called before storing a value to the transposition table.
+
+ Value value_to_tt(Value v, int ply) {
+
+ if (v >= value_mate_in(PLY_MAX))
+ return v + ply;
+
+ if (v <= value_mated_in(PLY_MAX))
+ return v - ply;
+
+ return v;
+ }
+
+
+ // value_from_tt() is the inverse of value_to_tt(): It adjusts a mate score from
+ // the transposition table to a mate score corrected for the current ply.
+
+ Value value_from_tt(Value v, int ply) {
+
+ if (v >= value_mate_in(PLY_MAX))
+ return v - ply;
+
+ if (v <= value_mated_in(PLY_MAX))
+ return v + ply;
+
+ return v;
+ }
+
+
+ // move_is_killer() checks if the given move is among the killer moves
bool move_is_killer(Move m, SearchStack* ss) {
}
+ // value_to_uci() converts a value to a string suitable for use with the UCI protocol
+
+ std::string value_to_uci(Value v) {
+
+ std::stringstream s;
+
+ if (abs(v) < VALUE_MATE - PLY_MAX * OnePly)
+ s << "cp " << int(v) * 100 / int(PawnValueMidgame); // Scale to pawn = 100
+ else
+ s << "mate " << (v > 0 ? (VALUE_MATE - v + 1) / 2 : -(VALUE_MATE + v) / 2 );
+
+ return s.str();
+ }
+
// nps() computes the current nodes/second count.
int nps() {
{
ss->excludedMove = MOVE_NONE;
ss->skipNullMove = false;
+ ss->reduction = Depth(0);
if (i < 3)
{
void print_pv_info(const Position& pos, Move pv[], Value alpha, Value beta, Value value) {
cout << "info depth " << Iteration
- << " score " << value_to_string(value)
+ << " score " << value_to_uci(value)
<< (value >= beta ? " lowerbound" : value <= alpha ? " upperbound" : "")
<< " time " << current_search_time()
<< " nodes " << TM.nodes_searched()
// Find a quick score for the move
init_ss_array(ss, PLY_MAX_PLUS_2);
+ ss[0].eval = VALUE_NONE;
+ ss[0].currentMove = cur->move;
pos.do_move(cur->move, st);
moves[count].move = cur->move;
moves[count].score = -qsearch<PV>(pos, ss+1, -VALUE_INFINITE, VALUE_INFINITE, Depth(0), 1);