Example #1
0
        public Maze(ArrayPoint2D size, ArrayPoint2D start, ArrayPoint2D end)
        {
            Cells = new List <List <int> >(size.r);
            for (int i = 0; i < size.r; i++)
            {
                Cells.Add(new List <int>(size.c));
                for (int j = 0; j < size.c; j++)
                {
                    Cells[i].Add(0);
                }
            }

            HolWalls = new List <List <bool> >(size.r - 1);
            for (int i = 0; i < size.r - 1; i++)
            {
                HolWalls.Add(new List <bool>(size.c));
                for (int j = 0; j < size.c; j++)
                {
                    HolWalls[i].Add(true);
                }
            }

            VerWalls = new List <List <bool> >(size.r);
            for (int i = 0; i < size.r; i++)
            {
                VerWalls.Add(new List <bool>(size.c - 1));
                for (int j = 0; j < size.c - 1; j++)
                {
                    VerWalls[i].Add(true);
                }
            }
        }
Example #2
0
 public PathNode(ArrayPoint2D point, PathNode history)
 {
     this.point = point;
     path       = new List <ArrayPoint2D>(history.path)
     {
         this.point
     };
 }
Example #3
0
 public PathNode(ArrayPoint2D point)
 {
     this.point = point;
     path       = new List <ArrayPoint2D>
     {
         this.point
     };
 }
Example #4
0
        // 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();
            }
        }
Example #5
0
 public bool HasWallBetween(ArrayPoint2D pos0, ArrayPoint2D pos1)
 {
     if (pos0.r == pos1.r)
     {
         return(VerWalls[pos0.r][pos0.c > pos1.c ? pos1.c : pos0.c]);
     }
     else if (pos0.c == pos1.c)
     {
         return(HolWalls[pos0.r > pos1.r ? pos1.r : pos0.r][pos0.c]);
     }
     else
     {
         return(false);
     }
 }
Example #6
0
 public bool RemoveWallBetween(ArrayPoint2D pos0, ArrayPoint2D pos1, Action action)
 {
     if (pos0.r == pos1.r)
     {
         VerWalls[pos0.r][pos0.c > pos1.c ? pos1.c : pos0.c] = false;
     }
     else if (pos0.c == pos1.c)
     {
         HolWalls[pos0.r > pos1.r ? pos1.r : pos0.r][pos0.c] = false;
     }
     else
     {
         return(false);
     }
     action();
     Thread.Sleep(MainWindow.delayTime);
     return(true);
 }
Example #7
0
        public static bool Open(ref Maze maze)
        {
            StreamReader sr;

            try
            {
                sr = new StreamReader("maze.mzl");
            }
            catch (FileNotFoundException)
            {
                MessageBoxResult result = MessageBox.Show("maze.mzl 파일이 존재하지 않습니다.", "Wait...");
                return(false);
            }

            string line;

            line = sr.ReadLine().Trim();
            string[] sizeString = line.Split(' ');

            ArrayPoint2D size = new ArrayPoint2D(int.Parse(sizeString[0]), int.Parse(sizeString[1]));

            maze = new Maze(size, new ArrayPoint2D(0, 0), new ArrayPoint2D(0, 0));

            for (int i = 0; i < size.r - 1; i++)
            {
                int[] read = Array.ConvertAll(sr.ReadLine().Trim().Split(' '), int.Parse);
                for (int j = 0; j < size.c; j++)
                {
                    maze.HolWalls[i][j] = read[j] == 1 ? true : false;
                }
            }

            for (int i = 0; i < size.r; i++)
            {
                int[] read = Array.ConvertAll(sr.ReadLine().Trim().Split(' '), int.Parse);
                for (int j = 0; j < size.c - 1; j++)
                {
                    maze.VerWalls[i][j] = read[j] == 1 ? true : false;
                }
            }
            return(true);
        }
Example #8
0
        // position을 기준으로 이웃한 셀 위치를 List에 저장합니다.
        // List<> list: 저장할 List
        // ArrayPoint2D position: 기준 위치
        // ArrayPoint2D mazeSize: 미로 크기
        static void AddNeighbor(List <ArrayPoint2D> list, ArrayPoint2D position, ArrayPoint2D mazeSize)
        {
            if (position.r != 0)
            {
                list.Add(new ArrayPoint2D(position.r - 1, position.c));
            }

            if (position.c != 0)
            {
                list.Add(new ArrayPoint2D(position.r, position.c - 1));
            }

            if (position.r != mazeSize.r - 1)
            {
                list.Add(new ArrayPoint2D(position.r + 1, position.c));
            }

            if (position.c != mazeSize.c - 1)
            {
                list.Add(new ArrayPoint2D(position.r, position.c + 1));
            }
        }
Example #9
0
 public WallWithDirection(bool isVerWall, ArrayPoint2D wall)
 {
     IsVerWall = isVerWall;
     Wall      = wall;
 }
Example #10
0
        // 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();
            }
        }
Example #11
0
        // 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();
            }
        }
Example #12
0
 public bool IsValidPosition(ArrayPoint2D size)
 {
     return(r > -1 && c > -1 && r < size.r && c < size.c);
 }
Example #13
0
        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);
            }
        }
Example #14
0
        private void MenuGenerateButton(object sender, RoutedEventArgs e)
        {
            int inputRow = 0, inputCol = 0;

            #region EXCEPTION
            try
            {
                delayTime = int.Parse(DelayTimeTextBox.Text);
                if (delayTime < 0)
                {
                    throw new InvaildDelayTimeException("지연 시간은 0 이상이여야 합니다.");
                }
            }
            catch (FormatException)
            {
                MessageBoxResult result = MessageBox.Show("지연 시간 입력란에는 숫자만 입력할 수 있습니다.", "Wait...");
                return;
            }
            catch (InvaildDelayTimeException)
            {
                MessageBoxResult result = MessageBox.Show("지연 시간은 0 이상이여야 합니다.", "Wait...");
                return;
            }

            try
            {
                inputRow = int.Parse(RowInputTextBox.Text);
                inputCol = int.Parse(ColInputTextBox.Text);
                if (inputRow < 1 || inputCol < 1)
                {
                    throw new InvaildMazeSizeException("미로의 행과 열의 크기는 2 이상이여야 합니다.");
                }
            }
            catch (FormatException)
            {
                MessageBoxResult result = MessageBox.Show("미로의 크기 입력란에는 숫자만 입력할 수 있습니다.", "Wait...");
                return;
            }
            catch (InvaildMazeSizeException)
            {
                MessageBoxResult result = MessageBox.Show("미로의 행과 열의 크기는 2 이상이여야 합니다.", "Wait...");
                return;
            }
            #endregion

            ArrayPoint2D size = new ArrayPoint2D(inputRow, inputCol);
            mainMaze = new Maze(size, new ArrayPoint2D(0, 0), new ArrayPoint2D(9, 10));
            Prepare();

            switch (GenerateAlgComboBox.SelectedIndex)
            {
            case 0:
                MazeGenerator.RecursiveBacktracker(mainMaze, ShowMaze);
                mainMaze.isMaze = true;
                break;

            case 1:
                MazeGenerator.Kruskal(mainMaze, ShowMaze);
                mainMaze.isMaze = true;
                break;

            case 2:
                MazeGenerator.HuntAndKill(mainMaze, ShowMaze);
                mainMaze.isMaze = true;
                break;

            default:
                mainMaze.isMaze = false;
                break;
            }


            ShowMaze();
        }