(25/07/04)과거의 내가 작성한 A*알고리즘(자아비판)

허윤·2025년 7월 4일
public LinkedList<Node> PathFinding(Vector2Int startPos, Vector2Int endPos)
{
    // 닫힌 노드 목록: 이미 경로에 포함된 노드들
    LinkedList<Node> closedNodes = new LinkedList<Node>();

    // 목적지가 맵 안에 없거나, 출발지와 동일하면 빈 경로 반환
    if (!grids.ContainsKey(endPos))
    {
        closedNodes.Clear();
        return closedNodes;
    }

    if (startPos == endPos) 
    {
        closedNodes.Clear();
        return closedNodes;
    } 

    // 열린 노드 목록: 탐색 후보들
    LinkedList<Node> openNodes = new LinkedList<Node>();
    bool isSearchDone = false;

    // 시작 노드를 닫힌 목록에 추가하고 GH값 설정
    closedNodes.AddLast(grids[startPos]);
    grids[startPos].SetGH(startPos, endPos);

    short whileCounterMax = 1000; // 무한루프 방지용 안전장치

    // 메인 탐색 루프
    while (!isSearchDone)
    {
        // 현재 닫힌 노드의 주변을 검사해서 이동 가능한 노드를 openNodes에 추가
        GetNearOpenNodes(ref openNodes, closedNodes.Last().nodeCenterPosition, closedNodes);

        Vector2Int lowerstHNodePos = Vector2Int.zero; // 가장 낮은 H값을 가진 후보 노드
        int lowerstHValue = int.MaxValue;

        // 열린 노드 중에서 가장 좋은 후보를 고름
        while (openNodes.Count > 0)
        {
            Node node = openNodes.First();
            node.SetGH(startPos, endPos); // GH값 업데이트
            openNodes.RemoveFirst();

            // 이동 가능하고, 해당 위치에 캐릭터가 없거나 목적지인 경우에만 후보로 고려
            if (lowerstHValue > node.H && node.isMoveableTile &&
                (node.CharacterOnNode == null || endPos == node.nodeCenterPosition))
            {
                lowerstHValue = node.H;
                lowerstHNodePos = node.nodeCenterPosition;
            }

            // 목적지에 도달하면 탐색 종료
            if (endPos == node.nodeCenterPosition)
            {
                isSearchDone = true;
                openNodes.Clear();
            }
        }

        openNodes.Clear();

        // 후보가 유효하지 않으면 루프 탈출
        if (!grids.ContainsKey(lowerstHNodePos))
            break;

        // 연결 경로 설정 (현재 노드에 이전 노드 연결)
        grids[lowerstHNodePos].connectedNode = closedNodes.Last();

        // 최종 후보를 닫힌 노드 목록에 추가
        closedNodes.AddLast(grids[lowerstHNodePos]);

        // 무한 루프 방지 카운터
        --whileCounterMax;
        if (whileCounterMax <= 0) isSearchDone = true;
    }

    // 도착지까지 도달하지 못했거나, 경로가 잘못된 경우
    if (closedNodes.Last() != grids[endPos] || closedNodes.First() != grids[startPos])
    {
        return new LinkedList<Node>();
    }

    // 경로 이중 확인: 연결된 노드들을 따라 시작점까지 역추적
    isSearchDone = false;
    whileCounterMax = 1000;
    LinkedList<Node> doubleCheckedNodes = new LinkedList<Node>();
    doubleCheckedNodes.AddFirst(closedNodes.Last());

    while (!isSearchDone)
    {
        // 이전 노드로 따라가며 경로 재구성
        GetNearClosedNodes(ref doubleCheckedNodes, doubleCheckedNodes.First().nodeCenterPosition, closedNodes);

        if (doubleCheckedNodes.First() == grids[startPos] || whileCounterMax <= 0)
        {
            isSearchDone = true;
        }

        whileCounterMax--;
    }

    // 다시 추적한 경로가 유효한지 최종 확인
    if (doubleCheckedNodes.Last() != grids[endPos] || doubleCheckedNodes.First() != grids[startPos])
    {
        return new LinkedList<Node>();
    }

    // 최종 경로 반환 (시작점 → 도착점 방향)
    return doubleCheckedNodes;
}

비판점

  1. 일단 너무 길다. 재 작업을 하려해도 할 수 없는 구조
  2. 노드 역추적시 While을 통째로 한 함수에 박아놓은 나 자신을 용서 할 수 없는 구조
  3. 클린코드 작성이 필요할 것 같다(대표적으로 변수명). 내일 TIL의 목표로 작성요망
  4. 재귀호출을 통해 코드를 좀 더 간결하게 작업하는 연습이 필요
  5. 일단 이렇게 적진 말아야겠다는 교훈

그나마 잘한거

  1. 맥스루프를 정해두어 적어도 터지는걸 막았다.
    • 애초에 잘 짯으면 터질 걱정을 안했을 일
  2. 기능에 문제는 없었다
profile
C# 클라이언트 프로그래밍 지망

0개의 댓글