Created
September 14, 2017 20:48
-
-
Save zacharycarter/dbb8a2561f64fe67ada0edb0e1d538d6 to your computer and use it in GitHub Desktop.
This file contains 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
import random, times, deques | |
type | |
DungeonKind {.pure.} = enum | |
Caves | |
CellKind {.pure.} = enum | |
Empty, Floor, Wall, Count | |
Cell = object | |
kind: CellKind | |
Dungeon = object | |
case kind: DungeonKind | |
of DungeonKind.Caves: | |
centerPoint: tuple[column, row: int] | |
width, height: int | |
cells: seq[Cell] | |
proc `[]`*(d: Dungeon, x, y: int): Cell = | |
d.cells[y * d.width + x] | |
proc `[]=`*(d: var Dungeon, x, y: int, cellKind: CellKind) = | |
d.cells[y * d.width + x].kind = cellKind | |
proc initialize(dungeon: var Dungeon, width, height: int) = | |
dungeon.width = width | |
dungeon.height = height | |
dungeon.cells = newSeq[Cell](width * height) | |
for column in 0..<dungeon.width: | |
for row in 0..<dungeon.height: | |
dungeon[column, row] = CellKind.Wall | |
proc countAdjacentWalls(caves: Dungeon, row, column: int): int = | |
for i in -1..<2: | |
for j in -1..<2: | |
if caves[column + i, row + j].kind != CellKind.Count: | |
inc(result) | |
proc simulateCaveFormation(caves: Dungeon): Dungeon = | |
initialize(result, caves.width, caves.height) | |
for column in 1..<caves.width-1: | |
for row in 1..<caves.height-1: | |
let walls = countAdjacentWalls(caves, row, column) | |
if walls > 4: | |
result[column, row] = CellKind.Wall | |
else: | |
result[column, row] = CellKind.Count | |
proc checkValidity(dungeon: var Dungeon, column, row: int): bool = | |
result = column > 0 and column < dungeon.width - 1 and row > 0 and row < dungeon.height - 1 and dungeon[column, row].kind != CellKind.Floor | |
proc floodFill(dungeon: var Dungeon, r, c: int, room: var seq[tuple[column, row: int]]) = | |
var queue = initDeque[tuple[column, row: int]]() | |
queue.addLast((c, r)) | |
while queue.len > 0: | |
let coord = queue.popFirst() | |
dungeon[coord.column, coord.row] = CellKind.Floor | |
if checkValidity(dungeon, coord.column - 1, coord.row): | |
queue.addLast((coord.column - 1, coord.row)) | |
if checkValidity(dungeon, coord.column + 1, coord.row): | |
queue.addLast((coord.column + 1, coord.row)) | |
if checkValidity(dungeon, coord.column, coord.row - 1): | |
queue.addLast((coord.column, coord.row - 1)) | |
if checkValidity(dungeon, coord.column, coord.row + 1): | |
queue.addLast((coord.column, coord.row + 1)) | |
proc generateCaves(caves: var Dungeon) = | |
const chanceToStartAlive = 0.55 | |
for column in 1..<caves.width-1: | |
for row in 1..<caves.height-1: | |
if random(1.0) < chanceToStartAlive: | |
caves[column, row] = CellKind.Count | |
for step in 0..<2: | |
caves = simulateCaveFormation(caves) | |
var caverns: seq[seq[tuple[column, row: int]]] = @[] | |
for column in 1..<caves.width-1: | |
for row in 1..<caves.height-1: | |
if caves[column, row].kind == CellKind.Count: | |
var cavern: seq[tuple[column, row: int]] = @[] | |
floodFill(caves, row, column, cavern) | |
caverns.add(cavern) | |
# var largestCavern = caverns[0] | |
# for cavern in 1..<caverns.len: | |
# if caverns[cavern].len > largestCavern.len: | |
# largestCavern = caverns[cavern] | |
# for cavern in caverns: | |
# if cavern == largestCavern: | |
# continue | |
# for space in cavern: | |
# caves[space.column, space.row] = CellKind.Wall | |
proc generate*(width, height: int, kind: DungeonKind): Dungeon = | |
initialize(result, width, height) | |
case kind | |
of DungeonKind.Caves: | |
generateCaves(result) | |
proc print*(dungeon: Dungeon) = | |
for column in 0..<dungeon.width: | |
for row in 0..<dungeon.height: | |
case dungeon[column, row].kind | |
of CellKind.Empty: | |
write(stdout, " ") | |
of CellKind.Floor: | |
write(stdout, ".") | |
of CellKind.Wall: | |
write(stdout, "#") | |
else: | |
write(stdout, "+") | |
write(stdout, "\n") | |
when isMainModule: | |
randomize(getTime().int64) | |
let dungeon = generate(64, 64, DungeonKind.Caves) | |
dungeon.print |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment