11using System ;
2- using System . Collections . Generic ;
3- using System . Linq ;
42
53namespace MinimalChess
64{
@@ -16,7 +14,7 @@ public class IterativeSearch
1614 public bool Aborted => NodesVisited >= _maxNodes || _killSwitch . Get ( NodesVisited % QUERY_TC_FREQUENCY == 0 ) ;
1715 public bool GameOver => Evaluation . IsCheckmate ( Score ) ;
1816
19- Board _root = null ;
17+ Board _root ;
2018 KillerMoves _killers ;
2119 KillSwitch _killSwitch ;
2220 long _maxNodes ;
@@ -41,17 +39,9 @@ public void SearchDeeper(Func<bool> killSwitch = null)
4139
4240 Depth ++ ;
4341 _killers . Resize ( Depth ) ;
44- TriangularTable . Init ( Depth ) ;
4542 StorePVinTT ( PrincipalVariation , Depth ) ;
4643 _killSwitch = new KillSwitch ( killSwitch ) ;
47-
48- int score = EvalPosition ( _root , Depth , SearchWindow . Infinite ) ;
49-
50- if ( ! Aborted )
51- {
52- Score = score ;
53- PrincipalVariation = TriangularTable . GetLine ( Depth ) ;
54- }
44+ ( Score , PrincipalVariation ) = EvalPosition ( _root , Depth , SearchWindow . Infinite ) ;
5545 }
5646
5747 private void StorePVinTT ( Move [ ] pv , int depth )
@@ -64,30 +54,27 @@ private void StorePVinTT(Move[] pv, int depth)
6454 }
6555 }
6656
67- private int EvalPositionTT ( Board position , int depth , SearchWindow window , bool isNullMove = false )
57+ private ( int Score , Move [ ] PV ) EvalPositionTT ( Board position , int depth , SearchWindow window , bool isNullMove = false )
6858 {
69- if ( Transpositions . GetScore ( position , depth , window , out int score ) )
70- {
71- TriangularTable . Truncate ( depth ) ;
72- return score ;
73- }
59+ if ( Transpositions . GetScore ( position , depth , window , out int ttScore ) )
60+ return ( ttScore , Array . Empty < Move > ( ) ) ;
7461
75- score = EvalPosition ( position , depth , window , isNullMove ) ;
76- Transpositions . Store ( position . ZobristHash , depth , window , score , default ) ;
77- return score ;
62+ var result = EvalPosition ( position , depth , window , isNullMove ) ;
63+ Transpositions . Store ( position . ZobristHash , depth , window , result . Score , default ) ;
64+ return result ;
7865 }
7966
80- private int EvalPosition ( Board position , int depth , SearchWindow window , bool isNullMove = false )
67+ private ( int Score , Move [ ] PV ) EvalPosition ( Board position , int depth , SearchWindow window , bool isNullMove = false )
8168 {
8269 if ( depth <= 0 )
8370 {
8471 Evaluation . DynamicScore = Evaluation . ComputeMobility ( position ) ;
85- return QEval ( position , window ) ;
72+ return ( QEval ( position , window ) , Array . Empty < Move > ( ) ) ;
8673 }
8774
8875 NodesVisited ++ ;
8976 if ( Aborted )
90- return 0 ;
77+ return ( 0 , Array . Empty < Move > ( ) ) ;
9178
9279 Color color = position . SideToMove ;
9380 //should we try null move pruning?
@@ -98,13 +85,14 @@ private int EvalPosition(Board position, int depth, SearchWindow window, bool is
9885 Board nullChild = Playmaker . PlayNullMove ( position ) ;
9986 //evaluate the position at reduced depth with a null-window around beta
10087 SearchWindow nullWindow = window . GetUpperBound ( color ) ;
101- int nullScore = EvalPositionTT ( nullChild , depth - R - 1 , nullWindow , true ) ;
88+ ( int nullScore , _ ) = EvalPositionTT ( nullChild , depth - R - 1 , nullWindow , true ) ;
10289 //is the evaluation "too good" despite null-move? then don't waste time on a branch that is likely going to fail-high
10390 if ( nullWindow . Cut ( nullScore , color ) )
104- return nullScore ;
91+ return ( nullScore , Array . Empty < Move > ( ) ) ;
10592 }
10693
10794 //do a regular expansion...
95+ Move [ ] pv = Array . Empty < Move > ( ) ;
10896 int expandedNodes = 0 ;
10997 foreach ( ( Move move , Board child ) in Playmaker . Play ( position , depth , _killers ) )
11098 {
@@ -115,41 +103,37 @@ private int EvalPosition(Board position, int depth, SearchWindow window, bool is
115103 {
116104 //we can save a lot of nodes by searching with "null window" first, proving cheaply that the score is below alpha...
117105 SearchWindow nullWindow = window . GetLowerBound ( color ) ;
118- int nullScore = EvalPositionTT ( child , depth - 1 , nullWindow ) ;
119- if ( ! nullWindow . Inside ( nullScore , color ) )
106+ var nullResult = EvalPositionTT ( child , depth - 1 , nullWindow ) ;
107+ if ( ! nullWindow . Inside ( nullResult . Score , color ) )
120108 continue ;
121109 }
122110
123111 //this node may raise alpha!
124- int score = EvalPositionTT ( child , depth - 1 , window ) ;
125- if ( window . Inside ( score , color ) )
112+ var eval = EvalPositionTT ( child , depth - 1 , window ) ;
113+ if ( window . Inside ( eval . Score , color ) )
126114 {
127- Transpositions . Store ( position . ZobristHash , depth , window , score , move ) ;
128- TriangularTable . Store ( depth , move ) ;
115+ Transpositions . Store ( position . ZobristHash , depth , window , eval . Score , move ) ;
116+ //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 ) ;
129120 //...and maybe get a beta cutoff
130- if ( window . Cut ( score , color ) )
121+ if ( window . Cut ( eval . Score , color ) )
131122 {
132123 //we remember killers like hat!
133124 if ( position [ move . ToSquare ] == Piece . None )
134125 _killers . Add ( move , depth ) ;
135126
136- return window . GetScore ( color ) ;
127+ return ( window . GetScore ( color ) , pv ) ;
137128 }
138129 }
139130 }
140131
141- //no playable moves in this position ?
132+ //checkmate or draw ?
142133 if ( expandedNodes == 0 )
143- {
144- //clear PV because the game is over
145- TriangularTable . Truncate ( depth ) ;
146- if ( position . IsChecked ( color ) )
147- return Evaluation . Checkmate ( color ) ; //lost!
148- else
149- return 0 ; //draw!
150- }
134+ return ( position . IsChecked ( color ) ? Evaluation . Checkmate ( color ) : 0 , Array . Empty < Move > ( ) ) ;
151135
152- return window . GetScore ( color ) ;
136+ return ( window . GetScore ( color ) , pv ) ;
153137 }
154138
155139 private int QEval ( Board position , SearchWindow window )
0 commit comments