Skip to content

Commit 89e49d4

Browse files
committed
History.cs refactored. It's not a static class anymore, instead IterativeSearch has an instance and passes it to the playmaker just like killers. Only beta cutoffs are stored as "good" positions in the history. Almost 20+ ELO in selfplay.
1 parent e695270 commit 89e49d4

File tree

7 files changed

+58
-80
lines changed

7 files changed

+58
-80
lines changed

MinimalChess/Board.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -415,12 +415,12 @@ public bool IsChecked(Color color)
415415
Piece king = color == Color.Black ? Piece.BlackKing : Piece.WhiteKing;
416416
for (int square = 0; square < 64; square++)
417417
if(_state[square] == king)
418-
return IsSquareAttacked(square, Pieces.Flip(color));
418+
return IsSquareAttackedBy(square, Pieces.Flip(color));
419419

420420
throw new Exception($"No {color} King found!");
421421
}
422422

423-
private bool IsSquareAttacked(int square, Color color)
423+
public bool IsSquareAttackedBy(int square, Color color)
424424
{
425425
//1. Pawns? (if attacker is white, pawns move up and the square is attacked from below. squares below == Attacks.BlackPawn)
426426
var pawnAttacks = color == Color.White ? Attacks.BlackPawn : Attacks.WhitePawn;
@@ -547,7 +547,7 @@ private bool CanCastle(int kingSquare, int rookSquare, Color color)
547547

548548
//the king must not start, end or pass through a square that is attacked by an enemy piece. (but the rook and the square next to the rook on queenside may be attacked)
549549
for (int i = 0; i < 3; i++)
550-
if (IsSquareAttacked(kingSquare + i * dir, enemyColor))
550+
if (IsSquareAttackedBy(kingSquare + i * dir, enemyColor))
551551
return false;
552552

553553
return true;

MinimalChess/History.cs

Lines changed: 20 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -6,41 +6,14 @@
66

77
namespace MinimalChess
88
{
9-
public static class History
9+
public class History
1010
{
1111
private const int Squares = 64;
1212
private const int Pieces = 12;
13-
private static int[,] Positive = new int[Squares, Pieces];
14-
private static int[,] Negative = new int[Squares, Pieces];
15-
16-
public static int Max
17-
{
18-
get
19-
{
20-
int max = 0;
21-
for (int square = 0; square < Squares; square++)
22-
for (int piece = 0; piece < Pieces; piece++)
23-
{
24-
max = Math.Max(max, Positive[square, piece]);
25-
max = Math.Max(max, Negative[square, piece]);
26-
}
27-
28-
return max;
29-
}
30-
}
31-
32-
public static void Clear()
33-
{
34-
for (int square = 0; square < Squares; square++)
35-
for (int piece = 0; piece < Pieces; piece++)
36-
{
37-
Positive[square, piece] = 0;
38-
Negative[square, piece] = 0;
39-
}
40-
}
41-
42-
43-
public static void Shrink()
13+
private readonly int[,] Positive = new int[Squares, Pieces];
14+
private readonly int[,] Negative = new int[Squares, Pieces];
15+
16+
public void Scale()
4417
{
4518
for (int square = 0; square < Squares; square++)
4619
for(int piece = 0; piece < Pieces; piece++)
@@ -50,23 +23,28 @@ public static void Shrink()
5023
}
5124
}
5225

53-
public static void Good(Piece piece, int square, int depth)
26+
private int PieceIndex(Piece piece)
27+
{
28+
return ((byte)piece >> 1) - 2; //BlackPawn = 0...
29+
}
30+
31+
public void Good(Board context, Move move, int depth)
5432
{
55-
int iPiece = ((byte)piece >> 1) - 2; //BlackPawn = 0...
56-
Positive[square, iPiece] += depth * depth;
33+
int iPiece = PieceIndex(context[move.FromSquare]);
34+
Positive[move.ToSquare, iPiece] += depth * depth;
5735
}
5836

59-
public static void Bad(Piece piece, int square, int depth)
37+
public void Bad(Board context, Move move, int depth)
6038
{
61-
int iPiece = ((byte)piece >> 1) - 2; //BlackPawn = 0...
62-
Negative[square, iPiece] += depth * depth;
39+
int iPiece = PieceIndex(context[move.FromSquare]);
40+
Negative[move.ToSquare, iPiece] += depth * depth;
6341
}
6442

65-
public static float Value(Piece piece, int square)
43+
public float Value(Board context, Move move)
6644
{
67-
int iPiece = ((byte)piece >> 1) - 2; //BlackPawn = 0...
68-
float a = Positive[square, iPiece] + 1;
69-
float b = Negative[square, iPiece] + 2;
45+
int iPiece = PieceIndex(context[move.FromSquare]);
46+
float a = Positive[move.ToSquare, iPiece] + 1;
47+
float b = Negative[move.ToSquare, iPiece] + 2;
7048
return a / b;
7149
}
7250
}

MinimalChess/IterativeSearch.cs

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,18 @@ public class IterativeSearch
1515
public bool Aborted => NodesVisited >= _maxNodes || _killSwitch.Get(NodesVisited % QUERY_TC_FREQUENCY == 0);
1616
public bool GameOver => Evaluation.IsCheckmate(Score);
1717

18-
Board _root;
19-
KillerMoves _killers;
20-
KillSwitch _killSwitch;
21-
long _maxNodes;
18+
private Board _root;
19+
private KillerMoves _killers;
20+
private History _history;
21+
private KillSwitch _killSwitch;
22+
private long _maxNodes;
2223

2324
public IterativeSearch(Board board, long maxNodes = long.MaxValue)
2425
{
2526
_root = new Board(board);
2627
_killers = new KillerMoves(4);
28+
_history = new History();
2729
_maxNodes = maxNodes;
28-
History.Clear();
2930
}
3031

3132
public IterativeSearch(int searchDepth, Board board) : this(board)
@@ -36,12 +37,9 @@ public IterativeSearch(int searchDepth, Board board) : this(board)
3637

3738
public void SearchDeeper(Func<bool> killSwitch = null)
3839
{
39-
if (GameOver)
40-
return;
41-
4240
Depth++;
4341
_killers.Resize(Depth);
44-
History.Shrink();
42+
_history.Scale();
4543
StorePVinTT(PrincipalVariation, Depth);
4644
_killSwitch = new KillSwitch(killSwitch);
4745
(Score, PrincipalVariation) = EvalPosition(_root, Depth, SearchWindow.Infinite);
@@ -100,7 +98,7 @@ private void StorePVinTT(Move[] pv, int depth)
10098
//do a regular expansion...
10199
Move[] pv = Array.Empty<Move>();
102100
int expandedNodes = 0;
103-
foreach ((Move move, Board child) in Playmaker.Play(position, depth, _killers))
101+
foreach ((Move move, Board child) in Playmaker.Play(position, depth, _killers, _history))
104102
{
105103
expandedNodes++;
106104

@@ -124,11 +122,10 @@ private void StorePVinTT(Move[] pv, int depth)
124122
var eval = EvalPositionTT(child, depth - 1, window);
125123
if (window.FailLow(eval.Score, color))
126124
{
127-
History.Bad(position[move.FromSquare], move.ToSquare, depth);
125+
_history.Bad(position, move, depth);
128126
continue;
129127
}
130128

131-
History.Good(position[move.FromSquare], move.ToSquare, depth);
132129
Transpositions.Store(position.ZobristHash, depth, window, eval.Score, move);
133130
//store the PV beginning with move, followed by the PV of the childnode
134131
pv = Merge(move, eval.PV);
@@ -137,7 +134,10 @@ private void StorePVinTT(Move[] pv, int depth)
137134
{
138135
//we remember killers like hat!
139136
if (position[move.ToSquare] == Piece.None)
137+
{
138+
_history.Good(position, move, depth);
140139
_killers.Add(move, depth);
140+
}
141141

142142
return (window.GetScore(color), pv);
143143
}

MinimalChess/MoveCollection.cs

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -64,13 +64,9 @@ int Score(Move move)
6464
Sort((a, b) => Score(b).CompareTo(Score(a)));
6565
}
6666

67-
public void SortHistory(Board context)
67+
public void SortHistory(Board context, History history)
6868
{
69-
float Score(Move move)
70-
{
71-
return History.Value(context[move.FromSquare], move.ToSquare);
72-
}
73-
Sort((a, b) => Score(b).CompareTo(Score(a)));
69+
Sort((a, b) => history.Value(context, b).CompareTo(history.Value(context, a)));
7470
}
7571
}
7672
}

MinimalChess/Playmaker.cs

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ namespace MinimalChess
55
{
66
public static class Playmaker
77
{
8-
internal static IEnumerable<(Move Move, Board Board)> Play(Board position, int depth, KillerMoves killers)
8+
internal static IEnumerable<(Move Move, Board Board)> Play(Board position, int depth, KillerMoves killers, History history)
99
{
1010
//1. Captures Mvv-Lva, PV excluded
1111
Move bestMove = Transpositions.GetBestMove(position);
@@ -25,24 +25,28 @@ public static class Playmaker
2525

2626
//3. Killers if available
2727
foreach (Move killer in killers.Get(depth))
28-
if (position[killer.ToSquare] == Piece.None && position.IsPlayable(killer))
29-
{
30-
var nextPosition = new Board(position, killer);
31-
if (!nextPosition.IsChecked(position.SideToMove))
32-
yield return (killer, nextPosition);
33-
}
28+
{
29+
if (position[killer.ToSquare] != Piece.None || !position.IsPlayable(killer))
30+
continue;
31+
32+
var nextPosition = new Board(position, killer);
33+
if (!nextPosition.IsChecked(position.SideToMove))
34+
yield return (killer, nextPosition);
35+
}
3436

3537
//4. Play quiet moves that aren't known killers
3638
var quiets = MoveList.Quiets(position);
37-
if(depth >= 3)
38-
quiets.SortHistory(position);
39+
if (depth >= 3)
40+
quiets.SortHistory(position, history);
3941
foreach (var move in quiets)
40-
if (!killers.Contains(depth, move))
41-
{
42-
var nextPosition = new Board(position, move);
43-
if (!nextPosition.IsChecked(position.SideToMove))
44-
yield return (move, nextPosition);
45-
}
42+
{
43+
if (killers.Contains(depth, move))
44+
continue;
45+
46+
var nextPosition = new Board(position, move);
47+
if (!nextPosition.IsChecked(position.SideToMove))
48+
yield return (move, nextPosition);
49+
}
4650
}
4751

4852
internal static IEnumerable<Board> Play(Board position)

MinimalChessEngine/Program.cs

Lines changed: 1 addition & 1 deletion
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.10";
10+
const string NAME_VERSION = "MinimalChess 0.5.11";
1111

1212
static Engine _engine = new Engine();
1313
static async Task Main()

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.10 Windows</PublishDir>
11+
<PublishDir>D:\Projekte\Chess\Builds\MinimalChess 0.5.11 Windows</PublishDir>
1212
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
1313
<SelfContained>true</SelfContained>
1414
<PublishSingleFile>True</PublishSingleFile>

0 commit comments

Comments
 (0)