public static Room RoomFromMaze(Maze m) { Room ret = new Room(m.Width, m.Height); for (int x = 0; x < ret.Width; x++){ for (int y = 0; y < ret.Height; y++){ switch(m[x,y]){ case MazeTileType.WALL: ret[x,y] = new Tile(TileType.ROCK); break; case MazeTileType.SPACE: ret[x,y] = new Tile(TileType.BLANK); break; default: ret[x,y] = new Tile(TileType.BLANK); break; } } } return ret; }
/// <summary> /// /// </summary> /// <param name="m"> /// A <see cref="Maze"/> /// </param> /// <param name="rand"> /// A <see cref="System.Random"/> /// </param> /// <returns> /// A <see cref="Room"/> /// </returns> public static Room ChambersFromMaze(Maze m, ChamberMap cm, System.Random rand, coords StartPosition, coords EndPosition) { // LEFTOFF: Here! Room ret = new Room(m.Width * Chambers.CHAMBER_WIDTH, m.Height * Chambers.CHAMBER_HEIGHT); for (int x = 0; x < m.Width; x++){ for (int y = 0; y < m.Height; y++){ // Select a random chamber type ChamberType ct; if (new coords(x,y) == EndPosition){ ct = ChamberType.TYPE_BOSS; } else{ ct = (ChamberType)(rand.Next() % (int)ChamberType.NumElements); if (ct == ChamberType.TYPE_BOSS){ ct = ChamberType.TYPE_5; } } cm[x,y] = ct; Room r = Chambers.Rooms(ct).Clone() as Room; switch(m[x,y]){ case MazeTileType.SPACE: // Handle the door carving // Left and Right if (x > 0){ if (m[x-1,y] == MazeTileType.SPACE){ Chambers.LeftDoor(r, TileType.SNOW); } } if (x < m.Width-1){ if (m[x+1,y] == MazeTileType.SPACE){ Chambers.RightDoor(r, TileType.SNOW); } } // Bottom and Top if (y > 0){ if (m[x,y-1] == MazeTileType.SPACE){ Chambers.BottomDoor(r, TileType.SNOW); } } if (y < m.Height-1){ if (m[x,y+1] == MazeTileType.SPACE){ Chambers.TopDoor(r, TileType.SNOW); } } ret.CopyRoom(r, x * Chambers.CHAMBER_WIDTH, y * Chambers.CHAMBER_HEIGHT); break; } } } return ret; }
/// <summary> /// Based on the Growing Tree algorithm. /// </summary> /// <param name="branchRate"> /// Zero is unbiased, positive will make branches more frequent, negative will cause long passages. /// This controls the position in the list chosen: positive makes the start of the list more likely. /// Negative makes the end of the list more likely. /// Large negative values make the original point obvious. /// Try values between -10 and 10. /// </param> /// <param name="rand"> /// A <see cref="System.Random"/> /// </param> /// <returns> /// A <see cref="Room"/> /// </returns> public static Maze GrowingTree(int width, int height, int branchRate, bool nDiag, System.Random rand, out coords StartLocation, out coords EndLocation) { // The return value Maze ret = new Maze(width, height); // Initialize the grid to contain UU tiles for (int x = 0; x < width; x++){ for (int y = 0; y < height; y++){ ret[x,y] = MazeTileType.UU; } } // List of coordinates of unexposed but undetermined cells var frontier = new List<coords>(); // Functions #region Carve // This one makes the cell at (x,y) a space Action<int, int> carve = (int x, int y ) => { var extra = new List<coords>(); ret[x,y] = MazeTileType.SPACE; if (x > 0){ if (ret[x-1,y] == MazeTileType.UU){ ret[x-1,y] = MazeTileType.XU; extra.Add(new coords(x-1,y)); } } if (x < width-1){ if (ret[x+1,y] == MazeTileType.UU){ ret[x+1,y] = MazeTileType.XU; extra.Add(new coords(x+1,y)); } } if (y > 0){ if (ret[x,y-1] == MazeTileType.UU){ ret[x,y-1] = MazeTileType.XU; extra.Add(new coords(x,y-1)); } } if (y < height - 1){ if (ret[x,y+1] == MazeTileType.UU){ ret[x,y+1] = MazeTileType.XU; extra.Add(new coords(x,y+1)); } } // Add the shuffled list to the frontier frontier.AddRange(Misc.ShuffleList<coords>(extra, rand)); }; #endregion #region Harden Action<int,int> harden = (int x, int y)=> { ret[x,y] = MazeTileType.WALL; }; #endregion #region Check // Test cell at (x,y) : can this become a space? // True indicates it should become a space, false indicates // it should become a wall Func<int, int, bool, bool> check = (int x, int y, bool nodiagonals) => { int edgeState = 0; if (x > 0){ if (ret[x-1, y] == MazeTileType.SPACE){ edgeState += 1; } } if (x < width - 1){ if (ret[x+1, y] == MazeTileType.SPACE){ edgeState += 2; } } if (y > 0){ if (ret[x, y-1] == MazeTileType.SPACE){ edgeState += 4; } } if (y < height - 1){ if (ret[x,y+1] == MazeTileType.SPACE){ edgeState += 8; } } // If this would make a diagonal connection, forbid it if (nodiagonals){ if (edgeState == 1){ if (x < width-1){ if (y > 0){ if (ret[x+1,y-1] == MazeTileType.SPACE){ return false; } } if (y < height-1){ if (ret[x+1,y+1] == MazeTileType.SPACE){ return false; } } } return true; } if (edgeState == 2){ if (x > 0){ if (y > 0){ if (ret[x-1, y-1] == MazeTileType.SPACE){ return false; } } if (y < height-1){ if (ret[x-1,y+1] == MazeTileType.SPACE){ return false; } } } return true; } if (edgeState == 4){ if (y < height-1){ if (x > 0){ if (ret[x-1,y+1] == MazeTileType.SPACE){ return false; } } if (x < width-1){ if (ret[x+1,y+1] == MazeTileType.SPACE){ return false; } } } return true; } if (edgeState == 8){ if (y > 0){ if (x > 0){ if (ret[x-1, y-1] == MazeTileType.SPACE){ return false; } } if (x < width-1){ if (ret[x+1,y-1] == MazeTileType.SPACE){ return false; } } } return true; } return false; } else{ if (edgeState == 1 || edgeState == 2 || edgeState == 4 || edgeState == 8){ return true; } return false; } }; #endregion // Now that the function definitions are over, the algorithm starts // Choose an original point at random and carve it out int xChoice = rand.Next(0, width); int yChoice = rand.Next(0, height); coords tempEnd; StartLocation = tempEnd = new coords(xChoice, yChoice); carve(xChoice, yChoice); while (frontier.Count > 0){ // Select a random edge double pos = rand.NextDouble(); pos = Math.Pow(pos, Math.Exp(-branchRate)); int rIdx = (int)(pos * frontier.Count); coords choice = frontier[rIdx]; if (check(choice.X, choice.Y, nDiag)){ carve(choice.X, choice.Y); tempEnd = choice; } else{ harden(choice.X, choice.Y); } frontier.RemoveAt(rIdx); } // Set unexposed cells to be walls for (int x = 0; x < width; x++){ for (int y = 0; y < height; y++){ if (ret[x,y] == MazeTileType.UU){ ret[x,y] = MazeTileType.WALL; } } } EndLocation = tempEnd; return ret; }