diff --git a/Chess-Challenge/src/API/Board.cs b/Chess-Challenge/src/API/Board.cs index b85d1c383..fdcdec3da 100644 --- a/Chess-Challenge/src/API/Board.cs +++ b/Chess-Challenge/src/API/Board.cs @@ -239,6 +239,12 @@ public bool IsDraw() /// public bool IsInsufficientMaterial() => Arbiter.InsufficentMaterial(board); + /// + /// Does the given player has castled? + /// (this will only detect castled made during the game moves) + /// + public bool HasCastled(bool white) => white ? board.currentGameState.hasWhiteCastled : board.currentGameState.hasBlackCastled; + /// /// Does the given player still have the right to castle kingside? /// Note that having the right to castle doesn't necessarily mean castling is legal right now diff --git a/Chess-Challenge/src/Framework/Chess/Board/Board.cs b/Chess-Challenge/src/Framework/Chess/Board/Board.cs index 9fd4c1f3b..f92a187e5 100644 --- a/Chess-Challenge/src/Framework/Chess/Board/Board.cs +++ b/Chess-Challenge/src/Framework/Chess/Board/Board.cs @@ -138,6 +138,9 @@ public void MakeMove(Move move, bool inSearch = true) int newCastlingRights = currentGameState.castlingRights; int newEnPassantFile = 0; + bool hasWhiteCastled = currentGameState.hasWhiteCastled || IsWhiteToMove && move.MoveFlag == Move.CastleFlag; + bool hasBlackCastled = currentGameState.hasBlackCastled || !IsWhiteToMove && move.MoveFlag == Move.CastleFlag; + // Update bitboard of moved piece (pawn promotion is a special case and is corrected later) MovePiece(movedPiece, startSquare, targetSquare); @@ -275,7 +278,7 @@ public void MakeMove(Move move, bool inSearch = true) newFiftyMoveCounter = 0; } - GameState newState = new(capturedPieceType, newEnPassantFile, newCastlingRights, newFiftyMoveCounter, newZobristKey); + GameState newState = new(capturedPieceType, newEnPassantFile, newCastlingRights, hasWhiteCastled, hasBlackCastled, newFiftyMoveCounter, newZobristKey); gameStateHistory.Push(newState); currentGameState = newState; hasCachedInCheckValue = false; @@ -400,7 +403,7 @@ public void MakeNullMove() newZobristKey ^= Zobrist.sideToMove; newZobristKey ^= Zobrist.enPassantFile[currentGameState.enPassantFile]; - GameState newState = new(PieceHelper.None, 0, currentGameState.castlingRights, currentGameState.fiftyMoveCounter + 1, newZobristKey); + GameState newState = new (PieceHelper.None, 0, currentGameState.castlingRights, currentGameState.hasWhiteCastled, currentGameState.hasBlackCastled, currentGameState.fiftyMoveCounter + 1, newZobristKey); currentGameState = newState; gameStateHistory.Push(currentGameState); UpdateSliderBitboards(); @@ -519,9 +522,9 @@ public void LoadPosition(FenUtility.PositionInfo posInfo) plyCount = (posInfo.moveCount - 1) * 2 + (IsWhiteToMove ? 0 : 1); // Set game state (note: calculating zobrist key relies on current game state) - currentGameState = new GameState(PieceHelper.None, posInfo.epFile, castlingRights, posInfo.fiftyMovePlyCount, 0); + currentGameState = new GameState(PieceHelper.None, posInfo.epFile, castlingRights, false, false, posInfo.fiftyMovePlyCount, 0); ulong zobristKey = Zobrist.CalculateZobristKey(this); - currentGameState = new GameState(PieceHelper.None, posInfo.epFile, castlingRights, posInfo.fiftyMovePlyCount, zobristKey); + currentGameState = new GameState(PieceHelper.None, posInfo.epFile, castlingRights, false, false, posInfo.fiftyMovePlyCount, zobristKey); RepetitionPositionHistory.Push(zobristKey); diff --git a/Chess-Challenge/src/Framework/Chess/Board/GameState.cs b/Chess-Challenge/src/Framework/Chess/Board/GameState.cs index 23619d471..8e86bd5f2 100644 --- a/Chess-Challenge/src/Framework/Chess/Board/GameState.cs +++ b/Chess-Challenge/src/Framework/Chess/Board/GameState.cs @@ -5,6 +5,8 @@ public readonly struct GameState public readonly int capturedPieceType; public readonly int enPassantFile; public readonly int castlingRights; + public readonly bool hasWhiteCastled; + public readonly bool hasBlackCastled; public readonly int fiftyMoveCounter; public readonly ulong zobristKey; @@ -13,11 +15,13 @@ public readonly struct GameState public const int ClearBlackKingsideMask = 0b1011; public const int ClearBlackQueensideMask = 0b0111; - public GameState(int capturedPieceType, int enPassantFile, int castlingRights, int fiftyMoveCounter, ulong zobristKey) + public GameState(int capturedPieceType, int enPassantFile, int castlingRights, bool hasWhiteCastled, bool hasBlackCastled, int fiftyMoveCounter, ulong zobristKey) { this.capturedPieceType = capturedPieceType; this.enPassantFile = enPassantFile; this.castlingRights = castlingRights; + this.hasWhiteCastled = hasWhiteCastled; + this.hasBlackCastled = hasBlackCastled; this.fiftyMoveCounter = fiftyMoveCounter; this.zobristKey = zobristKey; }