Skip to content

Commit d77cb1a

Browse files
committed
Late moves are now reduced by 2 instead of 1.
History score of moves is now in the interval of [0..1] with all entries that have no recorded a beta-cutoff scored at value 0. Quiet moves are sorted differently. If their score is below a certain threshold they are appended, otherwise insertion sorted.
1 parent 89e49d4 commit d77cb1a

File tree

7 files changed

+64
-34
lines changed

7 files changed

+64
-34
lines changed

MinimalChess/History.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,9 @@ public void Bad(Board context, Move move, int depth)
4343
public float Value(Board context, Move move)
4444
{
4545
int iPiece = PieceIndex(context[move.FromSquare]);
46-
float a = Positive[move.ToSquare, iPiece] + 1;
47-
float b = Negative[move.ToSquare, iPiece] + 2;
48-
return a / b;
46+
float a = Positive[move.ToSquare, iPiece];
47+
float b = Negative[move.ToSquare, iPiece];
48+
return a / (a + b + 1);//Interval [0..1]
4949
}
5050
}
5151
}

MinimalChess/IterativeSearch.cs

Lines changed: 28 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,6 @@ private void StorePVinTT(Move[] pv, int depth)
7979

8080
Color color = position.SideToMove;
8181
bool isChecked = position.IsChecked(color);
82-
int futilityMargin = (int)color * depth * MAX_GAIN_PER_PLY;
8382

8483
//should we try null move pruning?
8584
if (depth >= 2 && !isChecked)
@@ -88,11 +87,10 @@ private void StorePVinTT(Move[] pv, int depth)
8887
//skip making a move
8988
Board nullChild = Playmaker.PlayNullMove(position);
9089
//evaluate the position at reduced depth with a null-window around beta
91-
SearchWindow nullWindow = window.GetUpperBound(color);
92-
(int nullScore, _) = EvalPositionTT(nullChild, depth - R - 1, nullWindow);
90+
(int score, _) = EvalPositionTT(nullChild, depth - R - 1, window.GetUpperBound(color));
9391
//is the evaluation "too good" despite null-move? then don't waste time on a branch that is likely going to fail-high
94-
if (nullWindow.Cut(nullScore, color))
95-
return (nullScore, Array.Empty<Move>());
92+
if (window.FailHigh(score, color))
93+
return (score, Array.Empty<Move>());
9694
}
9795

9896
//do a regular expansion...
@@ -102,34 +100,43 @@ private void StorePVinTT(Move[] pv, int depth)
102100
{
103101
expandedNodes++;
104102

105-
//moves after the PV node are unlikely to raise alpha. skip those that appear clearly futile!
106-
bool reduce = expandedNodes > 1 && !isChecked && (move.Promotion < Piece.Queen) && !child.IsChecked(child.SideToMove);
107-
if (reduce && depth <= 4 && window.FailLow(child.Score + futilityMargin, color))
108-
continue;
109-
110-
//moves after the PV node are unlikely to raise alpha. searching with a null-sized window can save a lot of nodes
111-
if (expandedNodes > 1 && depth >= 3)
103+
//moves after the PV node are unlikely to raise alpha. try to avoid a full evaluation!
104+
if(expandedNodes > 1)
112105
{
113-
//we can save a lot of nodes by searching with "null window" first, proving cheaply that the score is below alpha...
114-
int R = reduce && expandedNodes >= 4 ? 1 : 0;
115-
SearchWindow nullWindow = window.GetLowerBound(color);
116-
var nullResult = EvalPositionTT(child, depth - 1 - R, nullWindow);
117-
if (nullWindow.FailLow(nullResult.Score, color))
118-
continue;
106+
bool tactical = isChecked || (move.Promotion > Piece.Queen) || child.IsChecked(child.SideToMove);
107+
108+
//some moves are hopeless and can be skipped without deeper evaluation
109+
if (depth <= 4 && !tactical)
110+
{
111+
int futilityMargin = (int)color * depth * MAX_GAIN_PER_PLY;
112+
if (window.FailLow(child.Score + futilityMargin, color))
113+
continue;
114+
}
115+
116+
//other moves are searched with a null-sized window and skipped if they don't raise alpha
117+
if (depth >= 2)
118+
{
119+
//non-tactical late moves are searched at a reduced depth to make this test even faster!
120+
int R = (tactical || expandedNodes < 4) ? 0 : 2;
121+
(int score, _) = EvalPositionTT(child, depth - R - 1, window.GetLowerBound(color));
122+
if (window.FailLow(score, color))
123+
continue;
124+
}
119125
}
120126

121-
//this node may raise alpha!
127+
//this move is expected to raise alpha so we search at full depth!
122128
var eval = EvalPositionTT(child, depth - 1, window);
123129
if (window.FailLow(eval.Score, color))
124130
{
125131
_history.Bad(position, move, depth);
126132
continue;
127133
}
128134

135+
//the position has a new best move and score!
129136
Transpositions.Store(position.ZobristHash, depth, window, eval.Score, move);
130-
//store the PV beginning with move, followed by the PV of the childnode
137+
//set the PV to this move, followed by the PV of the childnode
131138
pv = Merge(move, eval.PV);
132-
//...and maybe get a beta cutoff
139+
//...and maybe we even get a beta cutoff
133140
if (window.Cut(eval.Score, color))
134141
{
135142
//we remember killers like hat!

MinimalChess/MoveCollection.cs

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using System.Collections.Generic;
1+
using System;
2+
using System.Collections.Generic;
23

34
namespace MinimalChess
45
{
@@ -53,7 +54,31 @@ internal static MoveList SortedCaptures(Board position)
5354
return captures;
5455
}
5556

56-
public void SortMvvLva(Board context)
57+
internal static MoveList SortedQuiets(Board position, History history, float threshold)
58+
{
59+
MoveList quiets = new MoveList();
60+
position.CollectQuiets(move =>
61+
{
62+
float score = history.Value(position, move);
63+
//if score >= threshold insertion-sort else just add
64+
int index = score >= threshold ? quiets.FindIndex(m => history.Value(position, m) <= score) : -1;
65+
if (index >= 0)
66+
quiets.Insert(index, move);
67+
else
68+
quiets.Add(move);
69+
});
70+
return quiets;
71+
}
72+
73+
public static MoveList SortedQuiets(Board position, History history)
74+
{
75+
MoveList quiets = new MoveList();
76+
position.CollectQuiets(quiets.Add);
77+
quiets.SortHistory(position, history);
78+
return quiets;
79+
}
80+
81+
private void SortMvvLva(Board context)
5782
{
5883
int Score(Move move)
5984
{
@@ -64,7 +89,7 @@ int Score(Move move)
6489
Sort((a, b) => Score(b).CompareTo(Score(a)));
6590
}
6691

67-
public void SortHistory(Board context, History history)
92+
private void SortHistory(Board context, History history)
6893
{
6994
Sort((a, b) => history.Value(context, b).CompareTo(history.Value(context, a)));
7095
}

MinimalChess/Playmaker.cs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.Diagnostics;
34

45
namespace MinimalChess
56
{
@@ -35,10 +36,7 @@ public static class Playmaker
3536
}
3637

3738
//4. Play quiet moves that aren't known killers
38-
var quiets = MoveList.Quiets(position);
39-
if (depth >= 3)
40-
quiets.SortHistory(position, history);
41-
foreach (var move in quiets)
39+
foreach (var move in MoveList.SortedQuiets(position, history))
4240
{
4341
if (killers.Contains(depth, move))
4442
continue;

MinimalChess/SearchWindow.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ public bool Cut(int score, Color color)
4242

4343
public bool FailLow(int score, Color color) => color == Color.White ? (score <= Floor) : (score >= Ceiling);
4444

45-
//public bool FailHigh(int score, Color color) => color == Color.White ? (score >= Ceiling) : (score <= Floor);
45+
public bool FailHigh(int score, Color color) => color == Color.White ? (score >= Ceiling) : (score <= Floor);
4646

4747
public int GetScore(Color color) => color == Color.White ? Floor : Ceiling;
4848
}

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

0 commit comments

Comments
 (0)