Skip to main content
added 9 characters in body
Source Link
Ethan Bierlein
  • 15.9k
  • 4
  • 60
  • 146
  1. The initial 2D terrain array is generated with a provided width and height, and then filled entirely with NoneTypes.
  2. Then the array is iterated over a certain amount of times and "seeds" are placed in random positions. The value of these "seeds" is between a maximum height and a minimum height.
  3. After this happens, the array is then iterated over another given amount of times, and on each iteration, if a tile is found that isn't a NoneType, it's top, bottom, left and right neighbor values are determined by this: tile_value + randint(min_change, max_change). This process then repeats until the iteration ends.
  4. The array is iterated over one last time and replaces any remaining NoneTypes with the minimum height value.
  1. The initial 2D terrain array is generated with a provided width and height, and then filled with NoneTypes.
  2. Then the array is iterated over a certain amount of times and "seeds" are placed in random positions. The value of these "seeds" is between a maximum height and a minimum height.
  3. After this happens, the array is then iterated over another given amount of times, and on each iteration, if a tile is found that isn't a NoneType, it's top, bottom, left and right neighbor values are determined by this: tile_value + randint(min_change, max_change). This process then repeats until the iteration ends.
  4. The array is iterated over one last time and replaces any remaining NoneTypes with the minimum height value.
  1. The initial 2D terrain array is generated with a provided width and height, and then filled entirely with NoneTypes.
  2. Then the array is iterated over a certain amount of times and "seeds" are placed in random positions. The value of these "seeds" is between a maximum height and a minimum height.
  3. After this happens, the array is then iterated over another given amount of times, and on each iteration, if a tile is found that isn't a NoneType, it's top, bottom, left and right neighbor values are determined by this: tile_value + randint(min_change, max_change). This process then repeats until the iteration ends.
  4. The array is iterated over one last time and replaces any remaining NoneTypes with the minimum height value.
Source Link
Ethan Bierlein
  • 15.9k
  • 4
  • 60
  • 146

Generating realistic terrain data

I have some fascination with terrain generators, so I whipped up this generator in Python. The way it works is pretty simple, but I figure that I should give an explanation for those who don't want to try and figure it out.

  1. The initial 2D terrain array is generated with a provided width and height, and then filled with NoneTypes.
  2. Then the array is iterated over a certain amount of times and "seeds" are placed in random positions. The value of these "seeds" is between a maximum height and a minimum height.
  3. After this happens, the array is then iterated over another given amount of times, and on each iteration, if a tile is found that isn't a NoneType, it's top, bottom, left and right neighbor values are determined by this: tile_value + randint(min_change, max_change). This process then repeats until the iteration ends.
  4. The array is iterated over one last time and replaces any remaining NoneTypes with the minimum height value.

"""
A basic library containing a class for
generating basic terrain data.
"""
from random import randint

class Terrain(object):
    """
    Class for generating "realistic" looking terrain.
    """
    def __init__(self, max_height, min_height, max_change, min_change, width, height, iterations, seed_iterations):
        self.max_height = max_height
        self.min_height = min_height
        self.max_change = max_change
        self.min_change = min_change
        self.width = width
        self.height = height
        self.iterations = iterations
        self.seed_iterations = seed_iterations
        self.terrain = [[None for _ in range(self.width)] for _ in range(self.height)]
        
    def _seed_terrain(self):
        """
        Seed a random integer value at a random location.   
        """
        for _ in range(self.seed_iterations):
            self.terrain[randint(0, self.height-1)][randint(0, self.width-1)] = randint(self.min_height+1, self.max_height-1)
        
    def _iterate_terrain(self):
        """
        Loop through the terrain and change each
        nearby tile to a value slightly larger or 
        smaller than the current tile value.
        """
        for _ in range(self.iterations):
            for row in self.terrain:
                for tile in row:
                    current_row_index = self.terrain.index(row)
                    current_tile_index = row.index(tile)
                
                    upper_index = self.terrain.index(row)+1
                    lower_index = self.terrain.index(row)-1
                    right_index = row.index(tile)+1
                    left_index = row.index(tile)-1
                
                    if tile != None:
                        try:
                            self.terrain[upper_index][current_tile_index] = tile + randint(self.min_change, self.max_change) if tile >= self.min_height and tile <= self.max_height else tile
                            self.terrain[lower_index][current_tile_index] = tile + randint(self.min_change, self.max_change) if tile >= self.min_height and tile <= self.max_height else tile
                            self.terrain[current_row_index][right_index] = tile + randint(self.min_change, self.max_change) if tile >= self.min_height and tile <= self.max_height else tile
                            self.terrain[current_row_index][left_index] = tile + randint(self.min_change, self.max_change) if tile >= self.min_height and tile <= self.max_height else tile
                        except IndexError:
                            continue
                            
    def _final_pass(self):
        """
        Check to make sure that there are no
        NoneTypes left in the array, and if
        there are, change them to the minimum
        tile value.
        """
        for row in self.terrain:
            for tile in row:
                if tile == None:
                    self.terrain[self.terrain.index(row)][row.index(tile)] = self.min_height-1
                    
    def generate(self):
        """
        Generate the final terrain.
        """
        self._seed_terrain()
        self._iterate_terrain()
        self._final_pass()
        
    def render(self, spacing=" "):
        """
        Render the completed terrain.
        """
        for row in self.terrain:
            print spacing.join([str(tile) for tile in row])
            
    def return_terrain(self):
        return self.terrain

Few questions that you can answer about my code if you want.

  1. Is this code Pythonic?
  2. How can it be made faster? Can it be made Faster?
  3. Is there a different way I should implement this?
  4. How can I shorten some lines?