// Recursive Backtracker 방식의 미로 생성 // maze: 완전 미로를 생성할 변수 // action: 벽을 제거할 때마다 실행되기를 원하는 함수 public static void RecursiveBacktracker(Maze maze, Action action) { #region INITIALIZE ArrayPoint2D size = maze.GetSize(); List <List <bool> > hasVisited = new List <List <bool> >(); for (int i = 0; i < size.r; i++) { hasVisited.Add(new List <bool>(size.c)); for (int j = 0; j < size.c; j++) { hasVisited[i].Add(false); } } #endregion using (FileStream fs = new FileStream("test.log", FileMode.Create)) { StreamWriter sw = new StreamWriter(fs, Encoding.UTF8); #region ALGORITHM // CODE STARTS HERE // ArrayPoint2D current = maze.StartPoint; hasVisited[current.r][current.c] = true; sw.WriteLine("Recursive Backtracker 생성입니다. 현재 위치는 " + current + " 입니다."); // LOG Stack <ArrayPoint2D> PointStack = new Stack <ArrayPoint2D>(); while (!HasVisitedAll(hasVisited)) { List <ArrayPoint2D> avail = new List <ArrayPoint2D>(); AddNeighbor(avail, current, size); avail.RemoveAll(_ => hasVisited[_.r][_.c]); if (avail.Count() != 0) { ArrayPoint2D target = avail[random.Next(avail.Count())]; PointStack.Push(current); sw.WriteLine("스택에 " + current + " 가 푸시되었습니다."); // LOG maze.RemoveWallBetween(current, target, action); sw.WriteLine(current + " 와 " + target + " 사이 벽이 제거되었습니다."); // LOG action(); // GRAPHIC hasVisited[target.r][target.c] = true; current = target; sw.WriteLine("현재 위치는 이제 " + current + " 입니다."); // LOG } else { current = PointStack.Pop(); sw.WriteLine("현재 위치를 스택에서 팝된 데이터로 설정합니다. " + current + " 가 팝되었습니다."); // LOG } } #endregion sw.Flush(); } }
// HuntAndKill 방식의 미로 생성 // maze: 완전 미로를 생성할 변수 // action: 벽을 제거할 때마다 실행되기를 원하는 함수 public static void HuntAndKill(Maze maze, Action action) { #region INITIALIZE ArrayPoint2D size = maze.GetSize(); List <List <bool> > hasVisited = new List <List <bool> >(); for (int i = 0; i < size.r; i++) { hasVisited.Add(new List <bool>(size.c)); for (int j = 0; j < size.c; j++) { hasVisited[i].Add(false); } } #endregion using (FileStream fs = new FileStream("test.log", FileMode.Create)) { StreamWriter sw = new StreamWriter(fs, Encoding.UTF8); #region ALGORITHM // CODE STARTS HERE // ArrayPoint2D current = new ArrayPoint2D(random.Next(size.r), random.Next(size.c)); hasVisited[current.r][current.c] = true; sw.WriteLine("Hunt-And-Kill 생성입니다. 현재 위치는 " + current + " 입니다."); // LOG while (!HasVisitedAll(hasVisited)) { List <ArrayPoint2D> avail = new List <ArrayPoint2D>(); AddNeighbor(avail, current, size); avail.RemoveAll(_ => hasVisited[_.r][_.c]); while (avail.Count() != 0) { ArrayPoint2D target = avail[random.Next(avail.Count())]; maze.RemoveWallBetween(current, target, action); sw.WriteLine("미로를 생성 중입니다. " + current + " 와 " + target + " 사이 벽이 제거되었습니다."); hasVisited[target.r][target.c] = true; current = target; avail.Clear(); AddNeighbor(avail, current, size); avail.RemoveAll(_ => hasVisited[_.r][_.c]); } bool restart = false; // 이중 반복문 탈출을 위해 ArrayPoint2D loop; for (int i = 0; i < size.r; i++) { for (int j = 0; j < size.c; j++) { loop = new ArrayPoint2D(i, j); if (!hasVisited[loop.r][loop.c]) { List <ArrayPoint2D> related = new List <ArrayPoint2D>(); AddNeighbor(related, loop, size); related.RemoveAll(_ => !hasVisited[_.r][_.c]); if (related.Count == 0) { continue; } ArrayPoint2D target = related[random.Next(related.Count())]; maze.RemoveWallBetween(loop, target, action); sw.WriteLine("새로운 지역을 탐색합니다. " + loop + ", " + target + " 사이 벽이 제거되었습니다."); hasVisited[loop.r][loop.c] = true; current = loop; restart = true; sw.WriteLine("새로운 현재 위치는 " + current + " 입니다."); // LOG break; } } if (restart) { break; } } } // CODE ENDS HERE // #endregion sw.Flush(); } }
// Kruskal 방식의 미로 생성 // maze: 완전 미로를 생성할 변수 // action: 벽을 제거할 때마다 실행되기를 원하는 함수 public static void Kruskal(Maze maze, Action action) { #region INITIALIZE ArrayPoint2D size = maze.GetSize(); DisjointSet <ArrayPoint2D> disjointSet = new DisjointSet <ArrayPoint2D>(); List <WallWithDirection> WallList = new List <WallWithDirection>(); List <List <int> > CellIndex = new List <List <int> >(); int removedCount = 0; int removedCountTarget = (size.r * size.c) - 1; for (int i = 0; i < size.r - 1; i++) { for (int j = 0; j < size.c; j++) { WallList.Add(new WallWithDirection(false, new ArrayPoint2D(i, j))); } } for (int i = 0; i < size.r; i++) { for (int j = 0; j < size.c - 1; j++) { WallList.Add(new WallWithDirection(true, new ArrayPoint2D(i, j))); } } for (int i = 0; i < size.r; i++) { CellIndex.Add(new List <int>()); for (int j = 0; j < size.c; j++) { CellIndex[i].Add(-1); } } #endregion using (FileStream fs = new FileStream("test.log", FileMode.Create)) { StreamWriter sw = new StreamWriter(fs, Encoding.UTF8); #region ALGORITHM // CODE STARTS HERE // //WallList.Count != 0 || while (removedCount != removedCountTarget) { sw.WriteLine("Recursive Backtracker 생성입니다."); // LOG int rand = random.Next(WallList.Count); WallWithDirection target = WallList[rand]; ArrayPoint2D ULPos = target.Wall; ArrayPoint2D DRPos = target.Wall + (target.IsVerWall ? new ArrayPoint2D(0, 1) : new ArrayPoint2D(1, 0)); sw.WriteLine("현재 대상 벽은 " + ULPos + " 와 " + DRPos + " 사이의 벽입니다."); // LOG ArrayPoint2D[] targetCells = { ULPos, DRPos }; foreach (var item in targetCells) { if (CellIndex[item.r][item.c] == -1) { CellIndex[item.r][item.c] = disjointSet.GetTreeCount(); disjointSet.MakeSet(item); sw.WriteLine("Disjoint Set에 " + item + "을 추가합니다."); // LOG } } if (disjointSet.Find(CellIndex[ULPos.r][ULPos.c]) != disjointSet.Find(CellIndex[DRPos.r][DRPos.c])) { disjointSet.Union(CellIndex[ULPos.r][ULPos.c], CellIndex[DRPos.r][DRPos.c]); maze.RemoveWallBetween(ULPos, DRPos, action); sw.WriteLine(ULPos + " 와 " + DRPos + " 사이 벽이 제거되었습니다."); // LOG removedCount++; } WallList.RemoveAt(rand); } // CODE ENDS HERE // #endregion sw.Flush(); } }