Skip to content

Instantly share code, notes, and snippets.

@felko
Last active October 27, 2016 20:21
Show Gist options
  • Save felko/7ca7d82ae847dbc647be to your computer and use it in GitHub Desktop.
Save felko/7ca7d82ae847dbc647be to your computer and use it in GitHub Desktop.
Generates a 2D map - randomly generated terrain
# -*- coding: utf-8 -*-
import random
HEIGHT = 32
BLOCK, VOID = True, False
class Block:
blocks = []
def __init__(self, ID, rep='█'):
self.ID = ID
self.rep = rep
Block.blocks.append(self)
def __str__(self):
return self.rep
def __repr__(self):
return self.rep
def __bool__(self):
return bool(self.ID)
# Base blocks
AIR = Block(ID=0, rep=' ')
STONE = Block(ID=1, rep='█')
DIRT = Block(ID=2, rep='▒')
GRASS = Block(ID=3, rep='▓')
COBBLE = Block(ID=4)
class Mineral(Block):
blocks = []
probs = [STONE] * 100
def __init__(self, ID, strat=range(0, HEIGHT), prob=1.0, rep='█'):
super().__init__(ID, rep)
self.strat = strat
self.prob = prob
Mineral.add_block(self)
@classmethod
def add_block(cls, block):
cls.blocks.append(block)
cls.probs = []
for block in cls.blocks:
cls.probs += [block] * block.prob
while len(cls.probs) < 1000:
cls.probs.append(STONE)
# Minerals
SAPHIR = Mineral(ID=5, strat=range(0, 10), prob=3, rep='S')
EMERALD = Mineral(ID=6, strat=range(0, 10), prob=3, rep='E')
RUBY = Mineral(ID=7, strat=range(0, 10), prob=3, rep='R')
DIAMOND = Mineral(ID=8, strat=range(0, 3), prob=1, rep='D')
GOLD = Mineral(ID=9, strat=range(0, 7), prob=2, rep='G')
def geology(array):
new_array = array[:]
what_can_be_in = lambda depth: [(block if (random.randint(0, 100) in range(block.prob)) and (len(new_array)-depth in block.strat) else STONE) for block in Mineral.blocks]
distance_from_surface = lambda x, y: len([line[x] for line in array[y::-1] if line[x]])
for y, line in enumerate(new_array):
for x, block in enumerate(line):
if block:
if distance_from_surface(x, y) > random.randint(3, 5):
new_block = STONE
elif distance_from_surface(x, y) == 1:
new_block = GRASS
else:
new_block = DIRT
new_array[y][x] = new_block
else:
new_array[y][x] = AIR
for y, line in enumerate(new_array):
for x, block in enumerate(line):
if block is STONE:
new_array[y][x] = random.choice(what_can_be_in(y))
return new_array
def generate(length, flatness, height=range(1, 16), headstart=8, deniv=1):
array = [[VOID for iy in range(height.stop)] for ix in range(length)]
mem = length * [0]
mem[0] = headstart
r = list(range(-deniv, deniv+1))
turns = 0
for x in range(1, length):
same = 0
for col in mem[:x-1:-1]:
if col == mem[x]:
same += 1
else:
break
new = (not random.randint(0, flatness//same)) * random.choice(r)
mem[x] = mem[x-1] + new
while mem[x] not in height:
if mem[x] < height.start:
mem[x] += 1
else:
mem[x] -= 1
if new < 0:
r = list(range(-deniv, 0)) + [0] * flatness
turns = flatness
elif new > 0:
r = list(range(1, deniv+1)) + [0] * flatness
turns = flatness
turns -= 1
if turns == 0:
r = list(range(-deniv, deniv+1))
for x, h in enumerate(mem):
array[x] = [BLOCK] * h + [VOID] * (len(array[x]) - h)
width = len(array)
height = len(array[0])
array = [[array[width-1 - x][y] for x in range(width)][::-1] for y in range(height)][::-1]
return array
def print_array(array):
rep = ''
for line in array:
for elt in line:
rep += elt.rep
rep += '\n'
print(rep)
if __name__ == '__main__':
import sys
length, flatness, height = map(int, sys.argv[1:4])
headstart, deniv = height//2, 1
try:
headstart = int(sys.argv[4])
deniv = int(sys.argv[5])
except IndexError:
pass
noise = generate(length, flatness, range(1, height), headstart, deniv)
print_array(geology(noise))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment