@@ -8,6 +8,9 @@ internal class AlphaBetaPruning<TPosition, TStep> : IAlphaBetaPruning<TPosition>
88 private readonly IHeuristicTables < TStep > heuristicTables ;
99 private readonly ISearchManager searchManager ;
1010
11+ private const int MaxSearchDepth = 16 ;
12+ private readonly List < TStep > [ ] orderedStepBuffers ;
13+
1114 public AlphaBetaPruning (
1215 IRules < TPosition , TStep > rules ,
1316 ICacheTables < TPosition , TStep > cacheTables ,
@@ -18,6 +21,12 @@ public AlphaBetaPruning(
1821 this . cacheTables = cacheTables ?? throw new ArgumentNullException ( nameof ( cacheTables ) ) ;
1922 this . heuristicTables = heuristicTables ?? throw new ArgumentNullException ( nameof ( heuristicTables ) ) ;
2023 this . searchManager = searchManager ?? throw new ArgumentNullException ( nameof ( searchManager ) ) ;
24+
25+ orderedStepBuffers = new List < TStep > [ MaxSearchDepth ] ;
26+ for ( int i = 0 ; i < MaxSearchDepth ; i ++ )
27+ {
28+ orderedStepBuffers [ i ] = new List < TStep > ( ) ;
29+ }
2130 }
2231
2332 public int Search ( TPosition position , int alpha , int beta )
@@ -27,15 +36,20 @@ public int Search(TPosition position, int alpha, int beta)
2736
2837 private int SearchRecursively ( TPosition position , int depth , int alpha , int beta )
2938 {
30- if ( IsLeaf ( position , depth ) )
39+ if ( depth <= 0 )
3140 {
41+ if ( rules . IsGoal ( position ) )
42+ {
43+ return - ( sbyte . MaxValue + depth ) ;
44+ }
3245 return - HeuristicValue ( position , depth ) ;
3346 }
3447
3548 var originalAlpha = alpha ;
3649
37- if ( cacheTables . TryGetTransposition ( position , out Transposition < TStep > transposition )
38- && depth <= transposition . Depth )
50+ bool hasTransposition = cacheTables . TryGetTransposition ( position , out Transposition < TStep > transposition ) ;
51+
52+ if ( hasTransposition && depth <= transposition . Depth )
3953 {
4054 switch ( transposition . EvaluationMode )
4155 {
@@ -55,11 +69,19 @@ private int SearchRecursively(TPosition position, int depth, int alpha, int beta
5569 }
5670 }
5771
72+ var orderedSteps = GetOrderedLegalSteps ( position , depth , hasTransposition , transposition . OptimalStep ) ;
73+
74+ if ( orderedSteps . Count == 0 )
75+ {
76+ return - ( rules . IsGoal ( position ) ? sbyte . MaxValue + depth : 0 ) ;
77+ }
78+
5879 var bestValue = - int . MaxValue ;
5980 TStep bestStep = default ;
6081
61- foreach ( var step in OrderedLegalStepsAt ( position , depth , transposition ) )
82+ for ( int i = 0 ; i < orderedSteps . Count ; i ++ )
6283 {
84+ var step = orderedSteps [ i ] ;
6385 position . Take ( step ) ;
6486 var value = - SearchRecursively ( position , depth - 1 , - beta , - alpha ) ;
6587 position . TakeBack ( ) ;
@@ -78,40 +100,45 @@ private int SearchRecursively(TPosition position, int depth, int alpha, int beta
78100 }
79101 if ( depth > 1 )
80102 {
81- EvaluationMode evaluationMode = GetEvaluationMode ( bestValue , originalAlpha , beta ) ;
82- transposition = new Transposition < TStep > ( evaluationMode , bestValue , depth , bestStep ) ;
83- cacheTables . AddTransposition ( position , transposition ) ;
103+ var newTransposition = new Transposition < TStep > ( GetEvaluationMode ( bestValue , originalAlpha , beta ) , bestValue , depth , bestStep ) ;
104+ cacheTables . AddTransposition ( position , newTransposition ) ;
84105 }
85106 return bestValue ;
86107 }
87108
88- private IEnumerable < TStep > OrderedLegalStepsAt ( TPosition position , int depth , Transposition < TStep > transposition )
109+ private List < TStep > GetOrderedLegalSteps ( TPosition position , int depth , bool hasTransposition , TStep transpositionStep )
89110 {
90- if ( transposition != null )
91- {
92- yield return transposition . OptimalStep ;
93- }
94- var prevKillerSteps = heuristicTables . GetKillerSteps ( depth ) ;
95- var otherSteps = new List < TStep > ( ) ;
111+ var result = orderedStepBuffers [ depth ] ;
112+ result . Clear ( ) ;
113+
114+ var killers = heuristicTables . GetKillerSteps ( depth ) ;
115+ int killerCount = 0 ;
116+ bool transpositionStepIsLegal = false ;
117+
96118 foreach ( var move in rules . LegalStepsAt ( position ) )
97119 {
98- if ( transposition != null && move . Equals ( transposition . OptimalStep ) )
120+ if ( hasTransposition && move . Equals ( transpositionStep ) )
99121 {
122+ transpositionStepIsLegal = true ;
100123 continue ;
101124 }
102- if ( prevKillerSteps . Contains ( move ) )
125+ if ( killers . Contains ( move ) )
103126 {
104- yield return move ;
127+ result . Insert ( killerCount , move ) ;
128+ killerCount ++ ;
105129 }
106130 else
107131 {
108- otherSteps . Add ( move ) ;
132+ result . Add ( move ) ;
109133 }
110134 }
111- foreach ( var move in otherSteps )
135+
136+ if ( transpositionStepIsLegal )
112137 {
113- yield return move ;
138+ result . Insert ( 0 , transpositionStep ) ;
114139 }
140+
141+ return result ;
115142 }
116143
117144 private bool IsBetaCutOff ( int alpha , int beta )
@@ -124,11 +151,6 @@ private void HandleBetaCutOff(TStep step, int depth)
124151 heuristicTables . StoreBetaCutOff ( step , depth ) ;
125152 }
126153
127- private bool IsLeaf ( TPosition position , int depth )
128- {
129- return depth <= 0 || ! rules . LegalStepsAt ( position ) . Any ( ) ;
130- }
131-
132154 private EvaluationMode GetEvaluationMode ( int value , int alpha , int beta )
133155 {
134156 if ( value <= alpha )
@@ -147,16 +169,12 @@ private EvaluationMode GetEvaluationMode(int value, int alpha, int beta)
147169
148170 private int HeuristicValue ( TPosition position , int depth )
149171 {
150- if ( rules . LegalStepsAt ( position ) . Any ( ) )
172+ if ( ! cacheTables . TryGetValue ( position , out var value ) )
151173 {
152- if ( ! cacheTables . TryGetValue ( position , out var value ) )
153- {
154- value = position . Value ;
155- cacheTables . AddValue ( position , value ) ;
156- }
157- return IsOpponentsTurn ( depth ) ? - value : value ; // TODO: check if the sign is required!
174+ value = position . Value ;
175+ cacheTables . AddValue ( position , value ) ;
158176 }
159- return rules . IsGoal ( position ) ? sbyte . MaxValue + depth : 0 ;
177+ return IsOpponentsTurn ( depth ) ? - value : value ;
160178 }
161179
162180 private bool IsOpponentsTurn ( int depth )
0 commit comments