|
private int[] _singlePvAspirationWindows = new[] {100, 500}; |
|
private int[] _multiPvAspirationWindows = new[] {100, 200, 300, 400, 500, 600, 700, |
|
800, 900, 1000, 2000, 5000, StaticScore.Max}; |
|
// ... |
|
|
|
|
|
private int GetScoreWithinAspirationWindow(Board Board, int PrincipalVariations) |
|
{ |
|
var bestScore = _bestMoves[0].Score; |
|
if ((_originalHorizon < _aspirationMinToHorizon) || (Math.Abs(bestScore) >= StaticScore.Checkmate)) |
|
{ |
|
// Reset move scores, then search moves with infinite aspiration window. |
|
for (var moveIndex = 0; moveIndex < Board.CurrentPosition.MoveIndex; moveIndex++) |
|
{ |
|
_rootMoves[moveIndex].Score = -StaticScore.Max; |
|
} |
|
return GetDynamicScore(Board, 0, _originalHorizon, false, -StaticScore.Max, StaticScore.Max); |
|
} |
|
int[] aspirationWindows; |
|
// ReSharper disable once ConvertSwitchStatementToSwitchExpression |
|
switch (_scoreError) |
|
{ |
|
case 0 when PrincipalVariations == 1: |
|
// Use single PV aspiration windows. |
|
aspirationWindows = _singlePvAspirationWindows; |
|
break; |
|
default: |
|
// Use multi PV aspiration windows. |
|
aspirationWindows = _multiPvAspirationWindows; |
|
break; |
|
} |
|
var alpha = 0; |
|
var beta = 0; |
|
var scorePrecision = ScorePrecision.Exact; |
|
for (var aspirationIndex = 0; aspirationIndex < aspirationWindows.Length; aspirationIndex++) |
|
{ |
|
var aspirationWindow = aspirationWindows[aspirationIndex]; |
|
// Reset move scores. |
|
for (var moveIndex = 0; moveIndex < Board.CurrentPosition.MoveIndex; moveIndex++) |
|
{ |
|
_rootMoves[moveIndex].Score = -StaticScore.Max; |
|
} |
|
// Adjust alpha / beta window. |
|
// ReSharper disable once SwitchStatementMissingSomeCases |
|
switch (scorePrecision) |
|
{ |
|
case ScorePrecision.LowerBound: |
|
// Fail High |
|
alpha = beta - 1; |
|
beta = Math.Min(beta + aspirationWindow, StaticScore.Max); |
|
break; |
|
case ScorePrecision.UpperBound: |
|
// Fail Low |
|
beta = alpha + 1; |
|
alpha = Math.Max(alpha - aspirationWindow, -StaticScore.Max); |
|
break; |
|
case ScorePrecision.Exact: |
|
// Initial Aspiration Window |
|
// Center aspiration window around best score from prior ply. |
|
alpha = PrincipalVariations > 1 |
|
? _lastAlpha |
|
: bestScore - _scoreError - aspirationWindow; |
|
beta = bestScore + aspirationWindow; |
|
break; |
|
default: |
|
throw new Exception(scorePrecision + " score precision not supported."); |
|
} |
|
// Search moves with aspiration window. |
|
if (_debug()) _writeMessageLine( |
|
$"info string LowAspirationWindow = {aspirationWindow} Alpha = {alpha} Beta = {beta}"); |
|
var score = GetDynamicScore(Board, 0, _originalHorizon, false, alpha, beta); |
|
if (Math.Abs(score) == StaticScore.Interrupted) return score; // Stop searching. |
|
if (score >= beta) |
|
{ |
|
// Search failed high. |
|
scorePrecision = ScorePrecision.LowerBound; |
|
if (PvInfoUpdate) UpdateInfoScoreOutsideAspirationWindow(Board.Nodes, score, true); |
|
continue; |
|
} |
|
// Find lowest score. |
|
var lowestScore = PrincipalVariations == 1 |
|
? score |
|
: GetBestScore(Board.CurrentPosition, PrincipalVariations); |
|
if (lowestScore <= alpha) |
|
{ |
|
// Search failed low. |
|
scorePrecision = ScorePrecision.UpperBound; |
|
if (PvInfoUpdate) UpdateInfoScoreOutsideAspirationWindow(Board.Nodes, score, false); |
|
continue; |
|
} |
|
// Score within aspiration window. |
|
_lastAlpha = alpha; |
|
return score; |
|
} |
|
// Search moves with infinite aspiration window. |
|
return GetDynamicScore(Board, 0, _originalHorizon, false, -StaticScore.Max, StaticScore.Max); |
|
} |
|
|
|
|
|
private int GetBestScore(Position Position, int Rank) |
|
{ |
|
Debug.Assert(Rank > 0); |
|
if (Rank == 1) |
|
{ |
|
var bestScore = -StaticScore.Max; |
|
for (var moveIndex = 0; moveIndex < Position.MoveIndex; moveIndex++) |
|
{ |
|
var score = _rootMoves[moveIndex].Score; |
|
if (score > bestScore) bestScore = score; |
|
} |
|
return bestScore; |
|
} |
|
// Sort moves and return Rank best move (1 based index). |
|
Array.Sort(_rootMoves, 0, Position.MoveIndex, _moveScoreComparer); |
|
return _rootMoves[Rank - 1].Score; |
|
} |