public static void Save(Maze maze) { using (FileStream fs = new FileStream("maze.mzl", FileMode.Create)) { StreamWriter sw = new StreamWriter(fs, Encoding.UTF8); sw.WriteLine(maze.GetSize().r + " " + maze.GetSize().c); foreach (List <bool> i in maze.HolWalls) { foreach (bool j in i) { sw.Write((j ? 1 : 0) + " "); } sw.WriteLine(); } foreach (List <bool> i in maze.VerWalls) { foreach (bool j in i) { sw.Write((j ? 1 : 0) + " "); } sw.WriteLine(); } sw.Flush(); } }
// 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(); } }
public static bool MovePlayer(Maze maze, Key dir) { maze.Cells[playerPos.r][playerPos.c] = 0; switch (dir) { case Key.W: if (playerPos.r > 0 && maze.HolWalls[playerPos.r - 1][playerPos.c] == false) { playerPos.r--; } break; case Key.S: if (playerPos.r < maze.GetSize().r - 1 && maze.HolWalls[playerPos.r][playerPos.c] == false) { playerPos.r++; } break; case Key.A: if (playerPos.c > 0 && maze.VerWalls[playerPos.r][playerPos.c - 1] == false) { playerPos.c--; } break; case Key.D: if (playerPos.c < maze.GetSize().c - 1 && maze.VerWalls[playerPos.r][playerPos.c] == false) { playerPos.c++; } break; default: maze.Cells[playerPos.r][playerPos.c] = 4; return(false); } maze.Cells[playerPos.r][playerPos.c] = 4; return(true); }
// 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(); } }
public static void BFS(Maze maze, Action action) { #region INITIALIZE ArrayPoint2D size = maze.GetSize(); Queue <PathNode> que = new Queue <PathNode>(); List <List <bool> > hasVisited = new List <List <bool> >(); ArrayPoint2D[] dirs = { new ArrayPoint2D(-1, 0), new ArrayPoint2D(1, 0), new ArrayPoint2D(0, -1), new ArrayPoint2D(0, 1) }; PathNode answer = new PathNode(); 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 que.Enqueue(new PathNode(maze.StartPoint)); hasVisited[maze.StartPoint.r][maze.StartPoint.c] = true; while (que.Count != 0) { PathNode target = que.Dequeue(); maze.Cells[target.point.r][target.point.c] = 1; if (target.point == maze.EndPoint) { answer = target; break; } foreach (var item in dirs) { ArrayPoint2D enqueuePos = target.point + item; if (!enqueuePos.IsValidPosition(size)) { continue; } if (maze.HasWallBetween(target.point, enqueuePos)) { continue; } if (hasVisited[enqueuePos.r][enqueuePos.c]) { continue; } que.Enqueue(new PathNode(enqueuePos, target)); hasVisited[enqueuePos.r][enqueuePos.c] = true; } action(); Thread.Sleep(MainWindow.delayTime); } foreach (var item in answer.path) { maze.Cells[item.r][item.c] = 2; action(); Thread.Sleep(MainWindow.delayTime); } }
public void Prepare() { // CLEAR ALL ENTITIES IN GRID // MazeGrid.Children.Clear(); MazeGrid.RowDefinitions.Clear(); MazeGrid.ColumnDefinitions.Clear(); // MAKE DEFINITIONS // MazeGrid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Star) }); MazeGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) }); for (int i = 0; i < mainMaze.GetSize().r; i++) { MazeGrid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(2, GridUnitType.Star) }); MazeGrid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Star) }); } for (int i = 0; i < mainMaze.GetSize().c; i++) { MazeGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(2, GridUnitType.Star) }); MazeGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) }); } // DRAW DOTS // for (int i = 1; i < mainMaze.GetSize().r; i++) { for (int j = 1; j < mainMaze.GetSize().c; j++) { Rectangle rectangle = new Rectangle { Fill = Brushes.Black, StrokeThickness = 0 }; MazeGrid.Children.Add(rectangle); Grid.SetRow(rectangle, i * 2); Grid.SetColumn(rectangle, j * 2); } } // DRAW 4 BIG WALLS // Rectangle leftWall = new Rectangle { Fill = Brushes.Black, StrokeThickness = 0 }; Rectangle rightWall = new Rectangle { Fill = Brushes.Black, StrokeThickness = 0 }; Rectangle upWall = new Rectangle { Fill = Brushes.Black, StrokeThickness = 0 }; Rectangle downWall = new Rectangle { Fill = Brushes.Black, StrokeThickness = 0 }; MazeGrid.Children.Add(leftWall); Grid.SetRow(leftWall, 0); Grid.SetColumn(leftWall, 0); Grid.SetRowSpan(leftWall, mainMaze.GetSize().r * 2 + 1); MazeGrid.Children.Add(rightWall); Grid.SetRow(rightWall, 0); Grid.SetColumn(rightWall, mainMaze.GetSize().c * 2); Grid.SetRowSpan(rightWall, mainMaze.GetSize().r * 2 + 1); MazeGrid.Children.Add(upWall); Grid.SetRow(upWall, 0); Grid.SetColumn(upWall, 0); Grid.SetColumnSpan(upWall, mainMaze.GetSize().c * 2 + 1); MazeGrid.Children.Add(downWall); Grid.SetRow(downWall, mainMaze.GetSize().r * 2); Grid.SetColumn(downWall, 0); Grid.SetColumnSpan(downWall, mainMaze.GetSize().c * 2 + 1); // DRAW HORIZONTAL WALLS // HolWallsRects = new List <List <Rectangle> >(); for (int i = 0; i < mainMaze.GetSize().r - 1; i++) { HolWallsRects.Add(new List <Rectangle>()); for (int j = 0; j < mainMaze.GetSize().c; j++) { Rectangle rectangle = new Rectangle { Fill = Brushes.Black, StrokeThickness = 0 }; HolWallsRects[i].Add(rectangle); MazeGrid.Children.Add(rectangle); Grid.SetRow(rectangle, i * 2 + 2); Grid.SetColumn(rectangle, j * 2 + 1); } } // DRAW VERTICAL WALLS // VerWallsRects = new List <List <Rectangle> >(); for (int i = 0; i < mainMaze.GetSize().r; i++) { VerWallsRects.Add(new List <Rectangle>()); for (int j = 0; j < mainMaze.GetSize().c - 1; j++) { Rectangle rectangle = new Rectangle { Fill = Brushes.Black, StrokeThickness = 0 }; VerWallsRects[i].Add(rectangle); MazeGrid.Children.Add(rectangle); Grid.SetRow(rectangle, i * 2 + 1); Grid.SetColumn(rectangle, j * 2 + 2); } } CellRects = new List <List <Rectangle> >(); for (int i = 0; i < mainMaze.GetSize().r; i++) { CellRects.Add(new List <Rectangle>()); for (int j = 0; j < mainMaze.GetSize().c; j++) { Rectangle rectangle = new Rectangle { Fill = Brushes.White, StrokeThickness = 0 }; CellRects[i].Add(rectangle); MazeGrid.Children.Add(rectangle); Grid.SetRow(rectangle, i * 2 + 1); Grid.SetColumn(rectangle, j * 2 + 1); } } return; }