public override bool[] PreferredDirections(MazeSquare sq) { bool[] result = new bool[4]; for (int p = 0; p < 4; p++) { MazeSquare sq1 = sq.NeighborSquare((WallPosition)p); if (sq1 != null) { result[p] = ((shape[sq.XPos, sq.YPos] == shape[sq1.XPos, sq1.YPos]) == preferStayingInside); } } return(result); }
/// <summary> /// Initialize all squares in the mazeExtension (everything but trajectoryDistance). /// </summary> /// <param name="maze"></param> private void InitializeMazeExtension(Maze maze) { for (int i = 0; i < maze.XSize; i++) { for (int j = 0; j < maze.YSize; j++) { MazeSquare sq = maze[i, j]; MazeSquareExtension sqe = mazeExtension[i, j]; // extendedSquare: sqe.extendedSquare = sq; if (sq.isReserved) { // isDeadEnd: sqe.isDeadEnd = true; sqe.trajectoryDistance = -1; } else { // neighbors: sqe.neighbors = new List <MazeSquareExtension>(4); for (WallPosition wp = WallPosition.WP_MIN; wp <= WallPosition.WP_MAX; wp++) { MazeSquare sq2 = sq.NeighborSquare(wp); if (sq2 != null && !sq2.isReserved) { sqe.neighbors.Add(mazeExtension[sq2.XPos, sq2.YPos]); } } // Negative values mean: not initialized sqe.trajectoryDistance = int.MinValue; } } } }
/// <summary> /// Convert all undecided walls to either closed or open. /// In the resulting maze, there must be a path from every square to every other square. /// There must not be any circles, i.e. the maze must have a tree-like structure. /// </summary> private void BuildMaze() { // We hold a number of active squares in a stack. // Make the initial capacity sufficient to hold all squares. // Stack <MazeSquare> stack = new Stack <MazeSquare>(xSize * ySize); List <MazeSquare> outlineSquares = new List <MazeSquare>(); List <WallPosition> outlineWalls = new List <WallPosition>(); #region Start with a single random cell in the stack. while (true) { int x = random.Next(xSize); int y = random.Next(ySize); MazeSquare sq = this[x, y]; if (sq.MazeId == this.MazeId) { sq.isConnected = true; stack.Push(sq); break; } } #endregion #region Extend the maze by visiting the cells next to those in the stack. while (stack.Count > 0) { List <WallPosition> unresolvedWalls = new List <WallPosition>((int)WallPosition.WP_NUM); MazeSquare sq0 = stack.Pop(); // Collect the unfixed walls of sq0. // for (WallPosition wp = WallPosition.WP_MIN; wp <= WallPosition.WP_MAX; wp++) { switch (sq0[wp]) { case WallState.WS_MAYBE: MazeSquare sq = sq0.NeighborSquare(wp); if (sq.isConnected || sq.MazeId != sq0.MazeId) { sq0[wp] = sq[MazeSquare.OppositeWall(wp)] = WallState.WS_CLOSED; } else { unresolvedWalls.Add(wp); } break; // WS_MAYBE case WallState.WS_OUTLINE: outlineSquares.Add(sq0); outlineWalls.Add(wp); break; // WS_OUTLINE } } // foreach wp // Discard this square if it has no unresolved walls. if (unresolvedWalls.Count == 0) { // Note: This is the only place that may end the loop. // If the stack is empty: Open one outline wall. if (stack.Count == 0) { while (outlineSquares.Count > 0) { // Select a random square with an outline wall. int p = random.Next(outlineSquares.Count); MazeSquare sq = outlineSquares[p]; WallPosition wp = outlineWalls[p]; outlineSquares.RemoveAt(p); outlineWalls.RemoveAt(p); if (sq[wp] == WallState.WS_OUTLINE) { sq[wp] = WallState.WS_MAYBE; stack.Push(sq); // This square will be used in the next iteration. break; // from while(outlineSquares) } } } continue; // no walls to choose from } // Add the current cell to the stack. // Note: Do this before replacing unresolvedWalls with preferredWalls. if (unresolvedWalls.Count > 1) { stack.Push(sq0); } // Use only preferred wall positions. if (unresolvedWalls.Count > 1 && irregularMazeShape != null && (random.Next(100) < irregularMazeShape.ApplicationPercentage(this.irregularity))) { bool[] preferredPositions = irregularMazeShape.PreferredDirections(sq0); List <WallPosition> preferredWalls = new List <WallPosition>(unresolvedWalls.Count); foreach (WallPosition p in unresolvedWalls) { if (preferredPositions[(int)p]) { preferredWalls.Add(p); } } if (preferredWalls.Count > 0) { unresolvedWalls = preferredWalls; } } // Choose one wall. WallPosition wp0 = unresolvedWalls[random.Next(unresolvedWalls.Count)]; MazeSquare sq1 = sq0.NeighborSquare(wp0); // Open the wall. sq0[wp0] = sq1[MazeSquare.OppositeWall(wp0)] = WallState.WS_OPEN; // Add the new cell to the stack. sq1.isConnected = true; stack.Push(sq1); } // while stack is not empty #endregion }