private void MergeBetweenRows(MazeCell[] currentRow, MazeCell[] previousRow, Wall[] eWWalls) { // Determine which cell sets are present in the previous row. Dictionary key is the set ID. Dictionary value is a list of the positions (int) of cells in the row // that are part of the set. Dictionary <int, List <int> > setsInRow = new Dictionary <int, List <int> >(); for (int i = 0; i < 8; i++) { MazeCell c = previousRow[i]; if (setsInRow.ContainsKey(c.GetSetID())) { List <int> cellsInSet = setsInRow[c.GetSetID()]; cellsInSet.Add(i); } else { List <int> cellsInSet = new List <int>(); cellsInSet.Add(i); setsInRow[c.GetSetID()] = cellsInSet; } } // For each set in the previous row, randomly select one cell in the set in the previous row to merge to the adjacent cell in the current row. System.Random rand = new System.Random(); foreach (List <int> set in setsInRow.Values) { int positionToMerge = set[rand.Next(0, set.Count)]; // Merge the cell at this position with the cell in the adjacent position in the new row. eWWalls[positionToMerge] = null; MazeCell northNeighbor = currentRow[positionToMerge]; int cellSetID = previousRow[positionToMerge].GetSetID(); int neighborSetID = northNeighbor.GetSetID(); // Add the entire set of the cell in the current (northern-most) row to the set of the cell in the previous row. // If the northNeighbor is already in the same set as the cellToMerge, do not remove the wall between them to avoid creating loops. if (neighborSetID != cellSetID) { List <MazeCell> neighborSet = mazeCellSets[neighborSetID]; List <MazeCell> cellSet = mazeCellSets[cellSetID]; foreach (MazeCell c in neighborSet) { c.UpdateSetID(cellSetID); cellSet.Add(c); } mazeCellSets.Remove(neighborSetID); } } }
private void MergeWithinRow(MazeCell[] row, Wall[] nSWalls) { // Randomly choose number of cells to merge in range [1, 7). System.Random rand = new System.Random(); int numToMerge = rand.Next(1, 7); // Randomly choose cells to merge. May choose same cell multiple times. for (int i = 0; i < numToMerge; i++) { int cellPosition = rand.Next(0, 8); MazeCell cellToMerge = row[cellPosition]; // Randomly decide whether to merge with west cell or east cell (0 means west cell, 1 means east cell). If the cellToMerge is an edge cell (i.e. one of its // walls is an outer wall), merge with the only adjacent cell. int westOrEast = rand.Next(0, 2); if (cellPosition == 0 || (cellPosition < 7 && westOrEast == 1)) { // Merge with the cell to the east. nSWalls[cellPosition + 1] = null; // Entire set of the cell to the east of cellToMerge is added to the cellToMerge's set. MazeCell eastNeighbor = row[cellPosition + 1]; int neighborSetID = eastNeighbor.GetSetID(); int cellSetID = cellToMerge.GetSetID(); // If the eastNeighbor is already in the same set as the cellToMerge, do not remove the wall between them to avoid creating loops. if (neighborSetID != cellSetID) { List <MazeCell> neighborSet = mazeCellSets[neighborSetID]; List <MazeCell> cellSet = mazeCellSets[cellSetID]; foreach (MazeCell c in neighborSet) { c.UpdateSetID(cellSetID); cellSet.Add(c); } mazeCellSets.Remove(neighborSetID); } } else if (cellPosition == 7 || (cellPosition > 0 && westOrEast == 0)) { // Merge with the cell to the west. nSWalls[cellPosition] = null; // Entire set of cell to the west of cellToMerge is added to the cellToMerge's set. MazeCell westNeighbor = row[cellPosition - 1]; int neighborSetID = westNeighbor.GetSetID(); int cellSetID = cellToMerge.GetSetID(); // If the westNeighbor is already in the same set as the cellToMerge, do not remove the wall between them to avoid creating loops. if (neighborSetID != cellSetID) { List <MazeCell> neighborSet = mazeCellSets[neighborSetID]; List <MazeCell> cellSet = mazeCellSets[cellSetID]; foreach (MazeCell c in neighborSet) { c.UpdateSetID(cellSetID); cellSet.Add(c); } mazeCellSets.Remove(neighborSetID); } } } }
public void GenerateLastRow() { // Add row floor and outer maze boundaries, including an east-west-oriented boundary on the northern side of the maze. Instantiate(mazeRowFloor, new Vector3(100 + (numOfRows * 10), 0, 10), Quaternion.identity, maze); Transform westMazeBoundary = Instantiate(nsMazeBoundary, new Vector3(105 + (numOfRows * 10), 0, 90), Quaternion.identity, maze); westMazeBoundary.GetComponent <BoundaryController>().maze = this; Transform eastMazeBoundary = Instantiate(nsMazeBoundary, new Vector3(105 + (numOfRows * 10), 0, 10), Quaternion.identity, maze); eastMazeBoundary.GetComponent <BoundaryController>().maze = this; Transform ceilingBoundary = Instantiate(ceilingMazeBoundary, new Vector3(105 + (numOfRows * 10), 50, 50), Quaternion.Euler(90, 0, 0), maze); ceilingBoundary.GetComponent <BoundaryController>().maze = this; Transform northBoundary = Instantiate(ewMazeBoundary, new Vector3(110 + (numOfRows * 10), 0, 50), Quaternion.identity, maze); northBoundary.GetComponent <BoundaryController>().maze = this; // Add one more row, again merging sets, in which each cell has a northern wall and all sets are accessible. Wall[] nSWalls = new Wall[9]; for (int i = 0; i < 9; i++) { nSWalls[i] = new Wall(105 + (numOfRows * 10), 90 - (i * 10)); } // Create east-west oriented walls to be added to Maze Cells. // eWWalls[0] is on the south edge of the west-most cell. Wall[] eWWalls = new Wall[8]; for (int i = 0; i < 8; i++) { eWWalls[i] = new Wall(100 + (numOfRows * 10), 85 - (i * 10)); } // Create row of 8 new maze cells and add walls on west, east, and south edges. MazeCell[] newRow = new MazeCell[8]; mazeRows.Add(newRow); for (int i = 0; i < 8; i++) { MazeCell newCell = new MazeCell(numOfSets); newRow[i] = newCell; List <MazeCell> cellsInSet = new List <MazeCell>(); cellsInSet.Add(newCell); mazeCellSets[numOfSets] = cellsInSet; numOfSets++; } // Apply Eller's Algorithm: merge cells within row, then between new row and previous row. MergeWithinRow(newRow, nSWalls); MergeBetweenRows(newRow, mazeRows[numOfRows - 1], eWWalls); // Merge adjacent cells within the row if they are of different sets. for (int i = 0; i < 8; i++) { int currentSetID = newRow[i].GetSetID(); if (i < 7) { if (currentSetID != newRow[i + 1].GetSetID()) { // Merge with the cell to the east. nSWalls[i + 1] = null; // Add the entire set of the east cell to the set of the current cell MazeCell eastNeighbor = newRow[i + 1]; int neighborSetID = eastNeighbor.GetSetID(); List <MazeCell> neighborSet = mazeCellSets[neighborSetID]; List <MazeCell> cellSet = mazeCellSets[currentSetID]; foreach (MazeCell c in neighborSet) { c.UpdateSetID(currentSetID); cellSet.Add(c); } mazeCellSets.Remove(neighborSetID); } } if (i > 0) { if (currentSetID != newRow[i - 1].GetSetID()) { // Merge with the cell to the west. nSWalls[i] = null; // Add the entire set of the west cell to the set of the current cell MazeCell westNeighbor = newRow[i - 1]; int neighborSetID = westNeighbor.GetSetID(); List <MazeCell> neighborSet = mazeCellSets[neighborSetID]; List <MazeCell> cellSet = mazeCellSets[currentSetID]; foreach (MazeCell c in neighborSet) { c.UpdateSetID(currentSetID); cellSet.Add(c); } mazeCellSets.Remove(neighborSetID); } } } // Instantiate remaining north-south-oriented walls. for (int i = 0; i < 9; i++) { Wall w = nSWalls[i]; if (w != null) { Instantiate(nsMazeWall, new Vector3(w.GetXPosition(), 0, w.GetZPosition()), Quaternion.identity, maze); } } // Instantiate remaining east-west-oriented walls on south side of cells. for (int i = 0; i < 8; i++) { Wall w = eWWalls[i]; if (w != null) { Instantiate(ewMazeWall, new Vector3(w.GetXPosition(), 0, w.GetZPosition()), Quaternion.Euler(0, 90, 0), maze); } } // Instantiate a projectile in the center of each cell for (int i = 0; i < 8; i++) { Instantiate(projectile, new Vector3(105 + (numOfRows * 10), 1, 85 - (i * 10)), Quaternion.identity, maze); } numOfRows++; // Instantiate walls on the north side of each cell to close the maze. for (int i = 0; i < 8; i++) { Instantiate(ewMazeWall, new Vector3(100 + (numOfRows * 10), 0, 85 - (i * 10)), Quaternion.Euler(0, 90, 0), maze); } mazeRowEntrance.gameObject.SetActive(false); mazeCompleted = true; }