using Global; using Logica; using System.Drawing; namespace Logic { public class DepthFirstAlgoritm { public Maze maze; public bool isDone = false; private static readonly Random random = new Random(); private int x; private int y; private int attempts = 0; private bool goodStep; private int startcellId; public DepthFirstAlgoritm(Maze maze) { this.maze = maze; x = 0; y = 0; } /// /// Generate the maze. /// public void Generate() { maze.length--; maze.height--; CalculateIdStartCell(); while (isDone == false) { SetStep(); } CalculateStartStop(1); CalculateStartStop(maze.length - 1); maze.height++; maze.length++; GenerateBorder(); SetWalls(); } /// /// Set a step in a random direction. If there are too many unsuccesfull attempts it will force a step /// private void SetStep() { goodStep = false; attempts = 0; while (goodStep == false && isDone == false) { goodStep = false; int tempX = x; int tempY = y; if (attempts > 5) { ForceStep(); break; } else { Direction direction = GenerateRandomMovement(); switch (direction) { case Direction.up: tempY = y - 1; break; case Direction.down: tempY = y + 1; break; case Direction.right: tempX = x + 1; break; case Direction.left: tempX = x - 1; break; } if (tempY >= 1 && tempX >= 1 && tempX < maze.length && tempY < maze.height) { if (CheckStepInvalid(tempX, tempY) || CheckNeighbours(x, y, tempX, tempY)) { attempts = attempts + 1; } else { x = tempX; y = tempY; maze.cels[x, y].SetVisited(true); maze.cels[x, y].color = Color.Red; goodStep = true; } } else { attempts = attempts + 1; } } } } /// /// will force check every direction for a good step. /// private void ForceStep() { if (CheckStepInvalid((x + 1), y) == false && CheckNeighbours(x, y, x + 1, y) == false) { goodStep = true; x++; } else if (CheckStepInvalid((x - 1), y) == false && CheckNeighbours(x, y, x - 1, y) == false) { goodStep = true; x--; } else if (CheckStepInvalid(x, (y + 1)) == false && CheckNeighbours(x, y, x, y + 1) == false) { goodStep = true; y++; } else if (CheckStepInvalid(x, (y - 1)) == false && CheckNeighbours(x, y, x, y - 1) == false) { goodStep = true; y--; } if (goodStep) { maze.cels[x, y].SetVisited(true); maze.cels[x, y].color = Color.Red; attempts = 0; } if (goodStep == false) { BacktrackStep(); } } /// /// Backstep in a random direction untill a good step has been found /// if the step is back to the startcell then the maze is done. /// private void BacktrackStep() { int tempY = y; int tempX = x; maze.cels[x, y].isBacktracked = true; Direction[] directions = Enum.GetValues(typeof(Direction)) .Cast() .OrderBy(_ => Guid.NewGuid()) .ToArray(); //Random order foreach (Direction direction in directions) { switch (direction) { case Direction.up: tempY = y - 1; break; case Direction.down: tempY = y + 1; break; case Direction.right: tempX = x + 1; break; case Direction.left: tempX = x - 1; break; } if (IsVisited(tempX, tempY) == true) { y = tempY; x = tempX; maze.cels[x, y].color = Color.Black; break; } } if (maze.cels[x, y].id == startcellId) { isDone = true; } } /// /// Check if a cell has a neighbouring cell that has been visited /// /// /// /// /// /// private bool CheckNeighbours(int x1, int y1, int x2, int y2) { bool notOk = false; // Check adjacent neighbors if (IsVisited(x2 + 1, y2) && x2 + 1 != x1) { notOk = true; } else if (IsVisited(x2 - 1, y2) && x2 - 1 != x1) { notOk = true; } else if (IsVisited(x2, y2 + 1) && y2 + 1 != y1) { notOk = true; } else if (IsVisited(x2, y2 - 1) && y2 - 1 != y1) { notOk = true; } // Check diagonal neighbors if (IsVisited(x2 + 1, y2 + 1) && x2 + 1 != x1 && y2 + 1 != y1) { notOk = true; } else if (IsVisited(x2 - 1, y2 - 1) && x2 - 1 != x1 && y2 - 1 != y1) { notOk = true; } else if (IsVisited(x2 + 1, y2 - 1) && x2 + 1 != x1 && y2 - 1 != y1) { notOk = true; } else if (IsVisited(x2 - 1, y2 + 1) && x2 - 1 != x1 && y2 + 1 != y1) { notOk = true; } return notOk; } /// /// Check if a cell has been visited to prevent array out of bounds errors /// /// /// /// private bool IsVisited(int x, int y) { if (x >= 1 && x < maze.length && y >= 1 && y < maze.height) { return maze.cels[x, y].visited; } else if (x == 0 || y == 0 || x == maze.length || y == maze.height) { return false; //wall, so can ignore } else { return true; } } /// /// Generate a random direction /// /// /// private Direction GenerateRandomMovement() { int randomNumber = random.Next(1, 5); switch (randomNumber) { case 1: return Direction.up; case 2: return Direction.down; case 3: return Direction.left; case 4: return Direction.right; default: throw new InvalidOperationException("Invalid random number generated."); } } /// /// Pick random cell at the left side to generate the maze from /// private void CalculateIdStartCell() { y = random.Next(1, maze.height - 1); x = random.Next(1, maze.length - 1); startcellId = maze.cels[x, y].id; maze.cels[x, y].SetVisited(true); } /// /// Find a usable cell in a row for the start or the stop of the maze. /// /// private void CalculateStartStop(int x) { if (x >= 1 && x < maze.length) { for (int i = 1; i < maze.length; i++) { Random random = new Random(); int randomY = random.Next(0, maze.length); if (maze.cels[x, randomY].color == Color.Black) { if (x == 1) { maze.ball = new Ball(); maze.ball.SetLocation(x, randomY); } else { maze.cels[x, randomY].color = Color.Blue; Cell endCell = new Cell(); endCell.setLocation(x, randomY); maze.endCell = endCell; } break; } } } } public void GenerateBorder() { int width = maze.length; int height = maze.height; for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { if (x == 0 || x == width - 1 || y == 0 || y == height - 1) { maze.cels[x, y].isWall = true; } } } } /// /// Check if a step is invalid /// /// /// /// private bool CheckStepInvalid(int x, int y) { bool isInvalid = true; if (x >= 1 && x < maze.length && y >= 1 && y < maze.height) { if (x < maze.length && x >= 1 && isInvalid != false) { isInvalid = false; } if (y < maze.height && y >= 1 && isInvalid != false) { isInvalid = false; } if (IsVisited(x, y) == true) { isInvalid = true; } } return isInvalid; } /// /// Not too proud of this fix /// private void SetWalls() { for (int x = 0; x < maze.length; x++) { for (int y = 0; y < maze.height; y++) { if (maze.cels[x, y].color == Color.Red) { maze.cels[x, y].isWall = true; } } } } } }