@@ -77,8 +77,9 @@ private void StorePVinTT(Move[] pv, int depth)
7777 return ( 0 , Array . Empty < Move > ( ) ) ;
7878
7979 Color color = position . SideToMove ;
80+ bool isChecked = position . IsChecked ( color ) ;
8081 //should we try null move pruning?
81- if ( depth >= 2 && ! position . IsChecked ( color ) )
82+ if ( depth >= 2 && ! isChecked )
8283 {
8384 const int R = 2 ;
8485 //skip making a move
@@ -98,8 +99,13 @@ private void StorePVinTT(Move[] pv, int depth)
9899 {
99100 expandedNodes ++ ;
100101
101- //moves after the PV node are unlikely to raise alpha.
102- if ( expandedNodes > 1 && depth >= 3 && window . Width > 0 )
102+ //moves after the PV node are unlikely to raise alpha. skip those that appear clearly futile!
103+ int futilityMargin = ( int ) color * depth * 70 ;
104+ if ( expandedNodes > 1 && depth <= 4 && ! isChecked && ! window . Inside ( Evaluation . Evaluate ( child ) + futilityMargin , color ) && ! child . IsChecked ( child . SideToMove ) )
105+ continue ;
106+
107+ //moves after the PV node are unlikely to raise alpha. searching with a null-sized window can save a lot of nodes
108+ if ( expandedNodes > 1 && depth >= 3 )
103109 {
104110 //we can save a lot of nodes by searching with "null window" first, proving cheaply that the score is below alpha...
105111 SearchWindow nullWindow = window . GetLowerBound ( color ) ;
@@ -114,9 +120,7 @@ private void StorePVinTT(Move[] pv, int depth)
114120 {
115121 Transpositions . Store ( position . ZobristHash , depth , window , eval . Score , move ) ;
116122 //store the PV beginning with move, followed by the PV of the childnode
117- pv = new Move [ eval . PV . Length + 1 ] ;
118- pv [ 0 ] = move ;
119- Array . Copy ( eval . PV , 0 , pv , 1 , eval . PV . Length ) ;
123+ pv = Merge ( move , eval . PV ) ;
120124 //...and maybe get a beta cutoff
121125 if ( window . Cut ( eval . Score , color ) )
122126 {
@@ -136,6 +140,14 @@ private void StorePVinTT(Move[] pv, int depth)
136140 return ( window . GetScore ( color ) , pv ) ;
137141 }
138142
143+ private static Move [ ] Merge ( Move move , Move [ ] pv )
144+ {
145+ Move [ ] result = new Move [ pv . Length + 1 ] ;
146+ result [ 0 ] = move ;
147+ Array . Copy ( pv , 0 , result , 1 , pv . Length ) ;
148+ return result ;
149+ }
150+
139151 private int QEval ( Board position , SearchWindow window )
140152 {
141153 NodesVisited ++ ;
0 commit comments