diff --git a/.github/workflows/release-pipeline.yaml b/.github/workflows/release-pipeline.yaml index d5ceab4..2896eab 100644 --- a/.github/workflows/release-pipeline.yaml +++ b/.github/workflows/release-pipeline.yaml @@ -25,7 +25,7 @@ jobs: working-directory: Sapling id: get_version run: | - VERSION=1.1.6 + VERSION=1.1.7 echo "Application version: $VERSION" echo "::set-output name=version::$VERSION" diff --git a/Sapling.Engine/RepetitionDetector.cs b/Sapling.Engine/RepetitionDetector.cs index 83ba41d..a6f42b3 100644 --- a/Sapling.Engine/RepetitionDetector.cs +++ b/Sapling.Engine/RepetitionDetector.cs @@ -76,6 +76,34 @@ ulong AttackMask(int idx, int piece) } } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool IsThreefoldRepetition(ushort turnCount, ushort halfMoveClock, ulong* hashHistory) + { + if (halfMoveClock < 3) + return false; + + var currHash = hashHistory + turnCount - 1; + + var initialHash = *(currHash); + + var count = 1; + for (var i = 2; i < halfMoveClock; i+=2) + { + currHash -= 2; + if (*(currHash) != initialHash) + { + continue; + } + + if (++count >= 3) + { + return true; + } + } + + return false; + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool HasRepetition(this ref BoardStateData pos, ulong* hashHistory, int depthFromRoot) { diff --git a/Sapling.Engine/Search/NegaMaxSearch.cs b/Sapling.Engine/Search/NegaMaxSearch.cs index b5fa31d..94d5c8f 100644 --- a/Sapling.Engine/Search/NegaMaxSearch.cs +++ b/Sapling.Engine/Search/NegaMaxSearch.cs @@ -54,7 +54,9 @@ public unsafe int return alpha; } - if (currentBoardState->HalfMoveClock >= 100 || currentBoardState->InsufficientMatingMaterial()) + if (currentBoardState->HalfMoveClock >= 100 || + currentBoardState->InsufficientMatingMaterial() || + RepetitionDetector.IsThreefoldRepetition(currentBoardState->TurnCount, currentBoardState->HalfMoveClock, HashHistory)) { // Detect draw by Fifty move counter or repetition return 0; @@ -248,6 +250,7 @@ public unsafe int counterMove); } + var nextHashHistoryEntry = HashHistory + currentBoardState->TurnCount; var probCutSortedUpTo = 0; // Probcut @@ -316,6 +319,7 @@ public unsafe int { newBoardState->FinishApplyBlack(ref *newAccumulatorState, m, currentBoardState->EnPassantFile, currentBoardState->CastleRights); } + *nextHashHistoryEntry = newBoardState->Hash; NodesVisited--; var score = -QuiescenceSearch(newBoardState, newAccumulatorState, depthFromRoot + 1, -probBeta, -probBeta + 1); @@ -344,7 +348,6 @@ public unsafe int uint bestMove = default; var evaluationBound = TranspositionTableFlag.Alpha; - var nextHashHistoryEntry = HashHistory + currentBoardState->TurnCount; var bestScore = int.MinValue; // Evaluate each move diff --git a/Sapling.Engine/Search/QuiescenceSearch.cs b/Sapling.Engine/Search/QuiescenceSearch.cs index 666c477..bbdfd9d 100644 --- a/Sapling.Engine/Search/QuiescenceSearch.cs +++ b/Sapling.Engine/Search/QuiescenceSearch.cs @@ -1,5 +1,4 @@ -using System.IO; -using System.Runtime.CompilerServices; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Intrinsics.X86; using Sapling.Engine.MoveGen; @@ -27,7 +26,9 @@ public unsafe int QuiescenceSearch(BoardStateData* boardState, AccumulatorState* return Evaluate(boardState, accumulatorState, depthFromRoot); } - if (boardState->InsufficientMatingMaterial()) + if (boardState->HalfMoveClock >= 100 || + boardState->InsufficientMatingMaterial() || + RepetitionDetector.IsThreefoldRepetition(boardState->TurnCount, boardState->HalfMoveClock, HashHistory)) { // Detect draw by Fifty move counter or repetition return 0; diff --git a/Sapling/Sapling.csproj b/Sapling/Sapling.csproj index 6fe9723..b2e4ec5 100644 --- a/Sapling/Sapling.csproj +++ b/Sapling/Sapling.csproj @@ -7,9 +7,9 @@ enable logo.ico Sapling - 1.1.6.0 - 1.1.6.0 - 1.1.6.0 + 1.1.7.0 + 1.1.7.0 + 1.1.7.0 true