https://m.youtube.com/watch?v=Bsy8pknHc0M
폰은 앞으로 이동할 수는 있지만 공격할 수는 없으므로,
폰 바로 앞은 체크 판정에서 제외해야 한다.
Piece p = gameManager.PieceAt(x, y - 1);
if (p == null && checkFrom == CheckFrom.MySide) moves.Add((x, y - 1));
if (FirstMove)
{
Piece p2 = gameManager.PieceAt(x, y - 2);
if (p == null && p2 == null && checkFrom == CheckFrom.MySide) moves.Add((x, y - 2));
}
적의 공격을 확인하는 거라면 경우의 수에서 제외하여 해결
킹을 제외한 다른 기물들에 CheckCheck()를 포함시키면 nullref 뜸.
CheckCheck()에서 적 기물들의 PossibleMove()를 호출하면 또 다시 CheckCheck()가 호출되어 무한 순환이 이루어지기 때문.
킹은 상대편 킹을 체크할 수 없기 때문에 그냥 빈 리스트를 return 했었는데,
상대편 기물들의 움직임은 확인해줘야 하므로 이번에는 경로들을 제대로 계산해야 한다.
if (checkFrom == CheckFrom.MySide) { CheckCheck(x, y); }
적의 경로를 계산할 때는 CheckCheck()를 호출하지 않게 하여 nullref는 막았는데,
여전히 체크가 되는 경우에는 이동하지 못하게 하지 못했다.
// 킹이라면 캐슬링 여부 검사
if (pieceScript is King)
{
// 캐슬링 검사및 배열 위치 변경
if (TryCastling(pieceScript as King, mx, my))
{
// 캐슬링 이후 룩의 오브젝트 위치 변경
if (mx == 3) pieces[4, my].transform.position = new Vector2(4, my);
else pieces[6, my].transform.position = new Vector2(6, my);
}
// 체크 검사 때 사용할 킹의 좌표 갱신
if (pieceScript.isWhite) whiteKingPosition = (mx, my);
else blackKingPosition = (mx, my);
}
킹의 좌표 갱신이 캐슬링을 했을 때만 이루어지고 있어 중괄호 밖으로 빼줌.
그랬더니 이상하게도 좌표 하나만 체크를 제대로 검사하고, 나머지는 정상적으로 판정이 되지 않음.
로직 정리
즉, 턴이 시작되면 자신의 모든 기물들의 모든 경로들에 대해 체크를 배제하기 위해 SimulateEnemyCheck()를 호출하므로
SimulateEnemyCheck()에 넣어놓은 print("king position : " + kingx + ", " + kingy);는 자신이 갖고 있는 기물의 수만큼 호출이 되야 하는데
1번만 호출이 되고 끝났다.
디버그 문구를 삽입하여 이유를 확인해보니, 그냥 아직 다른 기물들에 CheckCheck()을 넣어주지 않아서 그랬던 거였다.
public void CheckCheck(int x, int y)
{
foreach ((int, int) move in moves)
{
if (gameManager.SimulateEnemyCheck(x, y, move.Item1, move.Item2))
{
moves.Remove(move);
break;
}
}
}
CheckCheck()를 살펴보니 continue가 있어야 할 자리에 break;가 들어있어 교체해주었다.
그랬더니 InvalidOperationException이 떴다. 순회를 돌던 도중 리스트의 원소를 제거하는 연산은 불법이었다.
moves.RemoveAll(move => gameManager.SimulateEnemyCheck(x, y, move.Item1, move.Item2));
for문으로 리스트를 역순 순회하는 방법도 있지만, 간단하게 람다식으로 변경해주었다.

내 생각보다 중복되는 계산을 너무 많이 하고 있었다.
public override List<(int, int)> PossibleMove(CheckFrom checkFrom)
{
// 내 기물을 조회하고 있는거고, 캐싱된 값이 있다면 그 값을 반환한다
if (checkFrom == CheckFrom.MySide && cached) { return moves; }
// 남의 기물을 조회하고 있는 거라면 킹에 의한 변수를 제거하기 위해 매번 재계산한다
if (checkFrom == CheckFrom.OtherSide) { moves.Clear(); }
캐싱을 사용하지 않을 땐 매번 moves를 초기화하여 해결했다.
킹이 체크가 아님에도 체크라고 판정되는 버그도 자연스럽게 해결됐다.
