private void GoGenerate(InnerMap map, Maze maze, Random r, Action<int, int, long, long> pixelChangedCallback) { long totSteps = (((long)maze.Width - 1L) / 2L) * (((long)maze.Height - 1L) / 2L); long currentStep = 1; int width = maze.Width; int height = maze.Height; int x = 1; int y = 1; //Stack<MazePoint> stackje = new Stack<MazePoint>(); //stackje.Push(new MazePoint(x, y)); map[x, y] = true; pixelChangedCallback.Invoke(x, y, currentStep, totSteps); MazePoint[] targets = new MazePoint[4]; QuatroStack quatro = new QuatroStack(); //0 == top, 1 == right, 2 == bot, 3 == left Boolean backtracking = false; int prex = 0; int prey = 0; while (true) { //Console.WriteLine(quatro.Count + ", X: " + x + " Y: " + y); int targetCount = 0; if (x - 2 > 0 && !map[x - 2, y]) { targets[targetCount].X = x - 2; targets[targetCount].Y = y; targetCount++; } if (x + 2 < width - 1 && !map[x + 2, y]) { targets[targetCount].X = x + 2; targets[targetCount].Y = y; targetCount++; } if (y - 2 > 0 && !map[x, y - 2]) { targets[targetCount].X = x; targets[targetCount].Y = y - 2; targetCount++; } if (y + 2 < height - 1 && !map[x, y + 2]) { targets[targetCount].X = x; targets[targetCount].Y = y + 2; targetCount++; } //Thread.Sleep(1000); if (targetCount > 0) { var target = targets[r.Next(targetCount)]; if (backtracking) { backtracking = false; targetCount = 0; if (map[x - 1, y]) //Wall open at the left { targets[targetCount].X = x - 2; targets[targetCount].Y = y; targetCount++; } if (map[x + 1, y]) //Wall open at the right { targets[targetCount].X = x + 2; targets[targetCount].Y = y; targetCount++; } if (map[x, y - 1]) //Wall open at the top { targets[targetCount].X = x; targets[targetCount].Y = y - 2; targetCount++; } if (map[x, y + 1]) //Wall open at the bottom { targets[targetCount].X = x; targets[targetCount].Y = y + 2; targetCount++; } if (targetCount <= 2) //If currently only 2 exist at this tile, create junction { for (int i = 0; i < targetCount; i++) { var curMazePoint = targets[i]; if (curMazePoint.X != prex || curMazePoint.Y != prey) { if (curMazePoint.Y < y) { quatro.Push(0); //g.FillRectangle(Brushes.Green, x * 5, y * 5, 5, 5); } else if (curMazePoint.X > x) { quatro.Push(1); //g.FillRectangle(Brushes.Violet, x * 5, y * 5, 5, 5); } else if (curMazePoint.Y > y) { quatro.Push(2); //g.FillRectangle(Brushes.Blue, x * 5, y * 5, 5, 5); } else if (curMazePoint.X < x) { quatro.Push(3); //g.FillRectangle(Brushes.Brown, x * 5, y * 5, 5, 5); } break; } } } } //stackje.Push(target); map[target.X, target.Y] = true; currentStep++; if (target.X < x) { map[x - 1, y] = true; pixelChangedCallback.Invoke(x - 1, y, currentStep, totSteps); } else if (target.X > x) { map[x + 1, y] = true; pixelChangedCallback.Invoke(x + 1, y, currentStep, totSteps); } else if (target.Y < y) { map[x, y - 1] = true; pixelChangedCallback.Invoke(x, y - 1, currentStep, totSteps); } else if (target.Y > y) { map[x, y + 1] = true; pixelChangedCallback.Invoke(x, y + 1, currentStep, totSteps); } x = target.X; y = target.Y; prex = -1; prey = -1; pixelChangedCallback.Invoke(target.X, target.Y, currentStep, totSteps); } else { backtracking = true; if (map[x - 1, y]) //Wall open at the left { targets[targetCount].X = x - 2; targets[targetCount].Y = y; targetCount++; } if (map[x + 1, y]) //Wall open at the right { targets[targetCount].X = x + 2; targets[targetCount].Y = y; targetCount++; } if (map[x, y - 1]) //Wall open at the top { targets[targetCount].X = x; targets[targetCount].Y = y - 2; targetCount++; } if (map[x, y + 1]) //Wall open at the bottom { targets[targetCount].X = x; targets[targetCount].Y = y + 2; targetCount++; } if (targetCount > 2) //Junction { prex = x; prey = y; int whereToGo = quatro.Pop(); if (whereToGo == 0) { y -= 2; } else if (whereToGo == 1) { x += 2; } else if (whereToGo == 2) { y += 2; } else if (whereToGo == 3) { x -= 2; } } else { for (int i = 0; i < targetCount; i++) { var curMazePoint = targets[i]; if (curMazePoint.X != prex || curMazePoint.Y != prey) { prex = x; prey = y; x = curMazePoint.X; y = curMazePoint.Y; break; } } } pixelChangedCallback.Invoke(x, y, currentStep, totSteps); } if (x == 1 && y == 1) { break; } } }
/// <summary> /// Finds the path between the start and the endpoint in a maze /// </summary> /// <param name="start">The start point</param> /// <param name="end">The end point</param> /// <param name="map">The maze.InnerMap</param> /// <param name="callBack">The callback that can be used to see what the pathfinder is doing (or null), the boolean true = a new path find thingy or false when it determined that path is not correct</param> /// <returns>The direction from begin to end</returns> public static QuatroStack GoFind(MazePoint start, MazePoint end, InnerMap map, Action <int, int, PathFinderAction> callBack) { if (callBack == null) { callBack = (x, y, z) => { }; } //Callback won't work nice with this since it will find its path from back to front //Swap them so we don't have to reverse at the end ;) MazePoint temp = start; start = end; end = temp; int width = map.Width; int height = map.Height; //List<MazePoint> stackje = new List<MazePoint>(); //stackje.Add(start); QuatroStack quatro = new QuatroStack(); //0 == top, 1 == right, 2 == bot, 3 == left MazePoint cur = start; MazePoint prev = new MazePoint(-1, -1); Boolean backtracking = false; var possibleDirections = new MazePoint[4]; int possibleDirectionsCount = 0; int maxTimesAtStart = -1; while (true) { //cur = stackje[stackje.Count - 1]; var x = cur.X; var y = cur.Y; if (!backtracking) { callBack(x, y, PathFinderAction.Step); } else { callBack(x, y, PathFinderAction.Backtrack); } possibleDirectionsCount = 0; if ((prev.X != x - 1 || prev.Y != y) && x - 1 > 0 && map[x - 1, y]) { possibleDirections[possibleDirectionsCount].X = x - 1; possibleDirections[possibleDirectionsCount].Y = y; possibleDirectionsCount++; } if ((prev.X != x || prev.Y != y - 1) && y - 1 > 0 && map[x, y - 1]) { possibleDirections[possibleDirectionsCount].X = x; possibleDirections[possibleDirectionsCount].Y = y - 1; possibleDirectionsCount++; } if ((prev.X != x + 1 || prev.Y != y) && x + 1 < width - 1 && map[x + 1, y]) { possibleDirections[possibleDirectionsCount].X = x + 1; possibleDirections[possibleDirectionsCount].Y = y; possibleDirectionsCount++; } if ((prev.X != x || prev.Y != y + 1) && y + 1 < height - 1 && map[x, y + 1]) { possibleDirections[possibleDirectionsCount].X = x; possibleDirections[possibleDirectionsCount].Y = y + 1; possibleDirectionsCount++; } if (maxTimesAtStart == -1) { //Only the first time when we are actually at start maxTimesAtStart = possibleDirectionsCount; } else if (cur.X == start.X && cur.Y == start.Y) { maxTimesAtStart--; if (maxTimesAtStart == 0) { Console.WriteLine("No path found..."); break; } } //If we have more then 2 directions we got a junction (only if we're not backtracking) (This is actually 3 directions but we only count 2 because we don't count previous direction) //If we are however at the start (which is actually the end because we swap them around) we don't create a direction because you're at the end and don't need directions //If we are however at the end (which is the start) we will create a direction if we have more then 2 directions (This is 2 because we don't have a previous one yet) if ((possibleDirectionsCount >= 2 && !backtracking && (x != start.X || y != start.Y)) || (possibleDirectionsCount >= 1 && x == end.X && y == end.Y)) { //Create junction callBack(x, y, PathFinderAction.Junction); int directionWeCameFrom = -1; if (prev.X > cur.X) { directionWeCameFrom = 1; //Previous x was bigger so we came from the right } else if (prev.Y > cur.Y) { directionWeCameFrom = 2; } else if (prev.X < cur.X) { directionWeCameFrom = 3; } else if (prev.Y < cur.Y) { directionWeCameFrom = 0; } quatro.Push(directionWeCameFrom); } if (x == end.X && y == end.Y) { //path found return(quatro); } if (possibleDirectionsCount > 0) { if (backtracking && cur.X == start.X && cur.Y == start.Y) { //This is because we don't have a junction at the start point but we want to stop backtracking anyway backtracking = false; } if (backtracking) { if (possibleDirectionsCount >= 2) //Make sure we don't start searching again in the direction we originally came from { callBack(x, y, PathFinderAction.RefoundJunction); //Set the direction we backtracked from var lastBackTrackDir = -1; if (prev.X < cur.X) { lastBackTrackDir = 0; } else if (prev.Y < cur.Y) { lastBackTrackDir = 1; } else if (prev.X > cur.X) { lastBackTrackDir = 2; } else if (prev.Y > cur.Y) { lastBackTrackDir = 3; } var foundJunction = quatro.Peek(); int previousDirectionX = 0; int previousDirectionY = 0; switch (foundJunction) { case 0: previousDirectionY = -1; break; case 1: previousDirectionX = 1; break; case 2: previousDirectionY = 1; break; case 3: previousDirectionX = -1; break; } Boolean foundSomething = false; for (int i = 0; i < possibleDirectionsCount; i++) { var probDir = possibleDirections[i]; if (probDir.X != x + previousDirectionX || probDir.Y != y + previousDirectionY) { var directionOfThisDir = -1; if (probDir.X < cur.X) { directionOfThisDir = 0; } else if (probDir.Y < cur.Y) { directionOfThisDir = 1; } else if (probDir.X > cur.X) { directionOfThisDir = 2; } else if (probDir.Y > cur.Y) { directionOfThisDir = 3; } if (directionOfThisDir > lastBackTrackDir) { prev = cur; cur = probDir; foundSomething = true; backtracking = false; break; } } } if (!foundSomething) { callBack(x, y, PathFinderAction.RemovingJunction); quatro.Pop(); prev = cur; cur.X += previousDirectionX; cur.Y += previousDirectionY; } } else { prev = cur; cur = possibleDirections[0]; } } else { prev = cur; cur = possibleDirections[0]; } } else { MazePoint curtemp = cur; cur = prev; prev = curtemp; backtracking = true; } } return(new QuatroStack()); }
private void GoGenerate(InnerMap map, Maze maze, Random r, Action <int, int, long, long> pixelChangedCallback) { long totSteps = (((long)maze.Width - 1L) / 2L) * (((long)maze.Height - 1L) / 2L); long currentStep = 1; int width = maze.Width; int height = maze.Height; int x = 1; int y = 1; //Stack<MazePoint> stackje = new Stack<MazePoint>(); //stackje.Push(new MazePoint(x, y)); map[x, y] = true; pixelChangedCallback.Invoke(x, y, currentStep, totSteps); MazePoint[] targets = new MazePoint[4]; QuatroStack quatro = new QuatroStack(); //0 == top, 1 == right, 2 == bot, 3 == left Boolean backtracking = false; int prex = 0; int prey = 0; while (true) { //Console.WriteLine(quatro.Count + ", X: " + x + " Y: " + y); int targetCount = 0; if (x - 2 > 0 && !map[x - 2, y]) { targets[targetCount].X = x - 2; targets[targetCount].Y = y; targetCount++; } if (x + 2 < width - 1 && !map[x + 2, y]) { targets[targetCount].X = x + 2; targets[targetCount].Y = y; targetCount++; } if (y - 2 > 0 && !map[x, y - 2]) { targets[targetCount].X = x; targets[targetCount].Y = y - 2; targetCount++; } if (y + 2 < height - 1 && !map[x, y + 2]) { targets[targetCount].X = x; targets[targetCount].Y = y + 2; targetCount++; } //Thread.Sleep(1000); if (targetCount > 0) { var target = targets[r.Next(targetCount)]; if (backtracking) { backtracking = false; targetCount = 0; if (map[x - 1, y]) //Wall open at the left { targets[targetCount].X = x - 2; targets[targetCount].Y = y; targetCount++; } if (map[x + 1, y]) //Wall open at the right { targets[targetCount].X = x + 2; targets[targetCount].Y = y; targetCount++; } if (map[x, y - 1]) //Wall open at the top { targets[targetCount].X = x; targets[targetCount].Y = y - 2; targetCount++; } if (map[x, y + 1]) //Wall open at the bottom { targets[targetCount].X = x; targets[targetCount].Y = y + 2; targetCount++; } if (targetCount <= 2) //If currently only 2 exist at this tile, create junction { for (int i = 0; i < targetCount; i++) { var curMazePoint = targets[i]; if (curMazePoint.X != prex || curMazePoint.Y != prey) { if (curMazePoint.Y < y) { quatro.Push(0); //g.FillRectangle(Brushes.Green, x * 5, y * 5, 5, 5); } else if (curMazePoint.X > x) { quatro.Push(1); //g.FillRectangle(Brushes.Violet, x * 5, y * 5, 5, 5); } else if (curMazePoint.Y > y) { quatro.Push(2); //g.FillRectangle(Brushes.Blue, x * 5, y * 5, 5, 5); } else if (curMazePoint.X < x) { quatro.Push(3); //g.FillRectangle(Brushes.Brown, x * 5, y * 5, 5, 5); } break; } } } } //stackje.Push(target); map[target.X, target.Y] = true; currentStep++; if (target.X < x) { map[x - 1, y] = true; pixelChangedCallback.Invoke(x - 1, y, currentStep, totSteps); } else if (target.X > x) { map[x + 1, y] = true; pixelChangedCallback.Invoke(x + 1, y, currentStep, totSteps); } else if (target.Y < y) { map[x, y - 1] = true; pixelChangedCallback.Invoke(x, y - 1, currentStep, totSteps); } else if (target.Y > y) { map[x, y + 1] = true; pixelChangedCallback.Invoke(x, y + 1, currentStep, totSteps); } x = target.X; y = target.Y; prex = -1; prey = -1; pixelChangedCallback.Invoke(target.X, target.Y, currentStep, totSteps); } else { backtracking = true; if (map[x - 1, y]) //Wall open at the left { targets[targetCount].X = x - 2; targets[targetCount].Y = y; targetCount++; } if (map[x + 1, y]) //Wall open at the right { targets[targetCount].X = x + 2; targets[targetCount].Y = y; targetCount++; } if (map[x, y - 1]) //Wall open at the top { targets[targetCount].X = x; targets[targetCount].Y = y - 2; targetCount++; } if (map[x, y + 1]) //Wall open at the bottom { targets[targetCount].X = x; targets[targetCount].Y = y + 2; targetCount++; } if (targetCount > 2) //Junction { prex = x; prey = y; int whereToGo = quatro.Pop(); if (whereToGo == 0) { y -= 2; } else if (whereToGo == 1) { x += 2; } else if (whereToGo == 2) { y += 2; } else if (whereToGo == 3) { x -= 2; } } else { for (int i = 0; i < targetCount; i++) { var curMazePoint = targets[i]; if (curMazePoint.X != prex || curMazePoint.Y != prey) { prex = x; prey = y; x = curMazePoint.X; y = curMazePoint.Y; break; } } } pixelChangedCallback.Invoke(x, y, currentStep, totSteps); } if (x == 1 && y == 1) { break; } } }