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,128 -5,33 +5,139 @@@ 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
      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):
              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):