Skip to content

Commit

Permalink
When we run out of captures in QSearch, double check to discard check…
Browse files Browse the repository at this point in the history
…mate/stalemate before returning static eval
  • Loading branch information
eduherminio committed Aug 18, 2023
1 parent 6ca70ea commit f2c9c71
Show file tree
Hide file tree
Showing 4 changed files with 28 additions and 5 deletions.
5 changes: 5 additions & 0 deletions src/Lynx/Model/Game.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ public Game(string fen)
CurrentPosition = new Position(parsedFen);
_gameInitialPosition = new Position(CurrentPosition);

if (!CurrentPosition.IsValid())
{
_logger.Warn($"Invalid position detected: {fen}");
}

MoveHistory = new(150);
PositionHashHistory = new(150) { CurrentPosition.UniqueIdentifier };

Expand Down
18 changes: 13 additions & 5 deletions src/Lynx/Search/NegaMax.cs
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,10 @@ public int QuiescenceSearch(int ply, int alpha, int beta)
var generatedMoves = position.AllCapturesMoves(Game.MovePool);
if (!generatedMoves.Any())
{
return staticEvaluation; // TODO check if in check or drawn position
// Since draws are detected in static evaluation and checks are extended,
// it's actually complex to probe that this works
// The closer I got is 7k/1Q4r1/2q1B3/1P2QNN1/8/R7/nN6/K1R5 b - - 0 1, where it saves time
return ValueIfAnyValidMoveOrFinalPositionEval(staticEvaluation);
}

var movesToEvaluate = generatedMoves.OrderByDescending(move => ScoreMove(move, ply, false));
Expand Down Expand Up @@ -395,6 +398,14 @@ public int QuiescenceSearch(int ply, int alpha, int beta)
return alpha;
}

return ValueIfAnyValidMoveOrFinalPositionEval(alpha);
}

// Node fails low
return alpha;

int ValueIfAnyValidMoveOrFinalPositionEval(int returnValue)
{
foreach (var move in position.AllPossibleMoves(Game.MovePool))
{
var gameState = position.MakeMove(move);
Expand All @@ -403,14 +414,11 @@ public int QuiescenceSearch(int ply, int alpha, int beta)

if (isValid)
{
return alpha;
return returnValue;
}
}

return Position.EvaluateFinalPosition(ply, position.IsInCheck());
}

// Node fails low
return alpha;
}
}
7 changes: 7 additions & 0 deletions tests/Lynx.Test/BestMove/QuiescenceTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,11 @@ public async Task Quiescence(string fen, int depth, int minQuiescenceSearchDepth
{
await TestBestMove(fen, allowedUCIMoveString, excludedUCIMoveString, depth);
}

[TestCase("7k/8/5NQ1/8/8/KN6/8/1r6 b - - 0 1", 1, new[] { "b1b3" })]
[TestCase("5Rbk/8/5N2/6Q1/8/1r6/8/KN6 b - - 0 1", 1, new[] { "b3b1" })]
public async Task DetectDrawWhenNoCaptures(string fen, int depth, string[]? allowedUCIMoveString, string[]? excludedUCIMoveString = null)
{
await TestBestMove(fen, allowedUCIMoveString, excludedUCIMoveString, depth);
}
}
3 changes: 3 additions & 0 deletions tests/Lynx.Test/BestMove/RegressionTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ public class RegressionTest : BaseTest
"g1h3", "g1f3", "g1e2"
}, Description = "Used to return an illegal move in the very first versions")]

[TestCase("7k/1Q4r1/2q1B3/1P2QNN1/8/R7/nN6/K1R5 b - - 0 1", new[] { "c6c1" },
Description = "Get stalemated vs winning a queen")]

public async Task GeneralRegression(string fen, string[]? allowedUCIMoveString, string[]? excludedUCIMoveString = null)
{
await TestBestMove(fen, allowedUCIMoveString, excludedUCIMoveString, depth: 5);
Expand Down

0 comments on commit f2c9c71

Please sign in to comment.