Ejemplo n.º 1
0
    def make_corridors(self, level: 'Level') -> SquareStore:
        def heuristic(pos1: tuple, pos2: tuple) -> Union[float, int]:
            """A* heuristic for corridor creation (Manhattan distance)."""
            if any(level.locate(p) for p in (pos1, pos2)):
                return inf      # Avoid squares that contain something other than corridors
            return abs(pos1[0] - pos2[0]) + abs(pos1[1] - pos2[1])

        result = SquareStore()
        graph = nx.grid_2d_graph(Position.SCREEN_W, Position.SCREEN_H)
        # Sorts the rooms and then swaps them, in order to get a not-so-random dungeon
        rooms = sorted(list(level.rooms), key= lambda r: r.top_left)
        swaps = 0
        while d(1, 4) > 1 and swaps < len(level.rooms):
            a, b = sample(range(len(level.rooms)), 2)
            rooms[a], rooms[b] = rooms[b], rooms[a]
            swaps += 1
        graph.remove_nodes_from(pos for r in rooms for pos in r)#.squares)
        for r1, r2 in zip(rooms, rooms[1:]):
            start, end = CorridorFactory._rnd_doorway(r1), CorridorFactory._rnd_doorway(r2)
            del r1[start]
            del r2[end]
            for p in start, end:
                graph.add_node(p)            
                graph.add_edges_from((p, n) for n in p.neighbors(False) if level.locate(n) is None)
                result[position(*p)] = Square(SquareType.DOORWAY)
            path = nx.astar_path(graph, start, end, heuristic)
            result.update({position(*pos): Square(SquareType.CORRIDOR) for pos in path[1:-1]})
            graph.remove_nodes_from((start, end))   # Avoid using doorways in next computations
        return result
Ejemplo n.º 2
0
 def create(cls) -> 'Room':
     """Factory method."""
     width = cls._MIN_DIM + d(*cls._W_DICE) - 1
     height = cls._MIN_DIM + d(*cls._H_DICE) - 1
     top_left = position(
         randint(0, Position.SCREEN_W - width-1),
         randint(0, Position.SCREEN_H - height-1))
     return Room(top_left, width, height)
Ejemplo n.º 3
0
 def _build_squares(self) -> Dict[Position, Square]:
     """ Creates the dictionary of squares for the room. """
     b = self.bbox
     sq = {p: Square(t) for p, t in zip(self.corners, (SquareType.WALL_TL, SquareType.WALL_BL, SquareType.WALL_BR, SquareType.WALL_TR))}
     for idx in range(4):
         if idx % 2:     # Odd = horizontal wall
             sq.update({
                 position(i, b[idx]): Square(SquareType.WALL_H) 
                 for i in range(b[0]+1, b[2])
             })
         else:           # Even = vertical wall
             sq.update({
                 position(b[idx], i): Square(SquareType.WALL_V) 
                 for i in range(b[1]+1, b[3])
             })
     # Fill
     sq.update({position(i, j): Square(SquareType.ROOM) for i in range(b[0]+1, b[2]) for j in range(b[1]+1, b[3])})
     return sq
Ejemplo n.º 4
0
 def _rnd_doorway(room: Room) -> Position:
     tl, __, br, __ = room.corners
     candidates = [
         tl + (randint(1, room.width-1), 0),
         tl + (0, randint(1, room.height-1)),
         br - (randint(1, room.width-1), 0),
         br - (0, randint(1, room.height-1))
     ]
     candidates[:] = [
         pos for pos in candidates 
         if CorridorFactory._is_valid_doorway(pos) 
         and pos in room#.squares
         and room[pos].type in (SquareType.WALL_H, SquareType.WALL_V)
     ]
     if candidates:
         p = choice(candidates)
         return position(*p)
     else:
         return CorridorFactory._rnd_doorway(room)
Ejemplo n.º 5
0
 def corners(self) -> Tuple[Position, Position, Position, Position]:
     """Returns positions of corners in CCW order (TL, BL, BR, TR)."""
     return tuple(position(self.bbox[i], self.bbox[j]) for i, j in ((0, 1), (0, 3), (2, 3), (2, 1)))