Skip to content

Instantly share code, notes, and snippets.

@Skaruts
Last active July 4, 2019 09:41
Show Gist options
  • Save Skaruts/6e5ed14ea72bad7c95a8e222aba0d07c to your computer and use it in GitHub Desktop.
Save Skaruts/6e5ed14ea72bad7c95a8e222aba0d07c to your computer and use it in GitHub Desktop.
################################################################################
# cellular automata based off of
# https://gamedevelopment.tutsplus.com/tutorials/generate-random-cave-levels-using-cellular-automata--gamedev-9664
################################################################################
import random
import gen_ids, settings
{.experimental: "codeReordering".}
type
CaveGenerator* = ref object
w*:int
h*:int
# populate the grid randomly based on the density setting
method randomize_cells*(self:CaveGenerator, tilemap:var seq[seq[uint8]]) {.base.} =
for j in 0..<self.h:
for i in 0..<self.w:
if rand(100) < cg_density: tilemap[j][i] = ID_STONE # ID_STONE = 1
else: tilemap[j][i] = ID_EMPTY # ID_EMPTY = 0
# smooth it out
for i in 0..<cg_smothing:
self.smooth(tilemap)
# this is where the magic happens
method smooth*(self:CaveGenerator, old_map:var seq[seq[uint8]]) {.base.} =
var new_map = old_map # (Nim does a deepcopy of arrays by default)
for j in 0..<self.h:
for i in 0..<self.w:
# count neighbors that are stone
var nbs = self.count_neighbors(old_map, i, j)
# if cell is alive with too few neighbors, KILL!
if old_map[j][i] == ID_STONE:
if nbs < cg_death_rule: new_map[j][i] = ID_EMPTY
else: new_map[j][i] = ID_STONE
# if cell is dead with enough neighbors, revive it
else:
if nbs > cg_birth_rule: new_map[j][i] = ID_STONE
else: new_map[j][i] = ID_EMPTY
old_map = new_map
method count_neighbors*(self:CaveGenerator, tilemap:seq[seq[uint8]], x, y:int):int {.base.} =
# (Nim functions have an implicit return variable 'result' which gets silently returned
# automatically, so there's no need to create a variable and then return it.
# Though you can still do it if you want.
result = 0
for j in -1..1:
for i in -1..1:
if not (i == 0 and j == 0):
var nb_x = x+i # neighbor coords
var nb_y = y+j
# if it's out of bounds or if it's stone, count 1
if nb_x < 1 or nb_y < 1 or nb_x >= self.w-1 or nb_y >= self.h-1 or tilemap[nb_y][nb_x] == ID_STONE:
result += 1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment