Skip to content

Instantly share code, notes, and snippets.

@zacharycarter
Created September 14, 2017 20:48
Show Gist options
  • Save zacharycarter/dbb8a2561f64fe67ada0edb0e1d538d6 to your computer and use it in GitHub Desktop.
Save zacharycarter/dbb8a2561f64fe67ada0edb0e1d538d6 to your computer and use it in GitHub Desktop.
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