diff --git a/README.md b/README.md index 6b5e09a..e92aeb4 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,7 @@ IronPhoenix includes a modern alpha-beta search stack designed specifically for - Late Move Reductions (LMR) - Late Move Pruning (LMP) - Null Move Pruning (NMP) +- History Move Pruning (HMP) - Search pruning and reductions - Iterative deepening - Principal variation reporting diff --git a/src/search.cpp b/src/search.cpp index 096350d..b9766ff 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -18,6 +18,12 @@ namespace ironphoenix { constexpr int LMP_HISTORY_THRESHOLD = 2'000; + // History Move Pruning (HMP): only prune very poorly scoring quiet + // moves at shallow non-PV nodes. The threshold becomes more conservative + // with depth because deeper nodes deserve more tactical coverage. + constexpr int HISTORY_MOVE_PRUNE_MAX_DEPTH = 4; + constexpr int HISTORY_MOVE_PRUNE_MARGIN_PER_DEPTH = 1'500; + constexpr int NULL_MOVE_MIN_DEPTH = 2; constexpr int NULL_MOVE_DIVISOR = 190; constexpr std::size_t CHECK_BIT_WORDS = (MAX_MOVES + 63u) / 64u; @@ -642,6 +648,21 @@ namespace ironphoenix { continue; } + // History Move Pruning (HMP): prune quiet moves with strongly negative + // accumulated history before they consume a search. Keep it shallow, + // protect the first legal move, and never prune tactical/special moves. + if (!pvNode + && !inCheckNode + && depth <= HISTORY_MOVE_PRUNE_MAX_DEPTH + && legalMoves > 0 + && quiet + && move != ttMove + && !givesCheckMove + && !moveMateWindow + && lmrHistoryScore < -HISTORY_MOVE_PRUNE_MARGIN_PER_DEPTH * depth) { + continue; + } + // Static Exchange Evaluation (SEE) Pruning: at non-PV nodes, if a // capture move is likely to lose material, skip it. This is only done // at shallow depths, since SEE is not always accurate in complex positions.