public static Coord[] GetEndCells() { var coords = new Maze.Coord[Maze.EndSize.x * Maze.EndSize.y]; var endCoord = Maze.GetEndCoord(); int i = 0; for (int xAux = 0; xAux < Maze.EndSize.x; xAux++) { for (int yAux = 0; yAux < Maze.EndSize.y; yAux++) { coords[i] = new Maze.Coord(endCoord.x + xAux, endCoord.y + yAux); i++; } } return(coords); }
public static Wall GetWallBetween(Maze.Coord currentCell, Maze.Coord nextCell) { Maze.Cell cellA = Maze.Cells[currentCell.x, currentCell.y]; Maze.Cell cellB = Maze.Cells[nextCell.x, nextCell.y]; if (cellA.x + 1 == cellB.x) { if (cellA.HasWall(Maze.Wall.East) && cellB.HasWall(Maze.Wall.West)) { return(Maze.Wall.East); } } if (cellB.x + 1 == cellA.x) { if (cellA.HasWall(Maze.Wall.West) && cellB.HasWall(Maze.Wall.East)) { return(Maze.Wall.West); } } if (cellA.y + 1 == cellB.y) { if (cellA.HasWall(Maze.Wall.North) && cellB.HasWall(Maze.Wall.South)) { return(Maze.Wall.North); } } if (cellB.y + 1 == cellA.y) { if (cellA.HasWall(Maze.Wall.South) && cellB.HasWall(Maze.Wall.North)) { return(Maze.Wall.South); } } return(Maze.Wall.None); }
Maze.Coord chooseUnvisitedNeighbor(Maze.Coord currentCell) { int x = currentCell.x; int y = currentCell.y; Maze.Coord[] candidates = new Maze.Coord[4]; int found = 0; // left if (x > 0 && Maze.Cells[x - 1, y].visited == false) { candidates[found++] = new Maze.Coord(x - 1, y); } // right if (x < Maze.MazeSize.x - 1 && Maze.Cells[x + 1, y].visited == false) { candidates[found++] = new Maze.Coord(x + 1, y); } // down if (y > 0 && Maze.Cells[x, y - 1].visited == false) { candidates[found++] = new Maze.Coord(x, y - 1); } // up if (y < Maze.MazeSize.y - 1 && Maze.Cells[x, y + 1].visited == false) { candidates[found++] = new Maze.Coord(x, y + 1); } if (found == 0) { return(null); } // choose a random candidate int choice = (int)(UnityEngine.Random.Range(0f, 1f) * found); return(candidates[choice]); }
private void CalculateModifiedFloodFill(params Maze.Coord[] targetCells) { var currentStack = new Stack <Maze.Coord>(); int columns = (int)Maze.MazeSize.x; int rows = (int)Maze.MazeSize.y; currentStack.Push(new Maze.Coord(xPos, yPos)); for (int y = 0; y < rows; y++) { for (int x = 0; x < columns; x++) { floodFill[x, x].queued = false; } } while (currentStack.Count > 0) { Maze.Coord coord = currentStack.Pop(); int neighborMinimumFloodValue = Int32.MaxValue; // left if (coord.x > 0 && !cells[coord.x, coord.y].HasWall(Maze.Wall.West)) { neighborMinimumFloodValue = Math.Min(neighborMinimumFloodValue, floodFill[coord.x - 1, coord.y].value); } // right if (coord.x < columns - 1 && !cells[coord.x, coord.y].HasWall(Maze.Wall.East)) { neighborMinimumFloodValue = Math.Min(neighborMinimumFloodValue, floodFill[coord.x + 1, coord.y].value); } // down if (coord.y > 0 && !cells[coord.x, coord.y].HasWall(Maze.Wall.South)) { neighborMinimumFloodValue = Math.Min(neighborMinimumFloodValue, floodFill[coord.x, coord.y - 1].value); } // up if (coord.y < rows - 1 && !cells[coord.x, coord.y].HasWall(Maze.Wall.North)) { neighborMinimumFloodValue = Math.Min(neighborMinimumFloodValue, floodFill[coord.x, coord.y + 1].value); } if (floodFill[xPos, yPos].value != neighborMinimumFloodValue + 1) { floodFill[xPos, yPos].value = neighborMinimumFloodValue + 1; floodFill[coord.x, coord.y].textMesh.text = "" + floodFill[coord.x, coord.y].value; // left if (coord.x > 0 && !floodFill[coord.x - 1, coord.y].queued && !cells[coord.x, coord.y].HasWall(Maze.Wall.West)) { currentStack.Push(new Maze.Coord(coord.x - 1, coord.y)); floodFill[coord.x - 1, coord.y].queued = true; } // right if (coord.x < columns - 1 && !floodFill[coord.x + 1, coord.y].queued && !cells[coord.x, coord.y].HasWall(Maze.Wall.East)) { currentStack.Push(new Maze.Coord(coord.x + 1, coord.y)); floodFill[coord.x + 1, coord.y].queued = true; } // down if (coord.y > 0 && !floodFill[coord.x, coord.y - 1].queued && !cells[coord.x, coord.y].HasWall(Maze.Wall.South)) { currentStack.Push(new Maze.Coord(coord.x, coord.y - 1)); floodFill[coord.x, coord.y - 1].queued = true; } // up if (coord.y < rows - 1 && !floodFill[coord.x, coord.y + 1].queued && !cells[coord.x, coord.y].HasWall(Maze.Wall.North)) { currentStack.Push(new Maze.Coord(coord.x, coord.y + 1)); floodFill[coord.x, coord.y + 1].queued = true; } } } }
/** * build a list of walls in the maze, cells in the maze, and how they connect to each other. * @param out * @throws IOException */ public void GenerateMaze() { // build the cells Maze.Cells = new Maze.Cell[Maze.MazeSize.x, Maze.MazeSize.y]; for (int y = 0; y < Maze.MazeSize.y; ++y) { for (int x = 0; x < Maze.MazeSize.x; ++x) { Maze.Cells[x, y] = new Maze.Cell(x, y, Maze.Wall.All); } } int unvisitedCells = Maze.Cells.Length; // -1 for initial cell. int cellsOnStack = 0; // Make the initial cell the current cell and mark it as visited Maze.Coord currentCell = new Maze.Coord(0, 0); Maze.Cells[0, 0].visited = true; --unvisitedCells; // While there are unvisited cells while (unvisitedCells > 0) { // If the current cell has any neighbours which have not been visited // Choose randomly one of the unvisited neighbours Maze.Coord nextCell = chooseUnvisitedNeighbor(currentCell); if (nextCell != null) { int cx = currentCell.x; int cy = currentCell.y; int nx = nextCell.x; int ny = nextCell.y; // Push the current cell to the stack Maze.Cells[cx, cy].onStack = true; ++cellsOnStack; // Remove the wall between the current cell and the chosen cell Maze.Wall wall = Maze.GetWallBetween(currentCell, nextCell); if (wall != Maze.Wall.None) { Maze.Cells[cx, cy].RemoveWall(wall); Maze.Cells[nx, ny].RemoveWall(Maze.GetOppositeWall(wall)); } // Make the chosen cell the current cell and mark it as visited currentCell = nextCell; cx = currentCell.x; cy = currentCell.y; Maze.Cells[cx, cy].visited = true; --unvisitedCells; } else if (cellsOnStack > 0) { // else if stack is not empty pop a cell from the stack for (int y = 0; y < Maze.MazeSize.y; ++y) { for (int x = 0; x < Maze.MazeSize.x; ++x) { if (Maze.Cells[x, y].onStack) { // Make it the current cell currentCell = new Maze.Coord(x, y); Maze.Cells[x, y].onStack = false; --cellsOnStack; goto breakLoops; } } } breakLoops :; } } // remove the walls between the end squares Maze.Coord auxCurrentCell, auxNextCell; Maze.Wall auxWall; var endCoord = Maze.GetEndCoord(); for (int xAux = 0; xAux < Maze.EndSize.x; xAux++) { for (int yAux = 0; yAux < Maze.EndSize.y - 1; yAux++) { currentCell = new Maze.Coord(endCoord.x + xAux, endCoord.y + yAux); auxCurrentCell = currentCell; auxNextCell = new Maze.Coord(currentCell.x, currentCell.y + 1); auxWall = Maze.GetWallBetween(auxCurrentCell, auxNextCell); if (auxWall != Maze.Wall.None) { Maze.Cells[auxCurrentCell.x, auxCurrentCell.y].walls ^= auxWall; Maze.Cells[auxNextCell.x, auxNextCell.y].walls ^= Maze.GetOppositeWall(auxWall); } } } for (int xAux = 0; xAux < Maze.EndSize.x - 1; xAux++) { for (int yAux = 0; yAux < Maze.EndSize.y; yAux++) { currentCell = new Maze.Coord(endCoord.x + xAux, endCoord.y + yAux); auxCurrentCell = currentCell; auxNextCell = new Maze.Coord(currentCell.x + 1, currentCell.y); auxWall = Maze.GetWallBetween(auxCurrentCell, auxNextCell); if (auxWall != Maze.Wall.None) { Maze.Cells[auxCurrentCell.x, auxCurrentCell.y].walls ^= auxWall; Maze.Cells[auxNextCell.x, auxNextCell.y].walls ^= Maze.GetOppositeWall(auxWall); } } } }
public void ToggleWall(RaycastHit hit, bool insert) { var pillar1 = GetClosestPillar(hit.point); var pillar2 = GetClosestPillar(hit.point, pillar1); Vector3 bottomLeftPosition = new Vector3(Math.Min(pillar1.position.x, pillar2.position.x), 0, Math.Min(pillar1.position.z, pillar2.position.z)); Vector3 topRightPosition = new Vector3(Math.Max(pillar1.position.x, pillar2.position.x), 0, Math.Max(pillar1.position.z, pillar2.position.z)); var distanceToWallCenter = Vector3.Distance(hit.point, (topRightPosition + bottomLeftPosition) / 2); if (distanceToWallCenter > distanceToWallThreshold) { return; } Maze.Coord bottomLeftCoord = new Maze.Coord(0, 0); bottomLeftCoord.x = (int)Math.Round((bottomLeftPosition.x) * Maze.MazeSize.x / (Camera.main.transform.position.x * 2)); bottomLeftCoord.y = (int)Math.Round((bottomLeftPosition.z) * Maze.MazeSize.y / (Camera.main.transform.position.z * 2)); Vector3 diffPillar = pillar2.position - pillar1.position; Maze.Coord c0 = null; Maze.Coord c1 = null; Maze.Wall wall = Maze.Wall.None; // vertical wall if (diffPillar.x == 0 && bottomLeftCoord.x > 0 && bottomLeftCoord.y >= 0 && bottomLeftCoord.x < Maze.MazeSize.x && bottomLeftCoord.y < Maze.MazeSize.y) { c0 = new Maze.Coord(bottomLeftCoord.x - 1, bottomLeftCoord.y); c1 = new Maze.Coord(bottomLeftCoord.x, bottomLeftCoord.y); wall = Maze.Wall.East; } // horizontal wall else if (diffPillar.z == 0 && bottomLeftCoord.x >= 0 && bottomLeftCoord.y > 0 && bottomLeftCoord.x < Maze.MazeSize.x && bottomLeftCoord.y < Maze.MazeSize.y) { c0 = new Maze.Coord(bottomLeftCoord.x, bottomLeftCoord.y - 1); c1 = new Maze.Coord(bottomLeftCoord.x, bottomLeftCoord.y); wall = Maze.Wall.North; } if (c0 != null && c1 != null) { if (insert) { Maze.Cells[c0.x, c0.y].InsertWall(wall); Maze.Cells[c1.x, c1.y].InsertWall(Maze.GetOppositeWall(wall)); } else { Maze.Cells[c0.x, c0.y].RemoveWall(wall); Maze.Cells[c1.x, c1.y].RemoveWall(Maze.GetOppositeWall(wall)); } MazeSerializer.ResetMazeName(); FindObjectOfType <MazeBuilder>().Render(); } }