private void CheckCastling(List<(int, int)> moves, int x, int y)
{
// 한 번도 움직이지 않은 것이니, 왼쪽으로 4칸에 룩이 있거나 오른쪽으로 3칸에 룩이 있는지 바로 확인
// 그리고 룩이 한 번도 움직이지 않았는지 확인
// 그리고 룩과 킹 사이에 기물이 있는지 확인하고, 체크가 되는지 확인
// 모든 조건을 통과하면 캐슬링 가능
if (moveValidator.SimulateEnemyCheck(x, y, x, y)) return;
Rook leftRook = board.GetPieceScriptAt(x - 4, y) as Rook;
if (leftRook != null && leftRook.FirstMove)
{
bool canLeftCastling = true;
if (board.GetPieceAt(x - 3, y) != null)
{
canLeftCastling = false;
}
else
{
for (int i = 3; i <= 4; i++)
{
if (board.GetPieceAt(i, y) != null || moveValidator.SimulateEnemyCheck(x, y, i, y))
{
canLeftCastling = false;
break;
}
}
}
if (canLeftCastling) moves.Add((x - 2, y));
}
킹이 위치한 칸과 이동할 칸이 공격 받지 않는 상태여야 한다. 원래 위치, 캐슬링 방향으로 한 칸 옆 위치(거쳐가야 할 칸), 두 칸 옆 위치(목적지) 세 위치 중 하나라도 공격받는 중이라서 이동하는 킹이 체크 상태가 되는 경우 캐슬링을 할 수 없다.
else 추가하여 룩 바로 옆은 비어있는지만 확인하게 수정

저번부터 문제가 됐던 퀸 증발 버그

(판 위에는 멀쩡히 퀸이 살아있지만, FEN 기보 상으론 이미 퀸이 없다)
테스트를 거듭하고 코드를 계속 살펴본 결과, 캐슬링 로직에서 문제가 발생함을 알아냄.
for (int i = 3; i <= 4; i++)
{
if (board.GetPieceAt(i, y) != null || moveValidator.SimulateEnemyCheck(x, y, i, y))
{
canLeftCastling = false;
break;
}
}
캐슬링 할 수 있는지 판단할 때 공격 당하는 칸인지 확인하기 위해
SimulateEnemyCheck()를 통해 킹이 캐슬링 위치로 가보는 로직이 있음.
이때 캐슬링 위치로 잠깐 가보는 것임에도 불구하고
SimulateEnemyCheck()에서 위치가 캐슬링 위치이니 캐슬링을 하는 것으로 판단하고 기물들을 캐슬링대로 옮겨버림.
이때 진짜 캐슬링이 아니라 공격 당하는지만 체크하러 온 거였다면 캐슬링을 해버리는 과정에서 중간에 있던 퀸이 유실되는 결과가 발생함.
킹사이드에선 캐슬링 위치(나이트가 있는 곳)까지 SimulateEnemyCheck()를 한다는 건
이미 캐슬링을 할 수 있는 조건이 갖춰져 있다는 것이기에 오류가 발생하지 않았지만,
퀸사이드에선 퀸을 고려하지 않고도 앞에서 SimulateEnemyCheck()를 호출하여 문제가 발생했던 것.
public bool TryCastling(King king, int mx, int my)
{
if (!king.FirstMove) return false; // 첫 이동이 아니라면 캐슬링 불가능
// 처음 움직인 것인데 특정한 x축 좌표로 이동했다면 캐슬링
// 캐슬링을 검증할 때 TryCastling이 호출될 때도 있으므로, 혹시 기물이 이미 있지는 않은지 확인한다
// 킹은 이후 로직에서 이동할 예정이므로, 룩의 좌표만 이동시켜준다 (룩 오브젝트의 위치는 MoveTo로 돌아가서 바꿈)
if (mx == 3)
{
if (board.GetPieceAt(4, my) != null) return false; // 퀸이 있다면 캐슬링 시뮬 불가
board.SetPieceAt(board.GetPieceAt(1, my), 4, my);
board.SetPieceAt(null, 1, my);
return true;
}
if (mx == 7)
{
board.SetPieceAt(board.GetPieceAt(8, my), 6, my);
board.SetPieceAt(null, 8, my);
return true;
}
return false;
}
SimulateEnemyCheck()에서 사용되는 TryCastling()에
if (board.GetPieceAt(4, my) != null) return false를 추가하여 해결

보이는 것보다 콜라이더가 커서 원하는대로 선택이 되지 않는 문제 수정
배운 것 : 콜라이더는 한 오브젝트에 여러 개 붙일 수 있다