static void Main(string[] args) { //int seed = 0; //if (args.Length == 1) seed = Convert.ToInt32(args[0]); rand = new Random(); BSPNode map = new BSPNode() { XPos = 0, YPos = 0, MapXPos = 0, MapYPos = 0, XSize = 50, YSize = 50, Depth = 0, Active = true }; List<Room> rooms = new List<Room>(); Generate(map, rooms); map.PlotGrid(); //Console.WriteLine(map.ToString() + "\n"); // intersect test for (int i = rooms.Count - 1; i >= 0; i--) { bool found = false; for (int j = rooms.Count - 1; j >= 0; j--) { if (i == j) continue; if (Intersects(rooms[i].XPos, rooms[i].YPos, rooms[i].XSize, rooms[i].YSize, rooms[j].XPos, rooms[j].YPos, rooms[j].XSize, rooms[j].YSize)) found = true; } if (!found) rooms.RemoveAt(i); } // Room walk test for (int i = rooms.Count - 1; i >= 0; i--) { List<int> breadcrumbs = new List<int>(); breadcrumbs.Add(i); int walkCount = 1; WalkRoomsIntersect(rooms, i, breadcrumbs, ref walkCount); if (walkCount < rooms.Count) rooms.RemoveAt(i); } // Create Doors for (int i = rooms.Count - 1; i >= 0; i--) { bool doorCreated = false; var targetRooms = (from item in rooms orderby rand.Next() select item).ToList(); for (int j = targetRooms.Count - 1; j >= 0; j--) { if (i == j) continue; if (rooms[i].Doors.FirstOrDefault(dr => dr.AdjoiningRoom == targetRooms[j]) != null) continue; if (Intersects(rooms[i].XPos, rooms[i].YPos, rooms[i].XSize, rooms[i].YSize, targetRooms[j].XPos, targetRooms[j].YPos, targetRooms[j].XSize, targetRooms[j].YSize)) { for (int attempts = 0; attempts < MAX_DOOR_ATTEMPTS; attempts++) { // Room to the left if (targetRooms[j].XPos < rooms[i].XPos) { int dx = rooms[i].XPos; int dy = rooms[i].YPos + rand.Next(rooms[i].YSize - 3) + 1; if (dy > targetRooms[j].YPos && dy < targetRooms[j].YPos + (targetRooms[j].YSize - 2)) { doorCreated = true; rooms[i].Doors.Add(new Door() { AdjoiningRoom= targetRooms[j], Vertical=true, XPos = dx, YPos = dy}); targetRooms[j].Doors.Add(new Door() { AdjoiningRoom = rooms[i], Vertical = true, XPos = dx, YPos = dy }); break; } } // Room to the right if (targetRooms[j].XPos > rooms[i].XPos) { int dx = targetRooms[j].XPos; int dy = rooms[i].YPos + rand.Next(rooms[i].YSize - 3) + 1; if (dy > targetRooms[j].YPos && dy < targetRooms[j].YPos + (targetRooms[j].YSize - 2)) { doorCreated = true; rooms[i].Doors.Add(new Door() { AdjoiningRoom = targetRooms[j], Vertical = true, XPos = dx, YPos = dy }); targetRooms[j].Doors.Add(new Door() { AdjoiningRoom = rooms[i], Vertical = true, XPos = dx, YPos = dy }); break; } } // Room above if (targetRooms[j].YPos < rooms[i].YPos) { int dy = rooms[i].YPos; int dx = rooms[i].XPos + rand.Next(rooms[i].XSize - 3) + 1; if (dx > targetRooms[j].XPos && dx < targetRooms[j].XPos + (targetRooms[j].XSize - 2)) { doorCreated = true; rooms[i].Doors.Add(new Door() { AdjoiningRoom = targetRooms[j], Vertical = false, XPos = dx, YPos = dy }); targetRooms[j].Doors.Add(new Door() { AdjoiningRoom = rooms[i], Vertical = false, XPos = dx, YPos = dy }); break; } } // Room below if (targetRooms[j].YPos > rooms[i].YPos) { int dy = targetRooms[j].YPos; int dx = rooms[i].XPos + rand.Next(rooms[i].XSize - 3) + 1; if (dx > targetRooms[j].XPos && dx < targetRooms[j].XPos + (targetRooms[j].XSize - 2)) { doorCreated = true; rooms[i].Doors.Add(new Door() { AdjoiningRoom = targetRooms[j], Vertical = false, XPos = dx, YPos = dy }); targetRooms[j].Doors.Add(new Door() { AdjoiningRoom = rooms[i], Vertical = false, XPos = dx, YPos = dy }); break; } } } } if (doorCreated) break; } if(!doorCreated) rooms.RemoveAt(i); } // Room walk test using doors for (int i = rooms.Count - 1; i >= 0; i--) { List<int> breadcrumbs = new List<int>(); breadcrumbs.Add(i); int walkCount = 1; WalkRoomsDoors(rooms, i, breadcrumbs, ref walkCount); if (walkCount < rooms.Count) { for (int d = rooms[i].Doors.Count-1; d >= 0; d--) { rooms[i].Doors[d].AdjoiningRoom.Doors.Remove(rooms[i].Doors[d]); rooms[i].Doors.RemoveAt(d); } rooms.RemoveAt(i); } } // Test to see if doors still have valid connecting rooms foreach (Room r in rooms) { for (int i = r.Doors.Count - 1; i >= 0; i--) { if (r.Doors[i].AdjoiningRoom == null) r.Doors.RemoveAt(i); } } int[,] mapGrid = new int[map.XSize,map.YSize]; foreach (Room r in rooms) { for(int x=0;x<r.XSize;x++) for (int y = 0; y < r.YSize; y++) { if (x == 0 || y == 0 || x == r.XSize - 1 || y == r.YSize - 1) mapGrid[r.XPos + x, r.YPos + y] = 2; else mapGrid[r.XPos + x, r.YPos + y] = 1; } foreach (Door d in r.Doors) { if (d.AdjoiningRoom.Doors.Count == 0) continue; mapGrid[d.XPos, d.YPos] = 1; if(d.Vertical) mapGrid[d.XPos, d.YPos+1] = 1; else mapGrid[d.XPos+1, d.YPos] = 1; } } string mapOut = " "; for (int y = 0; y < map.YSize; y++) { for (int x = 0; x < map.XSize; x++) { mapOut += mapGrid[x, y]; } mapOut += "\n "; } mapOut = mapOut.Replace("0", " "); mapOut = mapOut.Replace("1", "."); Console.WriteLine(mapOut); if(rooms.Count<MIN_ROOMS || rooms.Count>MAX_ROOMS) Main(new[]{""}); string s = Console.ReadLine(); if(!string.IsNullOrEmpty(s)) Main(new []{s}); }
static void Generate(BSPNode node, List<Room> rooms) { //if (node.Depth == MAX_DEPTH) return; // Split horizontally or vertically depending on size ratio or random if XSize==YSize int split = node.XSize > node.YSize ? 1 : node.YSize > node.XSize ? 0 : rand.Next(2); switch (rand.Next(2)) { case 0: // Vertical split int splitY = (node.YSize/3) + rand.Next(node.YSize/2); if (splitY < MIN_SPLITSIZE || node.YSize - splitY < MIN_SPLITSIZE) { rooms.Add(new Room() { XPos = node.MapXPos, YPos = node.MapYPos, XSize = node.XSize, YSize = node.YSize }); return; } BSPNode top = new BSPNode() { XPos = 0, YPos = 0, MapXPos = node.MapXPos, MapYPos = node.MapYPos, XSize = node.XSize, YSize = splitY, Depth = node.Depth + 1, Active = true }; node.Children.Add(top); if (top.YSize < MIN_ROOMSIZE) { top.Active = false; } else { Generate(top, rooms); } BSPNode bottom = new BSPNode() { XPos = 0, YPos = splitY-1, MapXPos = node.MapXPos, MapYPos = node.MapYPos + (splitY-1), XSize = node.XSize, YSize = (node.YSize - splitY) +1, Depth = node.Depth + 1, Active = true }; node.Children.Add(bottom); if (bottom.YSize < MIN_ROOMSIZE) { bottom.Active = false; } else { Generate(bottom, rooms); } break; case 1: // Horizontal split int splitX = (node.XSize / 3) + rand.Next(node.XSize / 2); if (splitX < MIN_SPLITSIZE || node.XSize - splitX < MIN_SPLITSIZE) { rooms.Add(new Room() { XPos = node.MapXPos, YPos = node.MapYPos, XSize = node.XSize, YSize = node.YSize }); return; } BSPNode left = new BSPNode() { XPos = 0, YPos = 0, MapXPos = node.MapXPos, MapYPos = node.MapYPos, XSize = splitX, YSize = node.YSize, Depth = node.Depth + 1, Active = true }; node.Children.Add(left); if (left.XSize < MIN_ROOMSIZE) { left.Active = false; } else { Generate(left, rooms); } BSPNode right = new BSPNode() { XPos = splitX-1, YPos = 0, MapXPos = node.MapXPos + (splitX-1), MapYPos = node.MapYPos, XSize = (node.XSize - splitX) + 1, YSize = node.YSize, Depth = node.Depth + 1, Active = true }; node.Children.Add(right); if (right.XSize < MIN_ROOMSIZE) { right.Active = false; } else { Generate(right, rooms); } break; } }