This is how I fixed the castle bug, hope this helps! -Phrozen
Phr0z3nn opened this issue · 1 comments
Hello, I've been working on my own version of EmmyChess and I managed to fix the castle bug. My current version is very different from the asset so I will post some of the code to fix castle for the asset. If you want to see the changes I've made to emmy chess you can check out the Vrchat Map "Cozy Space". I had to basicly not call functions directly in order to avoid the crashing issue that came up a lot, so it caused me to update bools and call the bools instead of the direct function. I hope this helps, I am very new to coding, fixing this took probably a straight month of work.
//(added to defaultrules)
//Top part -
[HideInInspector]
public bool BlackLeftCastle = true;
[HideInInspector]
public bool BlackRightCastle = true;
[HideInInspector]
public bool WhiteLeftCastle = true;
[HideInInspector]
public bool WhiteRightCastle = true;
[HideInInspector]
public bool BlackMoveLeftCastle = true;
[HideInInspector]
public bool BlackMoveRightCastle = true;
[HideInInspector]
public bool WhiteMoveLeftCastle = true;
[HideInInspector]
public bool WhiteMoveRightCastle = true;
[HideInInspector]
public bool WhitePiecesRightCastle = false;
[HideInInspector]
public bool WhitePiecesLeftCastle = false;
[HideInInspector]
public bool BlackPiecesRightCastle = false;
[HideInInspector]
public bool BlackPiecesLeftCastle = false; //I also added all these exactly the same to start() might not be important.
[HideInInspector]
[UdonSynced]
public bool CastleInCheck = false;
//Added functions -
// (pseudolegalmoves)
else if (type == "king")
{
for (int i = -1; i < 2; i++)
{
for (int j = -1; j < 2; j++)
{
Piece squarepiece = board.GetGridPiece(x + i, y + j, grid);
if (squarepiece == null || (squarepiece != null && squarepiece.white != white))
{
index = AppendMove(index, x + i, y + j, legalMoves);
}
}
}
if (white)
{
if (WhiteRightCastle && WhiteMoveRightCastle && WhitePiecesRightCastle && !CastleInCheck)
{
index = AppendMove(index, x + 2, y, legalMoves);
}
if (WhiteLeftCastle && WhiteMoveLeftCastle && WhitePiecesLeftCastle && !CastleInCheck)
{
index = AppendMove(index, x - 2, y, legalMoves);
}
}
else
{
if (BlackRightCastle && BlackMoveRightCastle && BlackPiecesRightCastle && !CastleInCheck)
{
index = AppendMove(index, x + 2, y, legalMoves);
}
if (BlackLeftCastle && BlackMoveLeftCastle && BlackPiecesLeftCastle && !CastleInCheck)
{
index = AppendMove(index, x - 2, y, legalMoves);
}
}
}
//(iskingincheck)
if (opponentPseudoLegalMove == legalMovesEndMarker) { break; }
else
{
if (opponentPseudoLegalMove == threatenedPos)
{
isKingChecked = true;
CastleInCheck = true; //this is all thats added in order to not directly call iskingincheck
break;
}
}
//(new)
public void CastleMoveCheck()
{
WhiteMoveRightCastle = true;
BlackMoveRightCastle = true;
WhiteMoveLeftCastle = true;
BlackMoveLeftCastle = true;
RequestSerialization();
}
public void CastleNotMoved(Piece movedPiece)
{
if (movedPiece.type == "king")
{
if (movedPiece.white)
{
WhiteMoveRightCastle = false;
WhiteMoveLeftCastle = false;
}
else
{
BlackMoveRightCastle = false;
BlackMoveLeftCastle = false;
}
}
else if (movedPiece.type == "rook")
{
if (movedPiece.white)
{
if (movedPiece.x == 0 && movedPiece.y == 0) // Left rook initial position for white
{
WhiteMoveLeftCastle = false;
}
else if (movedPiece.x == 7 && movedPiece.y == 0) // Right rook initial position for white
{
WhiteMoveRightCastle = false;
}
}
else
{
if (movedPiece.x == 0 && movedPiece.y == 7) // Left rook initial position for black
{
BlackMoveLeftCastle = false;
}
else if (movedPiece.x == 7 && movedPiece.y == 7) // Right rook initial position for black
{
BlackMoveRightCastle = false;
}
}
}
RequestSerialization();
}
public void CheckCastlePaths(Piece[] grid, Board board)
{
if (grid == null) { Debug.LogWarning("Empty grid, might be first turn"); return; }
// Check White Right Castle
WhitePiecesRightCastle = true;
for (int i = 5; i < 7; i++) // Check squares between king and right rook for white
{
if (board.GetGridPiece(i, 0, grid) != null) // Assuming white's back rank is y = 0
{
WhitePiecesRightCastle = false;
break;
}
}
// Check White Left Castle
WhitePiecesLeftCastle = true;
for (int i = 1; i < 4; i++) // Check squares between king and left rook for white
{
if (board.GetGridPiece(i, 0, grid) != null) // Assuming white's back rank is y = 0
{
WhitePiecesLeftCastle = false;
break;
}
}
// Check Black Right Castle
BlackPiecesRightCastle = true;
for (int i = 5; i < 7; i++) // Check squares between king and right rook for black
{
if (board.GetGridPiece(i, 7, grid) != null) // Assuming black's back rank is y = 7
{
BlackPiecesRightCastle = false;
break;
}
}
// Check Black Left Castle
BlackPiecesLeftCastle = true;
for (int i = 1; i < 4; i++) // Check squares between king and left rook for black
{
if (board.GetGridPiece(i, 7, grid) != null) // Assuming black's back rank is y = 7
{
BlackPiecesLeftCastle = false;
break;
}
}
RequestSerialization();
}
public void CheckCastleSafety(Piece[] grid, Board board)
{
// Check squares next to the White King
Vector2 whiteKingPos = board.whiteKing.GetVec();
WhiteLeftCastle = !(IsSquareUnderAttack((int)whiteKingPos.x - 1, (int)whiteKingPos.y, false, grid, board) ||
IsSquareUnderAttack((int)whiteKingPos.x - 2, (int)whiteKingPos.y, false, grid, board));
WhiteRightCastle = !(IsSquareUnderAttack((int)whiteKingPos.x + 1, (int)whiteKingPos.y, false, grid, board) ||
IsSquareUnderAttack((int)whiteKingPos.x + 2, (int)whiteKingPos.y, false, grid, board));
// Check squares next to the Black King
Vector2 blackKingPos = board.blackKing.GetVec();
BlackLeftCastle = !(IsSquareUnderAttack((int)blackKingPos.x - 1, (int)blackKingPos.y, true, grid, board) ||
IsSquareUnderAttack((int)blackKingPos.x - 2, (int)blackKingPos.y, true, grid, board));
BlackRightCastle = !(IsSquareUnderAttack((int)blackKingPos.x + 1, (int)blackKingPos.y, true, grid, board) ||
IsSquareUnderAttack((int)blackKingPos.x + 2, (int)blackKingPos.y, true, grid, board));
RequestSerialization();
}
private bool IsSquareUnderAttack(int x, int y, bool byWhite, Piece[] grid, Board board)
{
foreach (Piece piece in board.GetAllPieces())
{
if (piece.white == byWhite)
{
Vector2[] pseudoLegalMoves = GetAllPseudoLegalMovesGrid(piece, grid, board.PawnThatDidADoublePushLastRound,
board);
foreach (Vector2 move in pseudoLegalMoves)
{
if (move == legalMovesEndMarker) break;
if (move.x == x && move.y == y)
{
return true;
}
}
}
}
return false;
}
//(modified GetAlllegalMoves)
public Vector2[] GetAllLegalMoves(Piece movedPiece, Board board)
{
Vector2[] pseudoLegalMoves = GetAllPseudoLegalMovesGrid(movedPiece, board.grid, board.PawnThatDidADoublePushLastRound, board);
Vector2 piecePos = movedPiece.GetVec();
Piece king = movedPiece.white ? board.whiteKing : board.blackKing;
if (king != null)
{
Vector2 kingPos = king.GetVec();
Piece[] currentGrid = board.grid;
Piece[] testGrid = new Piece[currentGrid.Length];
CastleInCheck = false; // Reset CastleInCheck to false initially <-----only line added.
for (int i = 0; i < pseudoLegalMoves.Length; i++)
{
Vector2 pseudoLegalMove = pseudoLegalMoves[i];
if (pseudoLegalMove == legalMovesEndMarker) { break; }
else
{
Array.Copy(currentGrid, testGrid, currentGrid.Length);
board.MoveGridPieceVec(piecePos, pseudoLegalMove, testGrid);
Piece PawnThatDidADoublePush = null;
if (movedPiece.type == "pawn" && (Mathf.Abs(movedPiece.x - (int)pseudoLegalMove.x) > 1))
{
PawnThatDidADoublePush = movedPiece;
}
Vector2 threatenedPos = movedPiece.type != "king" ? kingPos : pseudoLegalMove;
if (isKingInCheck(threatenedPos, testGrid, board, PawnThatDidADoublePush, movedPiece.white)) { pseudoLegalMoves[i] = legalMovesIgnoreMarker; }
}
}
}
return pseudoLegalMoves;
}
//(modified Move)
public int Move(Piece movedPiece, int x, int y, Board board)
{
int result = 0;
if (anarchy)
{
Piece targetPiece = board.GetPiece(x, y);
result = 1;
if (targetPiece != null && targetPiece != movedPiece) { targetPiece._Capture(); result = 2; }
movedPiece._SetPosition(x, y);
return result;
}
else
{
Vector2[] legalMoves = GetAllLegalMoves(movedPiece, board);
result = MoveLegalCheck(movedPiece, x, y, board, legalMoves);
// Call CastleNotMoved whenever a piece is moved <---------
if (result > 0)
{
CastleNotMoved(movedPiece);
}
return result;
}
}
//(modified MoveLegalCheck)
public int MoveLegalCheck(Piece movedPiece, int x, int y, Board board, Vector2[] legalMoves)
{
int result = 0;
Piece targetPiece = board.GetPiece(x, y);
Vector2 move = new Vector2(x, y);
bool legal = false;
foreach (Vector2 legalMove in legalMoves)
{
if (legalMove != legalMovesIgnoreMarker)
{
if (legalMove == legalMovesEndMarker) break;
if (move == legalMove) { legal = true; break; }
}
}
if (legal)
{
if (targetPiece != null) { targetPiece._Capture(); result = 2; } else { result = 1; }
if (movedPiece.type == "pawn" && movedPiece.x != x && board.GetPiece(x, y) == null) //EN PASSANT
{
board.PawnThatDidADoublePushLastRound._Capture();
result = 2;
}
if (movedPiece.type == "king")
{
if (movedPiece.white)
{
if (x - movedPiece.x == 2 && WhiteRightCastle && WhiteMoveRightCastle && WhitePiecesRightCastle && !CastleInCheck) // White right castle
{
Piece rookCastle = board.GetPiece(7, y);
rookCastle._SetPosition(x - 1, y);
}
else if (x - movedPiece.x == -2 && WhiteLeftCastle && WhiteMoveLeftCastle && WhitePiecesLeftCastle && !CastleInCheck) // White left castle
{
Piece rookCastle = board.GetPiece(0, y);
rookCastle._SetPosition(x + 1, y);
}
}
else
{
if (x - movedPiece.x == 2 && BlackRightCastle && BlackMoveRightCastle && BlackPiecesRightCastle && !CastleInCheck) // Black right castle
{
Piece rookCastle = board.GetPiece(7, y);
rookCastle._SetPosition(x - 1, y);
}
else if (x - movedPiece.x == -2 && BlackLeftCastle && BlackMoveLeftCastle && BlackPiecesLeftCastle && !CastleInCheck) // Black left castle
{
Piece rookCastle = board.GetPiece(0, y);
rookCastle._SetPosition(x + 1, y);
}
}
}
if (movedPiece.type == "pawn" && Mathf.Abs(y - movedPiece.y) == 2)
{
board.PawnThatDidADoublePushLastRound = movedPiece;
}
else
{
board.PawnThatDidADoublePushLastRound = null;
}
CastleNotMoved(movedPiece);
movedPiece.hasMoved = true;
movedPiece._SetPosition(x, y);
return result;
}
else
{
movedPiece._SetPosition(movedPiece.x, movedPiece.y);
return 0;
}
}
//(Board.cs Changes - Removed the castle move from board.cs)
public void MoveGridPiece(int ox, int oy, int tx, int ty, Piece[] grid)
{
Piece piece = GetGridPiece(ox, oy, grid);
// No en passant or castling logic
SetGridPiece(tx, ty, piece, grid);
SetGridPiece(ox, oy, null, grid);
}
/// <summary>
/// Simulate a piece's move on a grid, including capture, en passant and castling
/// </summary>
/// <param name="original">Starting position</param>
/// <param name="target">Target position</param>
/// <param name="grid"></param>
public void MoveGridPieceVec(Vector2 original, Vector2 target, Piece[] grid)
{
MoveGridPiece((int)original.x, (int)original.y, (int)target.x, (int)target.y, grid);
}
//(Chessmanger Changes)
//(Endturn)
board.currentRules.CheckCastlePaths(board.grid, board); // Check castle paths at end turn <-added
board.currentRules.CheckCastleSafety(board.grid, board); // Check castle safety at end turn<-added
_RefreshUI();
RequestSerialization();
//(startgame)
board.currentRules.CheckCastlePaths(board.grid, board); // Check castle paths at game start
board.currentRules.CheckCastleSafety(board.grid, board); // Check castle safety at game start
//(endgame)
board.currentRules.CastleMoveCheck();