Skip to content

Instantly share code, notes, and snippets.

@Bio2hazard
Created August 22, 2014 07:31
Show Gist options
  • Save Bio2hazard/cd00f82b6e6e8ae79bfa to your computer and use it in GitHub Desktop.
Save Bio2hazard/cd00f82b6e6e8ae79bfa to your computer and use it in GitHub Desktop.
Room Generator
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