From f7d0f4c98840686fd5e22a8f5e834e05bfe1068e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eduardo=20C=C3=A1ceres?= Date: Tue, 30 Jan 2024 22:25:23 +0100 Subject: [PATCH] Add basic capture history --- src/Lynx/Engine.cs | 16 +++++++++++++--- src/Lynx/Search/Helpers.cs | 14 +++++++++----- src/Lynx/Search/IDDFS.cs | 19 ++++++++++++++++--- src/Lynx/Search/NegaMax.cs | 22 ++++++++++++++++------ 4 files changed, 54 insertions(+), 17 deletions(-) diff --git a/src/Lynx/Engine.cs b/src/Lynx/Engine.cs index 819a8c8f8..22c303c00 100644 --- a/src/Lynx/Engine.cs +++ b/src/Lynx/Engine.cs @@ -42,10 +42,20 @@ public Engine(ChannelWriter engineWriter) _absoluteSearchCancellationTokenSource = new(); _engineWriter = engineWriter; - _historyMoves = new int[12][]; - for (int i = 0; i < _historyMoves.Length; ++i) + _quietHistory = new int[12][]; + for (int i = 0; i < _quietHistory.Length; ++i) { - _historyMoves[i] = new int[64]; + _quietHistory[i] = new int[64]; + } + + _captureHistory = new int[12][][]; + for (int i = 0; i < 12; ++i) + { + _captureHistory[i] = new int[64][]; + for (var j = 0; j < 64; ++j) + { + _captureHistory[i][j] = new int[12]; + } } InitializeTT(); diff --git a/src/Lynx/Search/Helpers.cs b/src/Lynx/Search/Helpers.cs index 371ddfa79..81e69e5f4 100644 --- a/src/Lynx/Search/Helpers.cs +++ b/src/Lynx/Search/Helpers.cs @@ -59,7 +59,7 @@ public sealed partial class Engine private const int MaxValue = short.MaxValue; /// - /// Returns the score evaluation of a move taking into account , , , and + /// Returns the score evaluation of a move taking into account , , , and /// /// /// @@ -99,12 +99,16 @@ internal int ScoreMove(Move move, int depth, bool isNotQSearch, ShortMove bestMo if (isCapture) { - var baseCaptureScore = (isPromotion || move.IsEnPassant() || SEE.IsGoodCapture(Game.CurrentPosition, move)) ? EvaluationConstants.GoodCaptureMoveBaseScoreValue : EvaluationConstants.BadCaptureMoveBaseScoreValue; - return baseCaptureScore + EvaluationConstants.MostValueableVictimLeastValuableAttacker[move.Piece()][move.CapturedPiece()]; + var piece = move.Piece(); + + return baseCaptureScore + + EvaluationConstants.MostValueableVictimLeastValuableAttacker[piece][move.CapturedPiece()] + //+ EvaluationConstants.MVV_PieceValues[move.CapturedPiece()] + + _captureHistory[piece][move.TargetSquare()][move.CapturedPiece()]; } if (isPromotion) @@ -131,7 +135,7 @@ internal int ScoreMove(Move move, int depth, bool isNotQSearch, ShortMove bestMo } // History move or 0 if not found - return EvaluationConstants.BaseMoveScore + _historyMoves[move.Piece()][move.TargetSquare()]; + return EvaluationConstants.BaseMoveScore + _quietHistory[move.Piece()][move.TargetSquare()]; } return EvaluationConstants.BaseMoveScore; @@ -351,7 +355,7 @@ internal void PrintHistoryMoves() for (int i = 0; i < 12; ++i) { - var tmp = _historyMoves[i]; + var tmp = _quietHistory[i]; for (int j = 0; j < 64; ++i) { var item = tmp[j]; diff --git a/src/Lynx/Search/IDDFS.cs b/src/Lynx/Search/IDDFS.cs index 99da8fb4b..84a8bded2 100644 --- a/src/Lynx/Search/IDDFS.cs +++ b/src/Lynx/Search/IDDFS.cs @@ -24,7 +24,12 @@ public sealed partial class Engine /// /// 12x64 /// - private readonly int[][] _historyMoves; + private readonly int[][] _quietHistory; + + /// + /// 12x64x12 + /// + private readonly int[][][] _captureHistory; private readonly int[] _maxDepthReached = new int[Constants.AbsoluteMaxDepth]; private TranspositionTable _tt = []; @@ -298,9 +303,17 @@ private int CheckPonderHit(ref SearchResult? lastSearchResult, int depth) Array.Clear(_killerMoves[2]); Debug.Assert(_killerMoves.Length == 3); - for (int i = 0; i < _historyMoves.Length; i++) + for (int i = 0; i < _quietHistory.Length; i++) + { + Array.Clear(_quietHistory[i]); + } + + for (int i = 0; i < _captureHistory.Length; i++) { - Array.Clear(_historyMoves[i]); + for (int j = 0; j < _captureHistory[i].Length; j++) + { + Array.Clear(_captureHistory[i][j]); + } } } diff --git a/src/Lynx/Search/NegaMax.cs b/src/Lynx/Search/NegaMax.cs index 967fab7f8..c8768bd3e 100644 --- a/src/Lynx/Search/NegaMax.cs +++ b/src/Lynx/Search/NegaMax.cs @@ -287,7 +287,7 @@ private int NegaMax(int depth, int ply, int alpha, int beta, bool parentWasNullM } // -= history/(maxHistory/2) - reduction -= 2 * _historyMoves[move.Piece()][move.TargetSquare()] / Configuration.EngineSettings.History_MaxMoveValue; + reduction -= 2 * _quietHistory[move.Piece()][move.TargetSquare()] / Configuration.EngineSettings.History_MaxMoveValue; // Don't allow LMR to drop into qsearch or increase the depth // depth - 1 - depth +2 = 1, min depth we want @@ -338,15 +338,25 @@ private int NegaMax(int depth, int ply, int alpha, int beta, bool parentWasNullM { PrintMessage($"Pruning: {move} is enough"); - if (!move.IsCapture()) + if (move.IsCapture()) + { + var piece = move.Piece(); + var targetSquare = move.TargetSquare(); + var capturedPiece = move.CapturedPiece(); + + _captureHistory[piece][targetSquare][capturedPiece] = ScoreHistoryMove( + _captureHistory[piece][targetSquare][capturedPiece], + EvaluationConstants.HistoryBonus[depth]); + } + else { // 🔍 Quiet history moves // Doing this only in beta cutoffs (instead of when eval > alpha) was suggested by Sirius author var piece = move.Piece(); var targetSquare = move.TargetSquare(); - _historyMoves[piece][targetSquare] = ScoreHistoryMove( - _historyMoves[piece][targetSquare], + _quietHistory[piece][targetSquare] = ScoreHistoryMove( + _quietHistory[piece][targetSquare], EvaluationConstants.HistoryBonus[depth]); // 🔍 History penalty/malus @@ -359,8 +369,8 @@ private int NegaMax(int depth, int ply, int alpha, int beta, bool parentWasNullM var visitedMovePiece = visitedMove.Piece(); var visitedMoveTargetSquare = visitedMove.TargetSquare(); - _historyMoves[visitedMovePiece][visitedMoveTargetSquare] = ScoreHistoryMove( - _historyMoves[visitedMovePiece][visitedMoveTargetSquare], + _quietHistory[visitedMovePiece][visitedMoveTargetSquare] = ScoreHistoryMove( + _quietHistory[visitedMovePiece][visitedMoveTargetSquare], -EvaluationConstants.HistoryBonus[depth]); } }