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 @@