patternpythonMinor
Text-based terrain generator (Part 2)
Viewed 0 times
textpartgeneratorbasedterrain
Problem
I've updated my text-based terrain generator a lot. Even though I haven't worked on it all that much. I really just want to know, like usual, is there anything I can improve? How can I shorten the code? What can be made more efficient? Yada yada yada...
Also, this is python 2.7 I just prefer to use
#!/usr/bin/env python
from random import choice
from os import system, name
class Tiles(object):
tree = '\033[7;1;32m \033[0m'
land = '\033[7;32m \033[0m'
sand = '\033[7;1;33m \033[0m'
water = '\033[7;1;34m \033[0m'
class Sizes(object):
small = 10
med1 = 20
med2 = 30
large = 40
sizes = (
Sizes.small, Sizes.med1, Sizes.med2, Sizes.large)
tiles = (
Tiles.land, Tiles.sand, Tiles.tree, Tiles.water)
def generate(world_size):
system('cls' if name == 'nt' else 'clear')
for _ in range(world_size):
print(''.join(choice(tiles) for _ in range(world_size)))
if __name__ == "__main__":
generate(choice(sizes))Also, this is python 2.7 I just prefer to use
print() over print.Solution
Your terran is randomly generated, you may use a "transition" map like this:
It read "When you're near a land, you have a chance to peek sand, two to pick tree, and 5 to pick another land".
Then you may want to code something like this to pick a tile according to the neighbors:
Finally you may want to use this "not so random" tile picker:
Note that I'm iterating the world twice, one in reverse, because my "first land" is randomly placed, I do not start from a corner, the world is built around the first randomly placed land.
I think there may be a lot of better ways to do this, but it was fun to do. You also may try to read about "flood fill".
Ceveat: I'll never build rivers with this kind of algorithm.
transitions = {Tiles.land: [Tiles.sand] +
[Tiles.tree] * 2 +
[Tiles.land] * 5,
Tiles.sand: [Tiles.water, Tiles.sand],
Tiles.tree: [Tiles.tree, Tiles.land],
Tiles.water: [Tiles.water] * 10
}It read "When you're near a land, you have a chance to peek sand, two to pick tree, and 5 to pick another land".
Then you may want to code something like this to pick a tile according to the neighbors:
def pick_tile_for(world, x, y):
surrounding = []
if x > 0:
surrounding.append(world[x - 1][y])
if y 0:
surrounding.append(world[x][y - 1])
if x < len(world) - 1:
surrounding.append(world[x + 1][y])
surrounding = [tile for tile in surrounding if tile is not None]
if len(surrounding) == 0:
return None
excluded = set(surrounding[0])
for tile in surrounding:
excluded = excluded - set(transitions[tile])
next = list(chain(*[[t for t in transitions[tile] if t not in excluded]
for tile in surrounding]))
return choice(next)Finally you may want to use this "not so random" tile picker:
def generate(world_size):
system('cls' if name == 'nt' else 'clear')
world = []
for x in range(world_size):
world.append([None for _ in range(world_size)])
world[choice(range(world_size))][choice(range(world_size))] = Tiles.land
for x in range(world_size):
for y in range(world_size):
if world[x][y] is None:
world[x][y] = pick_tile_for(world, x, y)
for x in range(world_size - 1, -1, -1):
for y in range(world_size - 1, -1, -1):
if world[x][y] is None:
world[x][y] = pick_tile_for(world, x, y)
for line in world:
print ''.join(line)Note that I'm iterating the world twice, one in reverse, because my "first land" is randomly placed, I do not start from a corner, the world is built around the first randomly placed land.
I think there may be a lot of better ways to do this, but it was fun to do. You also may try to read about "flood fill".
Ceveat: I'll never build rivers with this kind of algorithm.
Code Snippets
transitions = {Tiles.land: [Tiles.sand] +
[Tiles.tree] * 2 +
[Tiles.land] * 5,
Tiles.sand: [Tiles.water, Tiles.sand],
Tiles.tree: [Tiles.tree, Tiles.land],
Tiles.water: [Tiles.water] * 10
}def pick_tile_for(world, x, y):
surrounding = []
if x > 0:
surrounding.append(world[x - 1][y])
if y < len(world) - 1:
surrounding.append(world[x][y + 1])
if y > 0:
surrounding.append(world[x][y - 1])
if x < len(world) - 1:
surrounding.append(world[x + 1][y])
surrounding = [tile for tile in surrounding if tile is not None]
if len(surrounding) == 0:
return None
excluded = set(surrounding[0])
for tile in surrounding:
excluded = excluded - set(transitions[tile])
next = list(chain(*[[t for t in transitions[tile] if t not in excluded]
for tile in surrounding]))
return choice(next)def generate(world_size):
system('cls' if name == 'nt' else 'clear')
world = []
for x in range(world_size):
world.append([None for _ in range(world_size)])
world[choice(range(world_size))][choice(range(world_size))] = Tiles.land
for x in range(world_size):
for y in range(world_size):
if world[x][y] is None:
world[x][y] = pick_tile_for(world, x, y)
for x in range(world_size - 1, -1, -1):
for y in range(world_size - 1, -1, -1):
if world[x][y] is None:
world[x][y] = pick_tile_for(world, x, y)
for line in world:
print ''.join(line)Context
StackExchange Code Review Q#56864, answer score: 5
Revisions (0)
No revisions yet.