/// <summary> /// 노드로부터 루트 까지의 경로를 콘솔 화면에 출력합니다. /// </summary> /// <param name="node"></param> /// <returns></returns> static public int PrintPath(EPNode node) { if (node == null) { return(-1); } int num = PrintPath(node.Parent) + 1; Console.WriteLine("Depth " + num); node.Print(); return(num); }
/// <summary> /// A* 알고리즘을 사용한 8 퍼즐 문제 풀이를 시작합니다. /// </summary> /// <returns></returns> public EPNode Solve() { if (!_solvability) { return(null); } Console.WriteLine("Start searching."); int count = 0; EPNode rootNode = new EPNode(_initial, _blank[0], _blank[1], 0, null).Estimate(_goal); EPNode goalNode = new EPNode(_goal, 0, 0, 0, null); // for checking _OPEN.Enqueue(rootNode, rootNode.Distance + rootNode.Heuristic); while (_OPEN.Count > 0 && count < _LIMIT) { count++; // 예상 비용이 가장 낮은 노드 선택 EPNode bestNode = _OPEN.Dequeue(); // Console창 출력 if (DEBUG) { Console.WriteLine("Node #" + count); bestNode.Print(); } else { Console.Write("Search count : " + count + " "); for (int i = 0; i < (count / 200) % 10; i++) { Console.Write("."); } } // CLOSED 큐에 추가 _CLOSED.Add(bestNode); // 목표 도달 if (bestNode.Equals(goalNode)) // Reached the goal! { if (!DEBUG) { Console.WriteLine("..."); } return(bestNode); } // 자식 노드 생성 (상, 하, 좌, 우 이동) EPNode[] movedNode = new EPNode[4]; movedNode[0] = bestNode.MoveUp(); movedNode[1] = bestNode.MoveDown(); movedNode[2] = bestNode.MoveLeft(); movedNode[3] = bestNode.MoveRight(); // 각 자식 노드들에 대해 다음 연산을 수행 for (int i = 0; i < 4; i++) { // 해당 방향으로는 이동이 불가능한 경우. 해당 노드 무시. if (movedNode[i] == null) { continue; // Hit the wall! } // OPEN, CLOSED 큐에서 해당 노드가 존재하는지 검색 EPNode nodeInOpen = Find(_OPEN, movedNode[i]); EPNode nodeInClosed = Find(_CLOSED, movedNode[i]); if (nodeInOpen == null && nodeInClosed == null) // OPEN, CLOSED 모두에 해당 노드가 존재하지 않는 경우 { // 자식 노드의 추정값 계산 movedNode[i].Estimate(_goal); _OPEN.Enqueue(movedNode[i], movedNode[i].Distance + movedNode[i].Heuristic); } else if (nodeInOpen != null) // OPEN 큐에 해당 노드가 존재할 경우 { // 만약 기존 노드보다 새로 생성한 자식 노드가 더 효율적일 때, if (nodeInOpen.Distance > movedNode[i].Distance) // ( == Distance가 더 작을 때) { // 큐에 넣기 전 자식 노드의 추정값 계산(추정값은 큐에 이미 존재하는 노드와 같음) movedNode[i].Estimate(_goal); nodeInOpen = movedNode[i]; // 새로 생성한 자식 노드로 기존 노드를 대체 } else // 그렇지 않으면, { continue; // 그냥 무시하고 진행 } } else if (nodeInClosed != null) // OPEN 큐에는 없지만 CLOSED 큐에 해당 노드가 존재할 경우 { // 더 좋은 path가 나올 가능성이 없으므로 패스 continue; } } if (!DEBUG) { Console.Write("\r" + new string(' ', Console.WindowWidth - 1) + "\r"); } } if (!DEBUG) { Console.WriteLine("..."); } return(null); }