Skip to content

Commit a762420

Browse files
committed
Extracting PV from the TT was too error prone. Going back to using a simplified TriangularTable for now but keeping the improved 2-slots TT.
1 parent c80ea4c commit a762420

File tree

5 files changed

+76
-45
lines changed

5 files changed

+76
-45
lines changed

MinimalChess/IterativeSearch.cs

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,17 @@
44

55
namespace MinimalChess
66
{
7+
78
public class IterativeSearch
89
{
910
const int QUERY_TC_FREQUENCY = 25;
1011

1112
public long NodesVisited { get; private set; }
1213
public int Depth { get; private set; }
1314
public int Score { get; private set; }
14-
public bool GameOver { get; private set; }
15-
public Move[] PrincipalVariation { get; private set; }
15+
public Move[] PrincipalVariation { get; private set; } = Array.Empty<Move>();
1616
public bool Aborted => NodesVisited >= _maxNodes || _killSwitch.Get(NodesVisited % QUERY_TC_FREQUENCY == 0);
17+
public bool GameOver => Evaluation.IsCheckmate(Score);
1718

1819
Board _root = null;
1920
KillerMoves _killers;
@@ -35,26 +36,41 @@ public IterativeSearch(int searchDepth, Board board) : this(board)
3536

3637
public void SearchDeeper(Func<bool> killSwitch = null)
3738
{
38-
if (GameOver || Aborted)
39+
if (GameOver)
3940
return;
4041

4142
Depth++;
4243
_killers.Resize(Depth);
44+
TriangularTable.Init(Depth);
45+
StorePVinTT(PrincipalVariation, Depth);
4346
_killSwitch = new KillSwitch(killSwitch);
47+
4448
int score = EvalPosition(_root, Depth, SearchWindow.Infinite);
4549

4650
if (!Aborted)
4751
{
48-
PrincipalVariation = Transpositions.ExtractPV(_root, Depth, out bool isDraw);
49-
GameOver = Evaluation.IsCheckmate(score) || isDraw;
5052
Score = score;
53+
PrincipalVariation = TriangularTable.GetLine(Depth);
54+
}
55+
}
56+
57+
private void StorePVinTT(Move[] pv, int depth)
58+
{
59+
Board position = new Board(_root);
60+
foreach (Move move in pv)
61+
{
62+
Transpositions.Store(position.ZobristHash, --depth, SearchWindow.Infinite, Score, move);
63+
position.Play(move);
5164
}
5265
}
5366

5467
private int EvalPositionTT(Board position, int depth, SearchWindow window, bool isNullMove = false)
5568
{
5669
if (Transpositions.GetScore(position, depth, window, out int score))
70+
{
71+
TriangularTable.Truncate(depth);
5772
return score;
73+
}
5874

5975
score = EvalPosition(position, depth, window, isNullMove);
6076
Transpositions.Store(position.ZobristHash, depth, window, score, default);
@@ -108,9 +124,8 @@ private int EvalPosition(Board position, int depth, SearchWindow window, bool is
108124
int score = EvalPositionTT(child, depth - 1, window);
109125
if (window.Inside(score, color))
110126
{
111-
//store move & score in TT. For root nodes a special depth is used to protect them against replacement (ROOT > HISTORY)
112-
int ttDepth = depth == Depth ? Transpositions.ROOT : depth;
113-
Transpositions.Store(position.ZobristHash, ttDepth, window, score, move);
127+
Transpositions.Store(position.ZobristHash, depth, window, score, move);
128+
TriangularTable.Store(depth, move);
114129
//...and maybe get a beta cutoff
115130
if (window.Cut(score, color))
116131
{
@@ -127,6 +142,7 @@ private int EvalPosition(Board position, int depth, SearchWindow window, bool is
127142
if (expandedNodes == 0)
128143
{
129144
//clear PV because the game is over
145+
TriangularTable.Truncate(depth);
130146
if (position.IsChecked(color))
131147
return Evaluation.Checkmate(color); //lost!
132148
else

MinimalChess/Transpositions.cs

Lines changed: 1 addition & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
11
using System;
2-
using System.Collections.Generic;
3-
using System.Linq;
4-
using System.Text;
52

63
namespace MinimalChess
74
{
@@ -25,8 +22,7 @@ public struct HashEntry
2522
// 16 Bytes
2623
}
2724

28-
public const short ROOT = 9999;
29-
public const short HISTORY = 9998;
25+
public const short HISTORY = 9999;
3026
public const int DEFAULT_SIZE_MB = 50;
3127
const int ENTRY_SIZE = 16; //BYTES
3228
static HashEntry[] _table;
@@ -69,35 +65,6 @@ public static void ClearChunk(int counter, int count)
6965
Array.Clear(_table, chunk * stride, stride);
7066
}
7167

72-
public static Move[] ExtractPV(Board root, int depth, out bool repeatsHistory)
73-
{
74-
var pv = new List<Move>();
75-
repeatsHistory = ExtractPV(new Board(root), pv, depth);
76-
return pv.ToArray();
77-
}
78-
79-
public static bool ExtractPV(Board position, List<Move> pv, int depth)
80-
{
81-
ulong zobristHash = position.ZobristHash;
82-
ref HashEntry entry = ref _table[Index(zobristHash)];
83-
84-
//Quit because entry is not about this position
85-
if (entry.Hash != zobristHash)
86-
return false;
87-
88-
//Quit because this position is flagged as a repetition
89-
if (entry.Depth == HISTORY)
90-
return true;
91-
92-
//Quit because the requested depth has been reached or no best move available
93-
if (depth == 0 || entry.BestMove == default)
94-
return false;
95-
96-
pv.Add(entry.BestMove);
97-
position.Play(entry.BestMove);
98-
return ExtractPV(position, pv, --depth);
99-
}
100-
10168
public static void Store(ulong zobristHash, int depth, SearchWindow window, int score, Move bestMove)
10269
{
10370
int index = Index(zobristHash);

MinimalChess/TriangularTable.cs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
using System;
2+
3+
namespace MinimalChess
4+
{
5+
public static class TriangularTable
6+
{
7+
static Move[] _moves = Array.Empty<Move>();
8+
9+
public static void Init(int maxDepth)
10+
{
11+
int size = Index(maxDepth + 1);
12+
_moves = new Move[size];
13+
}
14+
15+
private static int Index(int depth)
16+
{
17+
//return depth + (depth - 1) + (depth - 2) + ... + 1;
18+
int d = depth - 1;
19+
return (d * d + d) / 2;
20+
}
21+
22+
public static Move[] GetLine(int depth)
23+
{
24+
int start = Index(depth);
25+
int nullMove = Array.IndexOf(_moves, default, start, depth);
26+
int count = (nullMove == -1) ? depth : nullMove - start;
27+
28+
Move[] line = new Move[count];
29+
Array.Copy(_moves, start, line, 0, count);
30+
return line;
31+
}
32+
33+
public static void Store(int depth, Move move)
34+
{
35+
int a = Index(depth);
36+
_moves[a] = move;
37+
//remember the continuation
38+
int b = Index(depth - 1);
39+
for (int i = 0; i < depth - 1; i++)
40+
_moves[a + i + 1] = _moves[b + i];
41+
}
42+
43+
public static void Truncate(int depth)
44+
{
45+
Array.Clear(_moves, 0, Index(depth+1));
46+
}
47+
}
48+
}

MinimalChessEngine/Program.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ namespace MinimalChessEngine
77
{
88
public static class Program
99
{
10-
const string NAME_VERSION = "MinimalChess 0.5.2";
10+
const string NAME_VERSION = "MinimalChess 0.5.3";
1111

1212
static Engine _engine = new Engine();
1313
static async Task Main()
@@ -106,7 +106,7 @@ private static void UciGo(string[] tokens)
106106
//40 Moves in 5 Minutes, 1 second increment per Move = go wtime 300000 btime 300000 movestogo 40 winc 1000 binc 1000 movestogo 40
107107
//5 Minutes total, no increment (sudden death) = go wtime 300000 btime 300000
108108

109-
TryParse(tokens, "depth", out int maxDepth, int.MaxValue);
109+
TryParse(tokens, "depth", out int maxDepth, 99);
110110
TryParse(tokens, "movetime", out int maxTime, int.MaxValue);
111111
TryParse(tokens, "nodes", out int maxNodes, int.MaxValue);
112112
TryParse(tokens, "movestogo", out int movesToGo, 40); //assuming 30 e.g. spend 1/30th of total budget on the move

MinimalChessEngine/Properties/PublishProfiles/Windows x64.pubxml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
88
<Configuration>Release</Configuration>
99
<Platform>Any CPU</Platform>
1010
<TargetFramework>net5.0</TargetFramework>
11-
<PublishDir>D:\Projekte\Chess\Builds\MinimalChess 0.5.2 Windows</PublishDir>
11+
<PublishDir>D:\Projekte\Chess\Builds\MinimalChess 0.5.3 Windows</PublishDir>
1212
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
1313
<SelfContained>true</SelfContained>
1414
<PublishSingleFile>True</PublishSingleFile>

0 commit comments

Comments
 (0)