Created
August 22, 2014 07:31
-
-
Save Bio2hazard/cd00f82b6e6e8ae79bfa to your computer and use it in GitHub Desktop.
Room Generator
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
namespace RoomGen | |
{ | |
public class Room | |
{ | |
public Map Map { get; private set; } | |
public Cell OriginCell { get; private set; } | |
public Cell EndCell { get; private set; } | |
public IEnumerable<Cell> RoomCells { get; private set; } | |
public Room(Map map, Cell originCell, Cell endCell) | |
{ | |
Map = map; | |
OriginCell = originCell; | |
EndCell = endCell; | |
RoomCells = Map.GetCellGrid(originCell.X, originCell.Y, endCell.X, endCell.Y); | |
GenerateRoom(); | |
} | |
private void GenerateRoom() | |
{ | |
var cellsWithBorder = Map.GetCellGrid(OriginCell.X - 1, OriginCell.Y - 1, EndCell.X + 1, EndCell.Y + 1); | |
// Generate Border | |
foreach (var cell in cellsWithBorder) | |
{ | |
cell.SetCell(CellType.RoomWall); | |
} | |
// Generate Floor | |
foreach (var roomCell in RoomCells) | |
{ | |
roomCell.SetCell(CellType.Empty); | |
} | |
} | |
} | |
public class Map | |
{ | |
public int SizeX { get; private set; } | |
public int SizeY { get; private set; } | |
public IList<Room> Rooms; | |
public IList<Cell> Cells; | |
public Map(int sizeX, int sizeY, int numRooms) | |
{ | |
Rooms = new List<Room>(); | |
Cells = new List<Cell>(); | |
SizeX = sizeX; | |
SizeY = sizeY; | |
GenerateMap(); | |
GenerateRooms(numRooms); | |
} | |
public IEnumerable<Cell> GetCellGrid(int startX, int startY, int endX, int endY) | |
{ | |
return Cells.Where(c => c.X >= startX && c.X <= endX && c.Y >= startY && c.Y <= endY); | |
} | |
public void Draw() | |
{ | |
// Example on how to draw with LINQ | |
var orderedCells = Cells.OrderByDescending(c => c.Y).ThenBy(c => c.X); | |
int lastY = SizeY-1; | |
foreach (var orderedCell in orderedCells) | |
{ | |
if (orderedCell.Y != lastY) | |
{ | |
Console.WriteLine(); | |
lastY = orderedCell.Y; | |
} | |
Console.ForegroundColor = orderedCell.Symbol.Color; | |
Console.Write(orderedCell.Symbol.Symbol); | |
Console.ResetColor(); | |
} | |
// Example on how to draw with for | |
//for (int y = SizeY - 1; y >= 0; y--) | |
//{ | |
// for (int x = 0; x < SizeX; x++) | |
// { | |
// Cell cell = Cells.SingleOrDefault(c => c.X == x && c.Y == y); | |
// if (cell != null) | |
// { | |
// Console.ForegroundColor = cell.Symbol.Color; | |
// Console.Write(cell.Symbol.Symbol); | |
// Console.ResetColor(); | |
// } | |
// else | |
// { | |
// Console.Write('X'); | |
// } | |
// } | |
// Console.WriteLine(); | |
//} | |
} | |
private void GenerateMap() | |
{ | |
for (int y = 0; y < SizeY; y++) | |
{ | |
for (int x = 0; x < SizeX; x++) | |
{ | |
Cell newCell = new Cell(x, y); | |
// Hardened border, ohhh yeah | |
if (x == 0 || y == 0 || x == SizeX-1 || y == SizeY-1) | |
{ | |
newCell.SetCell(CellType.SturdyWall); | |
} | |
Cells.Add(newCell); | |
} | |
} | |
} | |
private void GenerateRooms(int numRooms) | |
{ | |
int minRoomSize = 3; | |
int maxRoomSize = 6; | |
int border = 1; | |
Random randomizer = new Random(); | |
while (Rooms.Count < numRooms) | |
{ | |
int roomSizeX = randomizer.Next(minRoomSize, maxRoomSize + 1); | |
int roomSizeY = randomizer.Next(minRoomSize, maxRoomSize + 1); | |
int minEligibleX = border; | |
int minElibibleY = border; | |
int maxEligibleX = (((SizeX-1) - border) - roomSizeX); | |
int maxEligibleY = (((SizeY-1) - border) - roomSizeY); | |
// Time to work some amazing linq magic. | |
IList<Cell> eligibleCells = | |
Cells.Where(startCell => startCell.X < maxEligibleX && startCell.X > minEligibleX && startCell.Y < maxEligibleY && startCell.Y > minElibibleY && startCell.Type == CellType.Wall && | |
CheckCellTypeMatrix(startCell, Cells.FirstOrDefault(endCell => endCell.X == startCell.X + roomSizeX && endCell.Y == startCell.Y + roomSizeY), CellType.Wall)).ToList(); | |
// eligibleCells now holds a list of potential starting points for a room of the given size, taking obstructions into consideration | |
// If we don't have any, it means a room of that size can not fit on the map | |
if (!eligibleCells.Any()) | |
{ | |
// No more room for ... rooms! | |
// Lets try it with a smaller room: | |
if (maxRoomSize > minRoomSize) | |
{ | |
maxRoomSize--; | |
continue; | |
} | |
// Well, maxRoomSize is as low as it can get. Abort! | |
break; | |
} | |
Cell roomOriginCell = eligibleCells[randomizer.Next(0, eligibleCells.Count)]; | |
Cell roomEndCell = Cells.Single(c => c.X == roomOriginCell.X + roomSizeX && c.Y == roomOriginCell.Y + roomSizeY); | |
Room newRoom = new Room(this, roomOriginCell, roomEndCell); | |
Rooms.Add(newRoom); | |
} | |
} | |
private bool CheckCellTypeMatrix(Cell startCell, Cell endCell, CellType type) | |
{ | |
// Returns true if every cell between start & end is of type, false if any do not match | |
return !Cells.Any(c => c.X >= startCell.X && c.X <= endCell.X && c.Y >= startCell.Y && c.Y <= endCell.Y && c.Type != type); | |
} | |
} | |
public struct ColorSymbol | |
{ | |
public char Symbol; | |
public ConsoleColor Color; | |
} | |
public class Cell | |
{ | |
private ColorSymbol _colorSymbol; | |
private char _baseSymbol = '#'; | |
private ConsoleColor _baseColor = ConsoleColor.Gray; | |
public int X { get; private set; } | |
public int Y { get; private set; } | |
public CellType Type { get; private set; } | |
public bool CanWalk { get; private set; } | |
public bool CanSee { get; private set; } | |
public bool IsRoomWall { get; private set; } | |
public bool IsDiggable { get; private set; } | |
// Add your fun attributes for a cell here! | |
public ColorSymbol Symbol | |
{ | |
get | |
{ | |
_colorSymbol.Symbol = _baseSymbol; | |
_colorSymbol.Color = _baseColor; | |
// Here we'll check for entities occupying this cell and return their symbol instead | |
return _colorSymbol; | |
} | |
} | |
public Cell(int x, int y, CellType type = CellType.Wall) | |
{ | |
X = x; | |
Y = y; | |
SetCell(type); | |
} | |
public void SetCell(CellType preset = CellType.Wall) | |
{ | |
switch (preset) | |
{ | |
case CellType.Empty: | |
CanWalk = true; | |
CanSee = true; | |
IsDiggable = false; | |
_baseSymbol = '.'; | |
_baseColor = ConsoleColor.Gray; | |
break; | |
case CellType.RoomWall: | |
SetCell(CellType.Wall); | |
IsRoomWall = true; | |
_baseSymbol = 'O'; | |
_baseColor = ConsoleColor.Gray; | |
break; | |
case CellType.SturdyWall: | |
SetCell(CellType.Wall); | |
IsDiggable = false; | |
_baseColor = ConsoleColor.White; | |
break; | |
default: | |
CanWalk = false; | |
CanSee = false; | |
IsRoomWall = false; | |
IsDiggable = true; | |
_baseSymbol = '#'; | |
_baseColor = ConsoleColor.Gray; | |
break; | |
} | |
Type = preset; | |
} | |
} | |
public enum CellType | |
{ | |
Wall, | |
RoomWall, | |
Empty, | |
SturdyWall | |
} | |
class Program | |
{ | |
static void Main(string[] args) | |
{ | |
ConsoleKeyInfo key = new ConsoleKeyInfo(); | |
do | |
{ | |
Console.WriteLine(); | |
// Feel free to mess with the map size & number of rooms | |
Map map = new Map(20, 20, 5); | |
map.Draw(); | |
Console.WriteLine(); | |
Console.WriteLine("R to Redraw, any other key to exit"); | |
key = Console.ReadKey(); | |
} | |
while (key.Key == ConsoleKey.R); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment