Skip to content

Commit

Permalink
⚡ Remove Position.MakeMoveCalculatingCapturedPiece, using `Position…
Browse files Browse the repository at this point in the history
….Board` instead (#1021)
  • Loading branch information
eduherminio authored Sep 17, 2024
1 parent eb9bf40 commit b33f5c9
Show file tree
Hide file tree
Showing 8 changed files with 74 additions and 235 deletions.
28 changes: 19 additions & 9 deletions src/Lynx.Benchmark/MakeUnmakeMove_implementation_Benchmark.cs
Original file line number Diff line number Diff line change
Expand Up @@ -145,14 +145,15 @@
namespace Lynx.Benchmark;
public class MakeUnmakeMove_implementation_Benchmark : BaseBenchmark
{
public static IEnumerable<(string, int)> Data => new[] {
(Constants.InitialPositionFEN, 4),
(Constants.TrickyTestPositionFEN, 4),
("r4rk1/1pp1qppp/p1np1n2/2b1p1B1/2B1P1b1/P1NP1N2/1PP1QPPP/R4RK1 w - - 0 10", 4),
("3K4/8/8/8/8/8/4p3/2k2R2 b - - 0 1", 6),
("2K2r2/4P3/8/8/8/8/8/3k4 w - - 0 1", 6),
("8/p7/8/1P6/K1k3p1/6P1/7P/8 w - -", 6),
};
public static IEnumerable<(string, int)> Data =>
[
(Constants.InitialPositionFEN, 4),
(Constants.TrickyTestPositionFEN, 4),
("r4rk1/1pp1qppp/p1np1n2/2b1p1B1/2B1P1b1/P1NP1N2/1PP1QPPP/R4RK1 w - - 0 10", 4),
("3K4/8/8/8/8/8/4p3/2k2R2 b - - 0 1", 6),
("2K2r2/4P3/8/8/8/8/8/3k4 w - - 0 1", 6),
("8/p7/8/1P6/K1k3p1/6P1/7P/8 w - -", 6),
];

[Benchmark(Baseline = true)]
[ArgumentsSource(nameof(Data))]
Expand Down Expand Up @@ -297,6 +298,8 @@ public struct MakeMovePosition

public BitBoard[] OccupancyBitBoards { get; }

public int[] Board { get; }

public Side Side { get; private set; }

public BoardSquare EnPassant { get; private set; }
Expand All @@ -312,6 +315,7 @@ public MakeMovePosition((BitBoard[] PieceBitBoards, BitBoard[] OccupancyBitBoard
{
PieceBitBoards = parsedFEN.PieceBitBoards;
OccupancyBitBoards = parsedFEN.OccupancyBitBoards;
Board = parsedFEN.board;
Side = parsedFEN.Side;
Castle = parsedFEN.Castle;
EnPassant = parsedFEN.EnPassant;
Expand All @@ -333,6 +337,9 @@ public MakeMovePosition(MakeMovePosition position)
OccupancyBitBoards = new BitBoard[3];
Array.Copy(position.OccupancyBitBoards, OccupancyBitBoards, position.OccupancyBitBoards.Length);

Board = new int[64];
Array.Copy(position.Board, Board, position.Board.Length);

Side = position.Side;
Castle = position.Castle;
EnPassant = position.EnPassant;
Expand All @@ -354,6 +361,9 @@ public MakeMovePosition(MakeMovePosition position, bool nullMove)
OccupancyBitBoards = new BitBoard[3];
Array.Copy(position.OccupancyBitBoards, OccupancyBitBoards, position.OccupancyBitBoards.Length);

Board = new int[64];
Array.Copy(position.Board, Board, position.Board.Length);

Side = (Side)Utils.OppositeSide(position.Side);
Castle = position.Castle;
EnPassant = BoardSquare.noSquare;
Expand Down Expand Up @@ -1645,7 +1655,7 @@ internal static void GeneratePawnMoves(ref int localIndex, Move[] movePool, Make
}
else
{
movePool[localIndex++] = MoveExtensions.EncodeCapture(sourceSquare, targetSquare, piece);
movePool[localIndex++] = MoveExtensions.EncodeCapture(sourceSquare, targetSquare, piece, position.Board[targetSquare]);
}
}
}
Expand Down
11 changes: 10 additions & 1 deletion src/Lynx.Benchmark/MakeUnmakeMove_integration_Benchmark.cs
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,8 @@ public struct MakeMovePosition

public BitBoard[] OccupancyBitBoards { get; }

public int[] Board { get; }

public Side Side { get; private set; }

public BoardSquare EnPassant { get; private set; }
Expand All @@ -314,6 +316,7 @@ public MakeMovePosition((BitBoard[] PieceBitBoards, BitBoard[] OccupancyBitBoard
{
PieceBitBoards = parsedFEN.PieceBitBoards;
OccupancyBitBoards = parsedFEN.OccupancyBitBoards;
Board = parsedFEN.board;
Side = parsedFEN.Side;
Castle = parsedFEN.Castle;
EnPassant = parsedFEN.EnPassant;
Expand All @@ -335,6 +338,9 @@ public MakeMovePosition(MakeMovePosition position)
OccupancyBitBoards = new BitBoard[3];
Array.Copy(position.OccupancyBitBoards, OccupancyBitBoards, position.OccupancyBitBoards.Length);

Board = new int[64];
Array.Copy(position.Board, Board, position.Board.Length);

Side = position.Side;
Castle = position.Castle;
EnPassant = position.EnPassant;
Expand All @@ -356,6 +362,9 @@ public MakeMovePosition(MakeMovePosition position, bool nullMove)
OccupancyBitBoards = new BitBoard[3];
Array.Copy(position.OccupancyBitBoards, OccupancyBitBoards, position.OccupancyBitBoards.Length);

Board = new int[64];
Array.Copy(position.Board, Board, position.Board.Length);

Side = (Side)Utils.OppositeSide(position.Side);
Castle = position.Castle;
EnPassant = BoardSquare.noSquare;
Expand Down Expand Up @@ -1512,7 +1521,7 @@ internal static void GeneratePawnMoves(ref int localIndex, Move[] movePool, Make
}
else
{
movePool[localIndex++] = MoveExtensions.EncodeCapture(sourceSquare, targetSquare, piece);
movePool[localIndex++] = MoveExtensions.EncodeCapture(sourceSquare, targetSquare, piece, position.Board[targetSquare]);
}
}
}
Expand Down
20 changes: 9 additions & 11 deletions src/Lynx.Benchmark/MoveGeneratorParallel_Benchmark.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,14 @@ namespace Lynx.Benchmark;

public class MoveGeneratorParallel_Benchmark : BaseBenchmark
{
public static IEnumerable<string> Data => new[]
{
Constants.InitialPositionFEN,
Constants.TrickyTestPositionFEN,
Constants.TrickyTestPositionReversedFEN,
Constants.CmkTestPositionFEN,
Constants.KillerTestPositionFEN
};
public static IEnumerable<string> Data =>
[
Constants.InitialPositionFEN,
Constants.TrickyTestPositionFEN,
Constants.TrickyTestPositionReversedFEN,
Constants.CmkTestPositionFEN,
Constants.KillerTestPositionFEN
];

[Benchmark(Baseline = true)]
[ArgumentsSource(nameof(Data))]
Expand Down Expand Up @@ -106,8 +106,6 @@ file static class CustomMoveGenerator
{
private static readonly Logger _logger = LogManager.GetCurrentClassLogger();

private const int TRUE = 1;

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static IOrderedEnumerable<Move> GenerateAllMoves_SingleThread(Position position, int[,]? killerMoves = null, int? plies = null, bool capturesOnly = false)
{
Expand Down Expand Up @@ -273,7 +271,7 @@ internal static IEnumerable<Move> GeneratePawnMoves(Position position, int offse
}
else
{
yield return MoveExtensions.EncodeCapture(sourceSquare, targetSquare, piece);
yield return MoveExtensions.EncodeCapture(sourceSquare, targetSquare, piece, position.Board[targetSquare]);
}
}
}
Expand Down
1 change: 0 additions & 1 deletion src/Lynx.Benchmark/Move_UCIString_Benchmark.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ public class Move_UCIString_Benchmark : BaseBenchmark
MoveExtensions.EncodePromotion((int)BoardSquare.e7, (int)BoardSquare.e8, (int)Piece.p, promotedPiece: (int)Piece.q),
MoveExtensions.EncodePromotion((int)BoardSquare.a7, (int)BoardSquare.b8, (int)Piece.p, promotedPiece: (int)Piece.n, capturedPiece: (int)Piece.B),
MoveExtensions.EncodeCapture((int)BoardSquare.a8, (int)BoardSquare.h1, (int)Piece.B, capturedPiece: (int)Piece.b),
MoveExtensions.EncodeCapture((int)BoardSquare.a8, (int)BoardSquare.h1, (int)Piece.B),
MoveExtensions.EncodeEnPassant((int)BoardSquare.e5, (int)BoardSquare.d6, (int)Piece.P)
];

Expand Down
34 changes: 0 additions & 34 deletions src/Lynx/Model/Move.cs
Original file line number Diff line number Diff line change
Expand Up @@ -117,22 +117,6 @@ public static Move EncodeCapture(int sourceSquare, int targetSquare, int piece,
| (1 << IsCaptureOffset);
}

/// <summary>
/// Override when captured piece isn't provided
/// </summary>
/// <param name="sourceSquare"></param>
/// <param name="targetSquare"></param>
/// <param name="piece"></param>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Move EncodeCapture(int sourceSquare, int targetSquare, int piece)
{
return (sourceSquare << SourceSquareOffset)
| (targetSquare << TargetSquareOffset)
| (piece << PieceOffset)
| (1 << IsCaptureOffset);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Move EncodePromotion(int sourceSquare, int targetSquare, int piece, int promotedPiece)
{
Expand All @@ -153,24 +137,6 @@ public static Move EncodePromotion(int sourceSquare, int targetSquare, int piece
| (1 << IsCaptureOffset);
}

/// <summary>
/// Override when captured piece isn't provided
/// </summary>
/// <param name="sourceSquare"></param>
/// <param name="targetSquare"></param>
/// <param name="piece"></param>
/// <param name="promotedPiece"></param>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Move EncodePromotionWithCapture(int sourceSquare, int targetSquare, int piece, int promotedPiece)
{
return promotedPiece
| (sourceSquare << SourceSquareOffset)
| (targetSquare << TargetSquareOffset)
| (piece << PieceOffset)
| (1 << IsCaptureOffset);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Move EncodeCapturedPiece(int move, int capturedPiece) => move | (capturedPiece << 20);

Expand Down
146 changes: 0 additions & 146 deletions src/Lynx/Model/Position.cs
Original file line number Diff line number Diff line change
Expand Up @@ -232,152 +232,6 @@ public GameState MakeMove(Move move)
//}
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public GameState MakeMoveCalculatingCapturedPiece(ref Move move)
{
byte castleCopy = Castle;
BoardSquare enpassantCopy = EnPassant;
long uniqueIdentifierCopy = UniqueIdentifier;

var oldSide = (int)Side;
var offset = Utils.PieceOffset(oldSide);
var oppositeSide = Utils.OppositeSide(oldSide);

int sourceSquare = move.SourceSquare();
int targetSquare = move.TargetSquare();
int piece = move.Piece();
int promotedPiece = move.PromotedPiece();
int capturedPiece = Board[targetSquare];

var newPiece = piece;
if (promotedPiece != default)
{
newPiece = promotedPiece;
}

PieceBitBoards[piece].PopBit(sourceSquare);
OccupancyBitBoards[oldSide].PopBit(sourceSquare);
Board[sourceSquare] = (int)Piece.None;

PieceBitBoards[newPiece].SetBit(targetSquare);
OccupancyBitBoards[oldSide].SetBit(targetSquare);
Board[targetSquare] = newPiece;

UniqueIdentifier ^=
ZobristTable.SideHash()
^ ZobristTable.PieceHash(sourceSquare, piece)
^ ZobristTable.PieceHash(targetSquare, newPiece)
^ ZobristTable.EnPassantHash((int)EnPassant) // We clear the existing enpassant square, if any
^ ZobristTable.CastleHash(Castle); // We clear the existing castle rights

EnPassant = BoardSquare.noSquare;

switch (move.SpecialMoveFlag())
{
case SpecialMoveType.DoublePawnPush:
{
var pawnPush = +8 - (oldSide * 16);
var enPassantSquare = sourceSquare + pawnPush;
Utils.Assert(Constants.EnPassantCaptureSquares.Length > enPassantSquare && Constants.EnPassantCaptureSquares[enPassantSquare] != 0, $"Unexpected en passant square : {(BoardSquare)enPassantSquare}");

EnPassant = (BoardSquare)enPassantSquare;
UniqueIdentifier ^= ZobristTable.EnPassantHash(enPassantSquare);

break;
}
case SpecialMoveType.ShortCastle:
{
var rookSourceSquare = Utils.ShortCastleRookSourceSquare(oldSide);
var rookTargetSquare = Utils.ShortCastleRookTargetSquare(oldSide);
var rookIndex = (int)Piece.R + offset;

PieceBitBoards[rookIndex].PopBit(rookSourceSquare);
OccupancyBitBoards[oldSide].PopBit(rookSourceSquare);
Board[rookSourceSquare] = (int)Piece.None;

PieceBitBoards[rookIndex].SetBit(rookTargetSquare);
OccupancyBitBoards[oldSide].SetBit(rookTargetSquare);
Board[rookTargetSquare] = rookIndex;

UniqueIdentifier ^=
ZobristTable.PieceHash(rookSourceSquare, rookIndex)
^ ZobristTable.PieceHash(rookTargetSquare, rookIndex);

break;
}
case SpecialMoveType.LongCastle:
{
var rookSourceSquare = Utils.LongCastleRookSourceSquare(oldSide);
var rookTargetSquare = Utils.LongCastleRookTargetSquare(oldSide);
var rookIndex = (int)Piece.R + offset;

PieceBitBoards[rookIndex].PopBit(rookSourceSquare);
OccupancyBitBoards[oldSide].PopBit(rookSourceSquare);
Board[rookSourceSquare] = (int)Piece.None;

PieceBitBoards[rookIndex].SetBit(rookTargetSquare);
OccupancyBitBoards[oldSide].SetBit(rookTargetSquare);
Board[rookTargetSquare] = rookIndex;

UniqueIdentifier ^=
ZobristTable.PieceHash(rookSourceSquare, rookIndex)
^ ZobristTable.PieceHash(rookTargetSquare, rookIndex);

break;
}

case SpecialMoveType.EnPassant:
{
var oppositePawnIndex = (int)Piece.p - offset;

var capturedPawnSquare = Constants.EnPassantCaptureSquares[targetSquare];
Utils.Assert(PieceBitBoards[oppositePawnIndex].GetBit(capturedPawnSquare), $"Expected {(Side)oppositeSide} pawn in {capturedPawnSquare}");

PieceBitBoards[oppositePawnIndex].PopBit(capturedPawnSquare);
OccupancyBitBoards[oppositeSide].PopBit(capturedPawnSquare);
Board[capturedPawnSquare] = (int)Piece.None;
UniqueIdentifier ^= ZobristTable.PieceHash(capturedPawnSquare, oppositePawnIndex);
move = MoveExtensions.EncodeCapturedPiece(move, oppositePawnIndex);

break;
}
default:
{
if (move.IsCapture())
{
Debug.Assert(capturedPiece != (int)Piece.None, $"Expected piece at {targetSquare}, since it was supposed to be captured");

PieceBitBoards[capturedPiece].PopBit(targetSquare);
OccupancyBitBoards[oppositeSide].PopBit(targetSquare);
// No need to update Board here, it already has newPiece

move = MoveExtensions.EncodeCapturedPiece(move, capturedPiece);

UniqueIdentifier ^= ZobristTable.PieceHash(targetSquare, capturedPiece);
}

break;
}
}

Side = (Side)oppositeSide;
OccupancyBitBoards[2] = OccupancyBitBoards[1] | OccupancyBitBoards[0];

// Updating castling rights
Castle &= Constants.CastlingRightsUpdateConstants[sourceSquare];
Castle &= Constants.CastlingRightsUpdateConstants[targetSquare];

UniqueIdentifier ^= ZobristTable.CastleHash(Castle);

return new GameState(uniqueIdentifierCopy, enpassantCopy, castleCopy);
//var clone = new Position(this);
//clone.UnmakeMove(move, gameState);
//if (uniqueIdentifierCopy != clone.UniqueIdentifier)
//{
// throw new($"{FEN()}: {uniqueIdentifierCopy} expected, got {clone.UniqueIdentifier} got after Make/Unmake move {move.ToEPDString()}");
//}
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void UnmakeMove(Move move, GameState gameState)
{
Expand Down
Loading

0 comments on commit b33f5c9

Please sign in to comment.