Value refine_eval(const TTEntry* tte, Value defaultEval, int ply);
void update_history(const Position& pos, Move move, Depth depth, Move movesSearched[], int moveCount);
void update_killers(Move m, SearchStack& ss);
+ void update_gains(const Position& pos, Move move, Value before, Value after);
bool fail_high_ply_1();
int current_search_time();
tte = TT.retrieve(pos.get_key());
}
- // Evaluate the position statically
isCheck = pos.is_check();
- EvalInfo ei;
if (!isCheck)
{
+ // Update gain statistics of the previous move that lead
+ // us in this position.
+ EvalInfo ei;
ss[ply].eval = evaluate(pos, ei, threadID);
-
- // Store gain statistics
- Move m = ss[ply - 1].currentMove;
- if ( m != MOVE_NULL
- && pos.captured_piece() == NO_PIECE_TYPE
- && !move_is_castle(m)
- && !move_is_promotion(m))
- MG.store(pos.piece_on(move_to(m)), move_from(m), move_to(m), ss[ply - 1].eval, -ss[ply].eval);
-
+ update_gains(pos, ss[ply - 1].currentMove, ss[ply - 1].eval, ss[ply].eval);
}
// Initialize a MovePicker object for the current position, and prepare
Move ttMove, move;
Depth ext, newDepth;
Value bestValue, staticValue, nullValue, value, futilityValue, futilityValueScaled;
- bool isCheck, useFutilityPruning, singleEvasion, moveIsCheck, captureOrPromotion, dangerous;
+ bool isCheck, singleEvasion, moveIsCheck, captureOrPromotion, dangerous;
bool mateThreat = false;
int moveCount = 0;
futilityValue = staticValue = bestValue = value = -VALUE_INFINITE;
// Calculate depth dependant futility pruning parameters
const int FutilityMoveCountMargin = 3 + (1 << (3 * int(depth) / 8));
- const int FutilityValueMargin = 112 * bitScanReverse32(int(depth) * int(depth) / 2);
+ const int PostFutilityValueMargin = 112 * bitScanReverse32(int(depth) * int(depth) / 2);
// Evaluate the position statically
if (!isCheck)
}
ss[ply].eval = staticValue;
- futilityValue = staticValue + FutilityValueMargin;
+ futilityValue = staticValue + PostFutilityValueMargin; //FIXME: Remove me, only for split
staticValue = refine_eval(tte, staticValue, ply); // Enhance accuracy with TT value if possible
-
- // Store gain statistics
- Move m = ss[ply - 1].currentMove;
- if ( m != MOVE_NULL
- && pos.captured_piece() == NO_PIECE_TYPE
- && !move_is_castle(m)
- && !move_is_promotion(m))
- MG.store(pos.piece_on(move_to(m)), move_from(m), move_to(m), ss[ply - 1].eval, -ss[ply].eval);
+ update_gains(pos, ss[ply - 1].currentMove, ss[ply - 1].eval, ss[ply].eval);
}
// Post futility pruning
- if (staticValue - FutilityValueMargin >= beta)
- return (staticValue - FutilityValueMargin);
+ if (depth < SelectiveDepth && staticValue - PostFutilityValueMargin >= beta)
+ return (staticValue - PostFutilityValueMargin);
// Null move search
if ( allowNullmove
// to search all moves.
MovePicker mp = MovePicker(pos, ttMove, depth, H, &ss[ply]);
CheckInfo ci(pos);
- useFutilityPruning = depth < SelectiveDepth && !isCheck;
// Loop through all legal moves until no moves remain or a beta cutoff occurs
while ( bestValue < beta
// Update current move
movesSearched[moveCount++] = ss[ply].currentMove = move;
+ // Futility pruning for captures
+ Color them = opposite_color(pos.side_to_move());
+
+ if ( !isCheck
+ && newDepth < SelectiveDepth
+ && !dangerous
+ && pos.move_is_capture(move)
+ && !pos.move_is_check(move, ci)
+ && !move_is_promotion(move)
+ && move != ttMove
+ && !move_is_ep(move)
+ && (pos.type_of_piece_on(move_to(move)) != PAWN || !pos.pawn_is_passed(them, move_to(move)))) // Do not prune passed pawn captures
+ {
+ int preFutilityValueMargin = 0;
+
+ if (newDepth >= OnePly)
+ preFutilityValueMargin = 112 * bitScanReverse32(int(newDepth) * int(newDepth) / 2);
+
+ if (ss[ply].eval + pos.endgame_value_of_piece_on(move_to(move)) + preFutilityValueMargin + ei.futilityMargin + 90 < beta)
+ continue;
+ }
+
+
// Futility pruning
- if ( useFutilityPruning
+ if ( !isCheck
&& !dangerous
&& !captureOrPromotion
&& !move_is_castle(move)
continue;
// Value based pruning
- futilityValueScaled = futilityValue - moveCount * IncrementalFutilityMargin;
+ Depth predictedDepth = newDepth;
- if (futilityValueScaled < beta)
+ //FIXME HACK: awful code duplication
+ double red = 0.5 + ln(moveCount) * ln(depth / 2) / 3.0;
+ if (red >= 1.0)
+ predictedDepth -= int(floor(red * int(OnePly)));
+
+ if (predictedDepth < SelectiveDepth)
{
- if (futilityValueScaled > bestValue)
- bestValue = futilityValueScaled;
- continue;
+ int preFutilityValueMargin = 0;
+ if (predictedDepth >= OnePly)
+ preFutilityValueMargin = 112 * bitScanReverse32(int(predictedDepth) * int(predictedDepth) / 2);
+
+ preFutilityValueMargin += MG.retrieve(pos.piece_on(move_from(move)), move_from(move), move_to(move)) + 45;
+
+ futilityValueScaled = ss[ply].eval + preFutilityValueMargin - moveCount * IncrementalFutilityMargin;
+
+ if (futilityValueScaled < beta)
+ {
+ if (futilityValueScaled > bestValue)
+ bestValue = futilityValueScaled;
+ continue;
+ }
}
}
&& idle_thread_exists(threadID)
&& !AbortSearch
&& !thread_should_stop(threadID)
- && split(pos, ss, ply, &beta, &beta, &bestValue, futilityValue,
+ && split(pos, ss, ply, &beta, &beta, &bestValue, futilityValue, //FIXME: SMP & futilityValue
depth, &moveCount, &mp, threadID, false))
break;
}
if (!isCheck)
{
ss[ply].eval = staticValue;
- // Store gain statistics
- Move m = ss[ply - 1].currentMove;
- if ( m != MOVE_NULL
- && pos.captured_piece() == NO_PIECE_TYPE
- && !move_is_castle(m)
- && !move_is_promotion(m))
- MG.store(pos.piece_on(move_to(m)), move_from(m), move_to(m), ss[ply - 1].eval, -ss[ply].eval);
+ update_gains(pos, ss[ply - 1].currentMove, ss[ply - 1].eval, ss[ply].eval);
}
-
// Initialize "stand pat score", and return it immediately if it is
// at least beta.
bestValue = staticValue;
}
+ // update_gains() updates the gains table of a non-capture move given
+ // the static position evaluation before and after the move.
+
+ void update_gains(const Position& pos, Move m, Value before, Value after) {
+
+ if ( m != MOVE_NULL
+ && before != VALUE_NONE
+ && after != VALUE_NONE
+ && pos.captured_piece() == NO_PIECE_TYPE
+ && !move_is_castle(m)
+ && !move_is_promotion(m))
+ MG.store(pos.piece_on(move_to(m)), move_from(m), move_to(m), -(before + after));
+ }
+
+
// fail_high_ply_1() checks if some thread is currently resolving a fail
// high at ply 1 at the node below the first root node. This information
// is used for time management.