Skip to content

Commit

Permalink
Implement Killer move heuristic
Browse files Browse the repository at this point in the history
In closed positions with very few good captures, this heuristic cuts down the search tree much faster. Easiest example is FEN "r2q1rk1/p1p1ppbp/2pp1np1/8/3PP3/2N2Q1P/PPP2PP1/R1B1K2R w KQ - 0 10". At depth 6, this brings down node traversal count from 758872 to 158769 - a huge improvement.
  • Loading branch information
znxftw committed Feb 24, 2022
1 parent 0fcc9c8 commit 8caf1a2
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 4 deletions.
22 changes: 20 additions & 2 deletions Rudim/Board/MoveOrdering.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ namespace Rudim.Board
static class MoveOrdering
{
private static readonly int[,] MVVLVA;
private static Move[,] KillerMoves;

static MoveOrdering()
{
Expand All @@ -18,11 +19,20 @@ static MoveOrdering()
{ 0, 0, 0, 0, 0, 0, 0 }, // K
{ 0, 0, 0, 0, 0, 0, 0 } // None
};
KillerMoves = new Move[2, Constants.MaxPly];
}
public static void PopulateMoveScore(Move move, BoardState boardState)
public static void PopulateMoveScore(Move move, BoardState boardState, int ply = Constants.MaxPly - 1)
{
if (!move.IsCapture())
move.Score = 0;
{
if (move == KillerMoves[0, ply])
move.Score = 9; // TODO : Revisit, assign better values and extract to constants
else if (move == KillerMoves[1, ply])
move.Score = 8;
else
move.Score = 0;
return;
}
var targetPiece = (int)Piece.None;
var sourcePiece = boardState.GetPieceOn(move.Source, boardState.SideToMove);
if (move.Type == MoveTypes.EnPassant)
Expand All @@ -32,6 +42,14 @@ public static void PopulateMoveScore(Move move, BoardState boardState)
move.Score = MVVLVA[targetPiece, sourcePiece];
}

public static void AddKillerMove(Move move, int ply)
{
if (KillerMoves[0, ply] != move)
{
KillerMoves[1, ply] = KillerMoves[0, ply];
KillerMoves[0, ply] = move;
}
}
public static void SortMoves(BoardState boardState)
{
// TODO : Partially sort within the loop only to avoid sorting elements that are not going to be queried after beta cutoff?
Expand Down
1 change: 1 addition & 0 deletions Rudim/Common/Constants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@ public static class Constants
public const int MaxRookMask = 1 << 12;
public const int MaxMaskIndex = MaxRookMask;
public const int MaxCentipawnEval = 49000;
public const int MaxPly = 64;
}
}
31 changes: 30 additions & 1 deletion Rudim/Common/Move.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
using Rudim.Board;
using System;
using System.Collections.Generic;

namespace Rudim.Common
{
public class Move
public class Move : IEquatable<Move>
{
public Square Source { get; set; }
public Square Target { get; set; }
Expand Down Expand Up @@ -66,5 +67,33 @@ private static Square ParseFromString(string squareString)
_ = Enum.TryParse(squareString, out square);
return square;
}

public override bool Equals(object obj)
{
return Equals(obj as Move);
}

public bool Equals(Move other)
{
return other != null &&
Source == other.Source &&
Target == other.Target &&
EqualityComparer<MoveType>.Default.Equals(Type, other.Type);
}

public override int GetHashCode()
{
return HashCode.Combine(Source, Target, Type);
}

public static bool operator ==(Move left, Move right)
{
return EqualityComparer<Move>.Default.Equals(left, right);
}

public static bool operator !=(Move left, Move right)
{
return !(left == right);
}
}
}
7 changes: 6 additions & 1 deletion Rudim/Search/Negamax.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,11 @@ public static int Search(BoardState boardState, int depth, int alpha, int beta)
Move bestEvaluation = null;

boardState.GenerateMoves();
var ply = SearchDepth - depth;
// TODO : Flag in GenerateMoves to avoid extra iteration?
foreach (var move in boardState.Moves)
{
MoveOrdering.PopulateMoveScore(move, boardState);
MoveOrdering.PopulateMoveScore(move, boardState, ply);
}

MoveOrdering.SortMoves(boardState);
Expand All @@ -42,7 +43,11 @@ public static int Search(BoardState boardState, int depth, int alpha, int beta)
boardState.UnmakeMove(move);
numberOfLegalMoves++;
if (score >= beta)
{
if (!move.IsCapture())
MoveOrdering.AddKillerMove(move, ply);
return beta;
}
if (score > alpha)
{
alpha = score;
Expand Down

0 comments on commit 8caf1a2

Please sign in to comment.