Skip to content

Commit 5aec425

Browse files
committed
refactor: move search config (maxDepth, timeBudget, MaxSearchDepth) into SearchManager
1 parent bc05ca0 commit 5aec425

6 files changed

Lines changed: 27 additions & 38 deletions

File tree

Alligator.Solver/Algorithms/AlphaBetaPruning.cs

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ internal class AlphaBetaPruning<TPosition, TStep> : IAlphaBetaPruning<TPosition>
88
private readonly IHeuristicTables<TStep> heuristicTables;
99
private readonly ISearchManager searchManager;
1010

11-
private const int MaxSearchDepth = 48;
1211
private readonly List<TStep>[] orderedStepBuffers;
1312

1413
public AlphaBetaPruning(
@@ -22,8 +21,8 @@ public AlphaBetaPruning(
2221
this.heuristicTables = heuristicTables ?? throw new ArgumentNullException(nameof(heuristicTables));
2322
this.searchManager = searchManager ?? throw new ArgumentNullException(nameof(searchManager));
2423

25-
orderedStepBuffers = new List<TStep>[MaxSearchDepth];
26-
for (int i = 0; i < MaxSearchDepth; i++)
24+
orderedStepBuffers = new List<TStep>[searchManager.MaxDepth];
25+
for (int i = 0; i < searchManager.MaxDepth; i++)
2726
{
2827
orderedStepBuffers[i] = new List<TStep>();
2928
}
@@ -189,16 +188,11 @@ private bool IsOpponentsTurn(int depth)
189188
return distanceFromRoot % 2 != 0;
190189
}
191190

192-
/// <summary>
193-
/// Computes the terminal (win/loss) value at the given remaining depth.
194-
/// Uses distance-from-root so the same game-theoretic outcome
195-
/// produces the same value regardless of the current DepthLimit.
196-
/// Closer wins score higher.
197-
/// </summary>
191+
// Distance-from-root makes this value independent of DepthLimit (important for TT consistency)
198192
private int WinValue(int depth)
199193
{
200194
int distanceFromRoot = searchManager.DepthLimit - depth;
201-
return sbyte.MaxValue + MaxSearchDepth - distanceFromRoot;
195+
return sbyte.MaxValue + searchManager.MaxDepth - distanceFromRoot;
202196
}
203197
}
204198
}

Alligator.Solver/Algorithms/AlphaBetaSolver.cs

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,23 +9,17 @@ internal class AlphaBetaSolver<TPosition, TStep> : ISolver<TStep>
99
private readonly IRules<TPosition, TStep> rules;
1010
private readonly ISearchManager searchManager;
1111
private readonly Action<string> logger;
12-
private readonly int maxDepth;
13-
private readonly long timeBudgetMs;
1412

1513
public AlphaBetaSolver(
1614
AlphaBetaPruning<TPosition, TStep> alphaBetaPruning,
1715
IRules<TPosition, TStep> rules,
1816
ISearchManager searchManager,
19-
Action<string> logger,
20-
int maxDepth,
21-
long timeBudgetMs = 0)
17+
Action<string> logger)
2218
{
2319
this.alphaBetaPruning = alphaBetaPruning ?? throw new ArgumentNullException(nameof(alphaBetaPruning));
2420
this.rules = rules ?? throw new ArgumentNullException(nameof(rules));
2521
this.searchManager = searchManager ?? throw new ArgumentNullException(nameof(searchManager));
2622
this.logger = logger ?? throw new ArgumentNullException(nameof(logger));
27-
this.maxDepth = maxDepth;
28-
this.timeBudgetMs = timeBudgetMs;
2923
}
3024

3125
public TStep OptimizeNextStep(IList<TStep> history)
@@ -34,12 +28,11 @@ public TStep OptimizeNextStep(IList<TStep> history)
3428
sw.Restart();
3529
var position = CreatePosition(history);
3630

37-
TStep? bestStep = default;
38-
39-
searchManager.StartTimedSearch(timeBudgetMs);
31+
TStep? bestStep = default;
32+
searchManager.StartSearch();
4033
var guess = 0;
4134

42-
for (int i = 2; i < maxDepth; i += 2)
35+
for (int i = 2; i < searchManager.MaxDepth; i += 2)
4336
{
4437
searchManager.DepthLimit = i;
4538
var (OptimalSteps, Value) = BestNodeSearch(position, guess);
@@ -60,7 +53,7 @@ public TStep OptimizeNextStep(IList<TStep> history)
6053

6154
private (ICollection<TStep> OptimalSteps, int Value) BestNodeSearch(TPosition position, int guess)
6255
{
63-
const int winScore = sbyte.MaxValue + 48; // must match AlphaBetaPruning.MaxSearchDepth
56+
int winScore = sbyte.MaxValue + searchManager.MaxDepth;
6457
int alpha = -winScore;
6558
int beta = winScore;
6659

Alligator.Solver/Algorithms/ISearchManager.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@
22
{
33
internal interface ISearchManager
44
{
5+
int MaxDepth { get; }
56
int DepthLimit { get; set; }
67
bool IsAborted { get; }
78

8-
void StartTimedSearch(long timeBudgetMs);
9+
void StartSearch();
910
void CheckTimeBudget();
1011
}
1112
}

Alligator.Solver/Algorithms/SearchManager.cs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,23 +5,24 @@ namespace Alligator.Solver.Algorithms
55
internal class SearchManager : ISearchManager
66
{
77
private readonly Stopwatch stopwatch = new();
8-
private long timeLimitMs;
8+
private readonly long timeLimitMs;
99
private int nodeCount;
1010

11+
public int MaxDepth { get; }
1112
public int DepthLimit { get; set; }
1213
public bool IsAborted { get; private set; }
1314

14-
public SearchManager(int depthLimit)
15+
public SearchManager(int maxDepth, TimeSpan? timeBudget = null)
1516
{
16-
DepthLimit = depthLimit;
17+
MaxDepth = maxDepth;
18+
timeLimitMs = (long)(timeBudget?.TotalMilliseconds ?? 0);
1719
}
1820

19-
public void StartTimedSearch(long timeBudgetMs)
21+
public void StartSearch()
2022
{
21-
timeLimitMs = timeBudgetMs;
2223
nodeCount = 0;
2324
IsAborted = false;
24-
if (timeBudgetMs > 0)
25+
if (timeLimitMs > 0)
2526
{
2627
stopwatch.Restart();
2728
}

Alligator.Solver/SolverProvider.cs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -41,15 +41,15 @@ public ISolver<TStep> Create()
4141

4242
internal ISolver<TStep> Create(ICacheTables<TPosition, TStep> cacheTables, IHeuristicTables<TStep> heuristicTables)
4343
{
44-
var searchManager = new SearchManager(6); // TODO: remove this ctor parameter
44+
var searchManager = new SearchManager(
45+
solverConfiguration.MaxDepth,
46+
solverConfiguration.TimeBudget);
4547

4648
return new AlphaBetaSolver<TPosition, TStep>(
47-
new AlphaBetaPruning<TPosition, TStep>(rules, cacheTables, heuristicTables, searchManager),
48-
rules,
49-
searchManager,
50-
logger,
51-
solverConfiguration.MaxDepth,
52-
(long)(solverConfiguration.TimeBudget?.TotalMilliseconds ?? 0));
49+
new AlphaBetaPruning<TPosition, TStep>(rules, cacheTables, heuristicTables, searchManager),
50+
rules,
51+
searchManager,
52+
logger);
5353
}
5454
}
5555
}

Alligator.Test/SolverTests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,11 @@ private static int Solve(TreeNode root, int maxDepth = 7)
1616
var rules = new TreeRules(root);
1717
var cacheTables = new CacheTables<TreePosition, int>();
1818
var heuristicTables = new HeuristicTables<int>();
19-
var searchManager = new SearchManager(maxDepth - 1);
19+
var searchManager = new SearchManager(maxDepth);
2020
var alphaBeta = new AlphaBetaPruning<TreePosition, int>(
2121
rules, cacheTables, heuristicTables, searchManager);
2222
var solver = new AlphaBetaSolver<TreePosition, int>(
23-
alphaBeta, rules, searchManager, _ => { }, maxDepth);
23+
alphaBeta, rules, searchManager, _ => { });
2424

2525
return solver.OptimizeNextStep([]);
2626
}

0 commit comments

Comments
 (0)