218 lines
6.3 KiB
Python
218 lines
6.3 KiB
Python
import sys
|
|
import functools
|
|
import random
|
|
from noise import pnoise2
|
|
from termcolor import colored
|
|
|
|
def addition(a, b):
|
|
return a + b
|
|
|
|
seed = 0
|
|
seed_codes = sys.argv[1].encode("utf-8")
|
|
if seed_codes:
|
|
seed = functools.reduce(addition, seed_codes)
|
|
|
|
scale = 25.0
|
|
world_w, world_h = 16, 16
|
|
|
|
water_deepest = -0.3
|
|
water_deep = -0.2
|
|
water = -0.1
|
|
grass = 0.3
|
|
grass_high = 0.6
|
|
mountains = 1
|
|
block = "█"
|
|
block = block + block
|
|
LAND = "land"
|
|
WATER = "water"
|
|
|
|
def generate_world(seed):
|
|
try:
|
|
print("Seed: " + str(seed))
|
|
random.seed(seed)
|
|
world = []
|
|
for y in range(1, world_h + 1):
|
|
row = []
|
|
for x in range(1, world_w + 1):
|
|
row_noise = pnoise2(
|
|
x / scale,
|
|
y / scale,
|
|
octaves=10,
|
|
persistence=0.5,
|
|
lacunarity=2.0,
|
|
base=seed
|
|
)
|
|
row.append(row_noise)
|
|
world.append(row)
|
|
return world
|
|
except Exception as e:
|
|
print(e)
|
|
|
|
def terrain_matches(cell1, cell2, key):
|
|
return cell1[key] == cell2[key]
|
|
|
|
def get_from_coords(world, x, y):
|
|
if y >= 0 and x>= 0 and y < len(world) and x < len(world[y]):
|
|
return world[y][x]
|
|
return None
|
|
|
|
def get_adjacent(world, x, y):
|
|
north = None
|
|
east = None
|
|
south = None
|
|
west = None
|
|
|
|
if y - 1 >= 0:
|
|
north = get_from_coords(world, x, y - 1)
|
|
|
|
if x + 1 < world_w:
|
|
east = get_from_coords(world, x + 1, y)
|
|
|
|
if y + 1 < world_h:
|
|
south = get_from_coords(world, x, y + 1)
|
|
|
|
if x - 1 >= 0:
|
|
west = get_from_coords(world, x - 1, y)
|
|
|
|
return north, east, south, west
|
|
|
|
|
|
def group_terrain(world):
|
|
terrain = []
|
|
to_visit = []
|
|
for y in range(world_h):
|
|
row = []
|
|
for x in range(world_w):
|
|
cell = world[y][x]
|
|
cell_with_details = {
|
|
"v": cell,
|
|
"x": x,
|
|
"y": y,
|
|
"type": LAND if cell > water else WATER
|
|
}
|
|
row.append(cell_with_details)
|
|
to_visit.append(cell_with_details)
|
|
terrain.append(row)
|
|
|
|
visited = []
|
|
def lets_walk(w, x, y, visited, group_id):
|
|
cell = get_from_coords(w, x, y)
|
|
cell["group_id"] = group_id
|
|
visited.append(cell)
|
|
to_visit.remove(cell)
|
|
|
|
north, east, south, west = get_adjacent(w, x, y)
|
|
if north and not north in visited and terrain_matches(cell, north, "type"):
|
|
lets_walk(w, north["x"], north["y"], visited, group_id)
|
|
if east and not east in visited and terrain_matches(cell, east, "type"):
|
|
lets_walk(w, east["x"], east["y"], visited, group_id)
|
|
if south and not south in visited and terrain_matches(cell, south, "type"):
|
|
lets_walk(w, south["x"], south["y"], visited, group_id)
|
|
if west and not west in visited and terrain_matches(cell, west, "type"):
|
|
lets_walk(w, west["x"], west["y"], visited, group_id)
|
|
|
|
group_id = 0
|
|
while len(to_visit) > 0:
|
|
lets_walk(terrain, to_visit[0]["x"], to_visit[0]["y"], visited, group_id)
|
|
group_id += 1
|
|
|
|
print(group_id)
|
|
|
|
return terrain
|
|
|
|
def add_home(world):
|
|
print("Choosing home location")
|
|
home = (0, 0)
|
|
|
|
# build only on "grass"
|
|
valid_locations = []
|
|
for y in range(world_h):
|
|
if y > 0 and y < world_h - 1:
|
|
for x in range(world_w):
|
|
if x > 0 and x < world_w - 1:
|
|
cell = world[y][x]
|
|
if cell > water and cell <= grass:
|
|
valid_locations.append((x, y))
|
|
|
|
location = random.randrange(len(valid_locations))
|
|
home = valid_locations[location]
|
|
print(home)
|
|
return home
|
|
|
|
def add_dock(world, home):
|
|
print("Adding a dock")
|
|
# find the closest bit of water to the house?
|
|
# find the biggest body of water
|
|
|
|
def distribution(world):
|
|
total = world_w * world_h
|
|
above_water = 0
|
|
|
|
for y in range(world_h):
|
|
for x in range(world_w):
|
|
cell = world[y][x]
|
|
if cell > water:
|
|
above_water = above_water + 1
|
|
|
|
return above_water / total
|
|
|
|
def print_map(world, home):
|
|
print(" ", end="", flush=True)
|
|
for x in range(world_w):
|
|
to_print = str(x) + " " if x < 10 else x
|
|
print(to_print, end="", flush=True)
|
|
print("")
|
|
for y in range(world_h):
|
|
to_print = str(y) + " " if y < 10 else y
|
|
print(to_print, end="", flush=True)
|
|
for x in range(world_w):
|
|
cell = world[y][x]
|
|
if home[0] == x and home[1] == y:
|
|
print(colored(block, "magenta"), end="", flush=True)
|
|
elif cell <= water_deepest:
|
|
print(colored(block, "grey"), end="", flush=True)
|
|
elif cell <= water_deep:
|
|
print(colored(block, "blue", attrs=["dark"]), end="", flush=True)
|
|
elif cell <= water:
|
|
print(colored(block, "blue"), end="", flush=True)
|
|
elif cell <= grass:
|
|
print(colored(block, "green"), end="", flush=True)
|
|
elif cell <= grass_high:
|
|
print(colored(block, "green", attrs=["dark"]), end="", flush=True)
|
|
else:
|
|
print(colored(block, "white"), end="", flush=True)
|
|
print("")
|
|
|
|
def print_terrain(world):
|
|
colours = ["grey", "red", "green", "yellow", "blue", "magenta", "cyan", "white"]
|
|
colours = colours + colours + colours + colours
|
|
print(" ", end="", flush=True)
|
|
for x in range(world_w):
|
|
to_print = str(x) + " " if x < 10 else x
|
|
print(to_print, end="", flush=True)
|
|
print("")
|
|
for y in range(world_h):
|
|
to_print = str(y) + " " if y < 10 else y
|
|
print(to_print, end="", flush=True)
|
|
for x in range(world_w):
|
|
cell = world[y][x]
|
|
print(colored(block, colours[cell["group_id"]]), end="", flush=True)
|
|
print("")
|
|
|
|
world = generate_world(seed)
|
|
i = 1
|
|
land_percentage = distribution(world)
|
|
while (land_percentage < 0.25 or 1 - land_percentage < 0.25):
|
|
world = generate_world(seed + i)
|
|
land_percentage = distribution(world)
|
|
i = i + 1
|
|
|
|
world_terrain = group_terrain(world)
|
|
|
|
print(str(i - 1) + " seed iterations")
|
|
|
|
home = add_home(world)
|
|
dock = add_dock(world, home)
|
|
print_map(world, home)
|
|
print_terrain(world_terrain)
|