Merge of doom
authorDavid Sharpe <decoydavid@gmail.com>
Thu, 3 Mar 2016 22:31:06 +0000 (00:31 +0200)
committerDavid Sharpe <decoydavid@gmail.com>
Thu, 3 Mar 2016 22:31:06 +0000 (00:31 +0200)
1  2 
koperkapel/generators/maps.py

index bbb6d1384b8e59c4ee35c7b4a48576c58e2f3f38,4647fb003f07df84b96c475e96c570e810dfb3a0..6e6bdbdc1915f61627fb1c5872979bfe75fa5d54
@@@ -5,288 -5,197 +5,354 @@@ import mat
  import json
  import os
  
 -i = random.randint(0,100)
 -
 -
  ATTRIBUTE_MAP = {
-     '#': {'base': 'cwall',
-           'behaviour': [],
-          },
-     ' ': {'base': 'floor',
-           'behaviour': ['walk', 'fly'],
 -    '#': {'floor': {'base': 'cwall',
 -                      'behaviour': [],
 -                   },
--         },
+     ' ': {'floor': {'base': 'floor',
 -                      'behaviour': ['walk', 'fly'],
 -                   },
 -         },
++                    'behaviour': ['walk', 'fly'],
++                    },
++          },
+     'o': {'tunnels': {'base': 'underground',
+                       'behaviour': [],
 -                     }
 -         },
++                      }
++          },
+     '-': {'tunnels': {'base': 'tunnel',
 -                      'behaviour': ['walk',],
 -                   },
 -         },
++                      'behaviour': ['walk', ],
++                      },
++          },
  }
  
  
-     def link_passage(self, local_tile, foriegn_tile):
 +class Room:
 +    def __init__(self, coordinates, region):
 +        """
 +        """
 +        self.coordinates = [coordinates]
 +        self.region = region
 +        self.max_connections = 1
 +        self.passages = []
 +        self.tunnels = []
 +
 +    def is_linked(self):
 +        """
 +        Check if the room is linked to another room
 +        :return: Whether the room has any links or not
 +        """
 +        return len(self.passages) + len(self.tunnels) > 0
 +
 +    def add_region(self, coordinates):
 +        """
 +        Add a new region into an existing room
 +        :param coordinates: region coordinates to be added to room
 +        :return:
 +        """
 +        self.coordinates.append(coordinates)
 +
 +    def connect_rooms(self, other_rooms):
 +        """ Find the nearest rooms to this room
 +        :param other_rooms: list of Rooms objects that we are searching
 +        :return:
 +        """
 +        distance = []
 +        other_tile = []
 +        this_tile = []
 +        target_rooms = []
 +        for coord in self.coordinates:
 +            for room in other_rooms:
 +                if self == room:
 +                    continue
 +                for new_coord in room.coordinates:
 +                    distance.append(
 +                        math.sqrt((coord[0] - new_coord[0]) ** 2 +
 +                                  (coord[1] - new_coord[1]) ** 2))
 +                    other_tile.append(new_coord)
 +                    this_tile.append(coord)
 +                    target_rooms.append(room)
 +
 +        sorted_indices = [i[0] for i in sorted(enumerate(distance),
 +                                               key=lambda x:x[0])]
 +        for index in sorted_indices:
 +            if len(self.passages) + len(self.tunnels) >= self.max_connections:
 +                break
 +            if not target_rooms[index].is_linked():
 +                self.link_passage(this_tile[index], other_tile[index])
 +                target_rooms[index].link_passage(
 +                    other_tile[index], this_tile[index])
 +
-         :param foriegn_tile: tile in another room to which we wish to link
++    def link_passage(self, local_tile, foreign_tile):
 +        """ Link a passage between two rooms
 +        :param local_tile: tile in this room to which we wish to link
-         self.passages.append([local_tile, foriegn_tile])
++        :param foreign_tile: tile in another room to which we wish to link
 +        :return:
 +        """
-             print(region)
-             print(self.region)
++        self.passages.append([local_tile, foreign_tile])
 +
 +    def render_region(self, region, room_dist, region_size, tile_map, x, y):
 +        """ Check if a region is in this room and return the required tiles
 +        :param region: Region that we wish to render
 +        :param room_dist: Tile separation distance from other rooms
 +        :param region_size: Region size in tiles
++        :param tile_map: Tile map to update
++        :param x: X coordinate
++        :param y: Y coordinate
 +        :return:
 +        """
 +        if region in self.coordinates:
 +            print(self.coordinates)
 +            for ht in range(room_dist, region_size - room_dist):
 +                for wt in range(room_dist, region_size - room_dist):
 +                    tile_map[x + ht][y + wt] = ' '
 +
 +                    # if w == 0:
 +                    #     w_dist = self.dist_from_other_rooms
 +                    # elif self.region_map[h][w-1] == region_selected:
 +                    #     w_dist = 0
 +                    # else:
 +                    #     w_dist = self.dist_from_other_rooms
 +                    #
 +                    # if w + 1 == self.width:
 +                    #     e_dist = self.region_size - self.dist_from_other_rooms
 +                    # elif self.region_map[h][w+1] == region_selected:
 +                    #     e_dist = self.region_size
 +                    # else:
 +                    #     e_dist = self.region_size - self.dist_from_other_rooms
 +                    #
 +                    # if h == 0:
 +                    #     n_dist = self.dist_from_other_rooms
 +                    # elif self.region_map[h-1][w] == region_selected:
 +                    #     n_dist = 0
 +                    # else:
 +                    #     n_dist = self.dist_from_other_rooms
 +                    #
 +                    # if h + 1 == self.height:
 +                    #     s_dist = self.region_size - self.dist_from_other_rooms
 +                    # elif self.region_map[h+1][w] == region_selected:
 +                    #     s_dist = self.region_size
 +                    # else:
 +                    #     s_dist = self.region_size - self.dist_from_other_rooms
 +                    #
 +                    # for wt in range(w_dist, e_dist):
 +                    #     for ht in range(n_dist, s_dist):
 +                    #         self.map[h * self.region_size + ht]\
 +                    #             [w * self.region_size + wt] = ' '
 +
+ def random_cardinal():
+     """Return a random cardinal direction for random walks."""
+     return random.choice([(0, 1), (0, -1), (1, 0), (-1, 0)])
  
  class LevelGenerator:
      width = 0
      height = 0
 -    rooms = 0
 +    no_rooms = 0
 +    rooms = []
      map = None
 -    min_room_size = 0
 -    max_room_size = 0
 -    dist_from_edge = 0
 +    map2 = None
      dist_from_other_rooms = 0
 -    regions = None
 -    region = 0
 -    region_size_in_tiles = 0
 +    region_map = None
 +    regions = 0
 +    region_size = 0
  
 -    def __init__(self, width, height, rooms, min_room_size, max_room_size, dist_from_edge,
 -                 dist_from_other_rooms, region_size_in_tiles):
 +    def __init__(self, width, height, no_rooms, dist_from_other_rooms,
 +                 region_size):
          """ Initialize the level parameters
          """
          self.width = width
          self.height = height
 -        self.rooms = rooms
 -        self.min_room_size = min_room_size
 -        self.max_room_size = max_room_size
 -        self.dist_from_edge = dist_from_edge
 +        self.no_rooms = no_rooms
          self.dist_from_other_rooms = dist_from_other_rooms
 -        self.region_size_in_tiles = region_size_in_tiles
 +        self.region_size = region_size
 +        self.region_coordinates = []
  
      def generate(self):
          """ Generate a random level map
          """
 -        self.generate_regions()
 -        row = ['#' for x in range(self.width * self.region_size_in_tiles)]
 -        self.map = [row[:] for x in range(self.height * self.region_size_in_tiles)]
 -        regions_selected = random.sample(range(self.region), min(self.region, self.rooms))
 +        self.generate_rooms()
 +        regions_selected = random.sample(range(self.regions),
 +                                         min(self.regions, self.no_rooms))
 +        row = ['#' for x in range(self.width * self.region_size)]
 +        self.map = [row[:] for x in range(self.height * self.region_size)]
 +        self.map2 = [row[:] for x in range(self.height * self.region_size)]
          print('Regions: %s' % str(regions_selected))
          for region in regions_selected:
-             self.generate_tiles(region)
 +            self.rooms[region].connect_rooms(
 +                [self.rooms[i] for i in regions_selected])
 -        self.generate_underlayer()
+             self.generate_room(region)
-             # self.rooms[coord[0]].render_region(
-             #     coord[1], self.dist_from_other_rooms, self.region_size,
-             #     self.map2, coord[1][0] * self.region_size,
-             #     coord[1][1] * self.region_size)
 +        region_coordinates_selected = [p for p in self.region_coordinates if
 +                                       p[0] in regions_selected]
 +        print('Coords: %s' % str(region_coordinates_selected))
 +        for coord in region_coordinates_selected:
 +            print(str(coord))
++            self.rooms[coord[0]].render_region(
++                coord[1], self.dist_from_other_rooms, self.region_size,
++                self.map2, coord[1][0] * self.region_size,
++                coord[1][1] * self.region_size)
++        # self.generate_underlayer()
  
 -    def generate_regions(self):
 +    def generate_rooms(self):
          """ Generate a random level region map
          """
 -        row = ['#' for x in range(self.width)]
 -        self.regions = [row[:] for x in range(self.height)]
 +        row = [0 for x in range(self.width)]
 +        self.region_map = [row[:] for x in range(self.height)]
          for h in range(self.height):
              for w in range(self.width):
                  random_number = random.randint(0, 2)
 +                increment_region = False
                  if w == h == 0:
 -                    self.regions[h][w] = self.region
 -                    self.region += 1
 +                    update_value = self.regions
 +                    increment_region = True
                  elif h == 0:
                      if random_number > 1:
 -                        try:
 -                            self.regions[h][w] = self.regions[h][w - 1]
 -                        except:
 -                            print(h, w)
 -                            raise
 +                        update_value = self.region_map[h][w - 1]
                      else:
 -                        self.regions[h][w] = self.region
 -                        self.region += 1
 +                        update_value = self.regions
 +                        increment_region = True
                  elif w == 0:
                      if random_number > 1:
 -                        self.regions[h][w] = self.regions[h - 1][w]
 +                        update_value = self.region_map[h - 1][w]
                      else:
 -                        self.regions[h][w] = self.region
 -                        self.region += 1
 +                        update_value = self.regions
 +                        increment_region = True
                  else:
                      if random_number > 1:
 -                        self.regions[h][w] = self.regions[h - 1][w]
 +                        update_value = self.region_map[h - 1][w]
                      elif random_number > 0:
 -                        self.regions[h][w] = self.regions[h][w - 1]
 +                        update_value = self.region_map[h][w - 1]
                      else:
 -                        self.regions[h][w] = self.region
 -                        self.region += 1
 +                        update_value = self.regions
 +                        increment_region = True
 +                self.region_map[h][w] = update_value
 +                if increment_region:
-                     r = Room([h, w], self.regions)
++                    r = Room([h, w], update_value)
 +                    self.rooms.append(r)
 +                    self.region_coordinates.append([update_value, [h, w]])
 +                    self.regions += 1
 +                else:
-                     self.rooms[-1].add_region([h, w])
++                    for r in self.rooms:
++                        if r.region == update_value:
++                            r.add_region([h, w])
 +                    self.region_coordinates.append([update_value, [h, w]])
  
+     def generate_underlayer(self):
+         """Generate a small mess of tunnels to have something."""
+         width = len(self.map[0])
+         height = len(self.map)
+         row = ['o' for x in range(width)]
+         self.underlayer = [row[:] for x in range(height)]
+         # we create a set of biased random walks to create the tunnel network
+         for walk in range(random.randint(3, 6)):
+             x = width // 2 + random.randint(-8, 8)
+             y = height // 2 + random.randint(-8, 8)
+             dir_x, dir_y = random_cardinal()
+             max_steps = random.randint(40, width * height // 4)
+             for step in range(20, max_steps):
+                 if 0 < x < width - 1:
+                     if 0 < y < height - 1:
+                         self.underlayer[y][x] = '-'
+                 if random.random() > 0.7:
+                    dir_x, dir_y = random_cardinal()
+                 x += dir_x
+                 y += dir_y
 +    def generate_tiles(self, region_selected):
++        """Generate a small mess of tunnels to have something."""
++        width = len(self.map[0])
++        height = len(self.map)
++        row = ['o' for x in range(width)]
++        self.underlayer = [row[:] for x in range(height)]
++        # we create a set of biased random walks to create the tunnel network
++        for walk in range(random.randint(3, 6)):
++            x = width // 2 + random.randint(-8, 8)
++            y = height // 2 + random.randint(-8, 8)
++            dir_x, dir_y = random_cardinal()
++            max_steps = random.randint(40, width * height // 4)
++            for step in range(20, max_steps):
++                if 0 < x < width - 1:
++                    if 0 < y < height - 1:
++                        self.underlayer[y][x] = '-'
++                if random.random() > 0.7:
++                   dir_x, dir_y = random_cardinal()
++                x += dir_x
++                y += dir_y
++
+     def generate_room(self, region_selected):
          """
 +        :param region_selected:
 +        :return:
          """
          for h in range(self.height):
              for w in range(self.width):
 -                if self.regions[h][w] == region_selected:
 +                if self.region_map[h][w] == region_selected:
                      if w == 0:
                          w_dist = self.dist_from_other_rooms
 -                    elif self.regions[h][w-1] == region_selected:
 +                    elif self.region_map[h][w-1] == region_selected:
                          w_dist = 0
                      else:
                          w_dist = self.dist_from_other_rooms
  
                      if w + 1 == self.width:
 -                        e_dist = self.region_size_in_tiles - self.dist_from_other_rooms
 -                    elif self.regions[h][w+1] == region_selected:
 -                        e_dist = self.region_size_in_tiles
 +                        e_dist = self.region_size - self.dist_from_other_rooms
 +                    elif self.region_map[h][w+1] == region_selected:
 +                        e_dist = self.region_size
                      else:
 -                        e_dist = self.region_size_in_tiles - self.dist_from_other_rooms
 +                        e_dist = self.region_size - self.dist_from_other_rooms
  
                      if h == 0:
                          n_dist = self.dist_from_other_rooms
 -                    elif self.regions[h-1][w] == region_selected:
 +                    elif self.region_map[h-1][w] == region_selected:
                          n_dist = 0
                      else:
                          n_dist = self.dist_from_other_rooms
  
                      if h + 1 == self.height:
 -                        s_dist = self.region_size_in_tiles - self.dist_from_other_rooms
 -                    elif self.regions[h+1][w] == region_selected:
 -                        s_dist = self.region_size_in_tiles
 +                        s_dist = self.region_size - self.dist_from_other_rooms
 +                    elif self.region_map[h+1][w] == region_selected:
 +                        s_dist = self.region_size
                      else:
 -                        s_dist = self.region_size_in_tiles - self.dist_from_other_rooms
 +                        s_dist = self.region_size - self.dist_from_other_rooms
  
                      for wt in range(w_dist, e_dist):
                          for ht in range(n_dist, s_dist):
 -                            self.map[h * self.region_size_in_tiles + ht][w * self.region_size_in_tiles + wt] = ' '
 +                            self.map[h * self.region_size + ht]\
 +                                [w * self.region_size + wt] = str(region_selected)
  
      def display(self):
          file = open('map.txt', 'w')
 +        print('-----------------')
          for l in self.map:
              print(''.join(l))
              file.write(''.join(l))
              file.write('\n')
 -        print('')
 -        for l in self.underlayer:
 +        print('-----------------')
 +        for l in self.map2:
              print(''.join(l))
              file.write(''.join(l))
              file.write('\n')
 +        print('-----------------')
++        try:
++            for l in self.underlayer:
++                print(''.join(l))
++                file.write(''.join(l))
++                file.write('\n')
++        except AttributeError:
++            pass
          file.close()
 -        self._to_json()
 -        for l in self.regions:
 +        for l in self.region_map:
 +            # self._to_json()
              print(l)
  
      def _to_json(self):
          level = {}
+         level['tileset'] = 'bunker'
          level['tiles'] = []
-         for l in self.map:
+         for l, lu in zip(self.map, self.underlayer):
              row = []
-             for t in l:
-                 row.append(ATTRIBUTE_MAP[t])
+             for t1, t2 in zip(l, lu):
+                 tile = ATTRIBUTE_MAP[t1].copy()
+                 tile.update(ATTRIBUTE_MAP[t2])
+                 row.append(tile)
              level['tiles'].append(row)
-         name = os.path.join(os.path.dirname(__file__), '..', 'levels', 'map.json')
-         # FIXME: Do a lot better here 
+         # FIXME: Do a lot better here
          # Crude hack so the level is written into the levels folder
+         name = os.path.join(os.path.dirname(__file__), '..', 'levels', 'map.json')
          f = open(name, 'w')
          json.dump(level, f)
          f.close()
  
  if __name__ == '__main__':
      while True:
 -        level = LevelGenerator(width=8, height=5, rooms=12, min_room_size=5, max_room_size=20,
 -                               dist_from_edge=2, dist_from_other_rooms=1, region_size_in_tiles=6)
 +        level = LevelGenerator(width=4, height=3, no_rooms=4,
 +                               dist_from_other_rooms=0, region_size=3)
          level.generate()
          level.display()
          input("Press Enter to continue...")