Last active
July 4, 2019 09:41
-
-
Save Skaruts/6e5ed14ea72bad7c95a8e222aba0d07c 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
################################################################################ | |
# 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