// Initialize
TT.new_search();
H.clear();
+ MG.clear();
init_ss_array(ss);
IterationInfo[1] = IterationInfoType(rml.get_move_score(0), rml.get_move_score(0));
Iteration = 1;
// 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
MG.store(pos.piece_on(move_to(m)), move_from(m), move_to(m), ss[ply - 1].eval, -ss[ply].eval);
}
+ // Post futility pruning
+ if (staticValue - PostFutilityValueMargin >= beta)
+ return (staticValue - PostFutilityValueMargin);
+
// Null move search
if ( allowNullmove
&& depth > OnePly
// Update current move
movesSearched[moveCount++] = ss[ply].currentMove = move;
+ // Futility pruning for captures
+ Color them = opposite_color(pos.side_to_move());
+
+ if ( useFutilityPruning
+ && !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
&& !dangerous
&& !captureOrPromotion
+ && !move_is_castle(move)
&& move != ttMove)
{
// Move count based pruning
continue;
// Value based pruning
- futilityValueScaled = futilityValue - moveCount * IncrementalFutilityMargin;
+ Depth predictedDepth = newDepth;
+
+ //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)));
+
+ 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)
{
&& 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;
}
Square mfrom, mto, tfrom, tto;
- // Prune if there isn't any threat move and
- // is not a castling move (common case).
- if (threat == MOVE_NONE && !move_is_castle(m))
+ // Prune if there isn't any threat move
+ if (threat == MOVE_NONE)
return true;
mfrom = move_from(m);
tfrom = move_from(threat);
tto = move_to(threat);
- // Case 1: Castling moves are never pruned
- if (move_is_castle(m))
- return false;
-
- // Case 2: Don't prune moves which move the threatened piece
+ // Case 1: Don't prune moves which move the threatened piece
if (mfrom == tto)
return false;
- // Case 3: If the threatened piece has value less than or equal to the
+ // Case 2: If the threatened piece has value less than or equal to the
// value of the threatening piece, don't prune move which defend it.
if ( pos.move_is_capture(threat)
&& ( pos.midgame_value_of_piece_on(tfrom) >= pos.midgame_value_of_piece_on(tto)
&& pos.move_attacks_square(m, tto))
return false;
- // Case 4: If the moving piece in the threatened move is a slider, don't
+ // Case 3: If the moving piece in the threatened move is a slider, don't
// prune safe moves which block its ray.
if ( piece_is_slider(pos.piece_on(tfrom))
&& bit_is_set(squares_between(tfrom, tto), mto)