```python
import matplotlib.pyplot as plt
import matplotlib.patches as patches
import random
import math
import networkx as nx
from mpl_toolkits.mplot3d.art3d import Poly3DCollection
import argparse

# Configuration
NUM_ROOMS = 20  # Увеличено количество комнат
MAP_WIDTH = 200  # Увеличены размеры карты
MAP_HEIGHT = 200
ROOM_MIN_SIZE = 5
ROOM_MAX_SIZE = 20
PASSAGEWAY_WIDTH = 3  # Увеличена ширина для лучшей видимости
EXTRA_CONNECTIONS_FACTOR = 0.4  # Коэффициент дополнительных соединений
ROOM_HEIGHT = 10  # Высота комнат (для 3D)
CORRIDOR_HEIGHT = 3  # Высота коридоров (для 3D)

class Room:
    def __init__(self, x, y, width, height, depth=ROOM_HEIGHT):
        self.x = x  # Bottom-left corner x
        self.y = y  # Bottom-left corner y
        self.width = width
        self.height = height
        self.depth = depth  # Высота комнаты для 3D
    
    def center(self):
        center_x = self.x + self.width / 2
        center_y = self.y + self.height / 2
        return (center_x, center_y)
    
    def intersects(self, other):
        return (self.x < other.x + other.width and
                self.x + self.width > other.x and
                self.y < other.y + other.height and
                self.y + self.height > other.y)

def generate_rooms():
    rooms = []
    attempts = 0
    max_attempts = NUM_ROOMS * 10  # Увеличено число попыток для размещения большего количества комнат

    while len(rooms) < NUM_ROOMS and attempts < max_attempts:
        width = random.randint(ROOM_MIN_SIZE, ROOM_MAX_SIZE)
        height = random.randint(ROOM_MIN_SIZE, ROOM_MAX_SIZE)
        x = random.randint(0, MAP_WIDTH - width)
        y = random.randint(0, MAP_HEIGHT - height)
        new_room = Room(x, y, width, height)

        # Check for overlap
        if any(new_room.intersects(other) for other in rooms):
            attempts += 1
            continue
        rooms.append(new_room)
    if len(rooms) < NUM_ROOMS:
        print(f"Could only place {len(rooms)} rooms after {attempts} attempts.")
    return rooms

def connect_rooms(rooms):
    """Connect rooms using a Minimum Spanning Tree and add additional connections."""
    G = nx.Graph()
    for i, room in enumerate(rooms):
        G.add_node(i, pos=room.center())

    # Add all possible edges with Euclidean distance as weight
    for i in range(len(rooms)):
        for j in range(i + 1, len(rooms)):
            pos_i = rooms[i].center()
            pos_j = rooms[j].center()
            distance = math.hypot(pos_i[0] - pos_j[0], pos_i[1] - pos_j[1])
            G.add_edge(i, j, weight=distance)

    # Compute MST
    mst = nx.minimum_spanning_tree(G)

    # Calculate количество дополнительных соединений
    extra_connections = int(EXTRA_CONNECTIONS_FACTOR * len(rooms))
    potential_extra = set(G.edges()) - set(mst.edges())

    if potential_extra:
        # Для логичной генерации дополнительных соединений, сортируем по расстоянию
        # и выбираем самые короткие ребра
        sorted_extra = sorted(potential_extra, key=lambda edge: G.edges[edge]['weight'])
        num_extra = min(extra_connections, len(sorted_extra))
        extra_edges = sorted_extra[:num_extra]
        for edge in extra_edges:
            mst.add_edge(*edge, weight=G.edges[edge]['weight'])

    return mst

def draw_map_2d(rooms, connections):
    fig, ax = plt.subplots(figsize=(15, 15))
    # Draw rooms
    for idx, room in enumerate(rooms):
        rect = patches.Rectangle(
            (room.x, room.y), 
            room.width, 
            room.height, 
            linewidth=1, 
            edgecolor='black', 
            facecolor='cyan', 
            alpha=0.8
        )
        ax.add_patch(rect)
        # Draw room centers
        cx, cy = room.center()
        ax.plot(cx, cy, 'ro')  # red dot at center
        # Добавим номер комнаты
        ax.text(cx, cy, str(idx+1), color='white', ha='center', va='center', fontsize=8, fontweight='bold')

    # Draw passageways as ортогональные коридоры (прямоугольники)
    for edge in connections.edges():
        room_a = rooms[edge[0]]
        room_b = rooms[edge[1]]
        ax_center = room_a.center()
        bx_center = room_b.center()

        ax_x, ax_y = ax_center
        bx_x, bx_y = bx_center

        # Decide order: horizontal then vertical or vice versa
        horizontal_first = random.choice([True, False])

        if horizontal_first:
            # Горизонтально, потом вертикально
            intermediate_point = (bx_x, ax_y)

            # Горизонтальный коридор
            corridor_length = abs(intermediate_point[0] - ax_x)
            corridor_x = min(ax_x, intermediate_point[0])
            corridor_y = ax_y - PASSAGEWAY_WIDTH / 2
            rect_h = patches.Rectangle(
                (corridor_x, corridor_y), 
                corridor_length, 
                PASSAGEWAY_WIDTH, 
                linewidth=0, 
                edgecolor=None, 
                facecolor='blue', 
                alpha=0.6
            )
            ax.add_patch(rect_h)

            # Вертикальный коридор
            corridor_length = abs(bx_y - ax_y)
            corridor_x = intermediate_point[0] - PASSAGEWAY_WIDTH / 2
            corridor_y = min(ax_y, bx_y)
            rect_v = patches.Rectangle(
                (corridor_x, corridor_y), 
                PASSAGEWAY_WIDTH, 
                corridor_length, 
                linewidth=0, 
                edgecolor=None, 
                facecolor='blue', 
                alpha=0.6
            )
            ax.add_patch(rect_v)
        else:
            # Вертикально, потом горизонтально
            intermediate_point = (ax_x, bx_y)

            # Вертикальный коридор
            corridor_length = abs(intermediate_point[1] - ax_y)
            corridor_x = ax_x - PASSAGEWAY_WIDTH / 2
            corridor_y = min(ax_y, intermediate_point[1])
            rect_v = patches.Rectangle(
                (corridor_x, corridor_y), 
                PASSAGEWAY_WIDTH, 
                corridor_length, 
                linewidth=0, 
                edgecolor=None, 
                facecolor='blue', 
                alpha=0.6
            )
            ax.add_patch(rect_v)

            # Горизонтальный коридор
            corridor_length = abs(bx_x - ax_x)
            corridor_x = min(ax_x, bx_x)
            corridor_y = intermediate_point[1] - PASSAGEWAY_WIDTH / 2
            rect_h = patches.Rectangle(
                (corridor_x, corridor_y), 
                corridor_length, 
                PASSAGEWAY_WIDTH, 
                linewidth=0, 
                edgecolor=None, 
                facecolor='blue', 
                alpha=0.6
            )
            ax.add_patch(rect_h)

    # Настройка границ и отображение
    ax.set_xlim(0, MAP_WIDTH)
    ax.set_ylim(0, MAP_HEIGHT)
    ax.set_aspect('equal')
    plt.title('Случайно сгенерированные комнаты с Ортогональными Коридорами (2D)', fontsize=16)
    plt.xlabel('X', fontsize=12)
    plt.ylabel('Y', fontsize=12)
    plt.grid(True, which='both', linestyle='--', linewidth=0.5, alpha=0.7)
    plt.show()

def draw_map_3d(rooms, connections):
    fig = plt.figure(figsize=(15, 15))
    ax = fig.add_subplot(111, projection='3d')
    
    # Функция для создания коробки (комнаты и коридоров)
    def create_box(x, y, z, dx, dy, dz, color='cyan', alpha=0.8):
        # Определяем вершины коробки
        vertices = [
            [x, y, z],
            [x + dx, y, z],
            [x + dx, y + dy, z],
            [x, y + dy, z],
            [x, y, z + dz],
            [x + dx, y, z + dz],
            [x + dx, y + dy, z + dz],
            [x, y + dy, z + dz]
        ]
        # Определяем грани коробки
        faces = [
            [vertices[0], vertices[1], vertices[2], vertices[3]],  # нижняя грань
            [vertices[4], vertices[5], vertices[6], vertices[7]],  # верхняя грань
            [vertices[0], vertices[1], vertices[5], vertices[4]],  # фронтальная грань
            [vertices[2], vertices[3], vertices[7], vertices[6]],  # задняя грань
            [vertices[1], vertices[2], vertices[6], vertices[5]],  # правая грань
            [vertices[4], vertices[7], vertices[3], vertices[0]]   # левая грань
        ]
        poly3d = Poly3DCollection(faces, facecolors=color, linewidths=1, edgecolors='black', alpha=alpha)
        ax.add_collection3d(poly3d)
    
    # Отрисовка комнат
    for idx, room in enumerate(rooms):
        x, y = room.x, room.y
        z = 0  # Нижнее основание комнаты
        dx, dy, dz = room.width, room.height, room.depth
        create_box(x, y, z, dx, dy, dz, color='cyan', alpha=0.8)
        # Отобразим номер комнаты на верхней грани
        cx, cy = room.center()
        ax.text(cx, cy, z + dz + 1, str(idx+1), color='white', ha='center', va='center', fontsize=8, fontweight='bold')

    # Отрисовка коридоров
    for edge in connections.edges():
        room_a = rooms[edge[0]]
        room_b = rooms[edge[1]]
        ax_center = room_a.center()
        bx_center = room_b.center()

        ax_x, ax_y = ax_center
        bx_x, bx_y = bx_center

        # Decide order: horizontal then vertical or vice versa
        horizontal_first = random.choice([True, False])

        if horizontal_first:
            # Горизонтально, потом вертикально
            intermediate_point = (bx_x, ax_y)
            # Коридор 1: Горизонтальный
            corridor_length = abs(intermediate_point[0] - ax_x)
            corridor_x = min(ax_x, intermediate_point[0])
            corridor_y = ax_y - PASSAGEWAY_WIDTH / 2
            z = 0
            dx_corridor, dy_corridor, dz_corridor = corridor_length, PASSAGEWAY_WIDTH, CORRIDOR_HEIGHT
            create_box(corridor_x, corridor_y, z, dx_corridor, dy_corridor, dz_corridor, color='blue', alpha=0.6)
            
            # Коридор 2: Вертикальный
            corridor_length = abs(bx_y - ax_y)
            corridor_x = intermediate_point[0] - PASSAGEWAY_WIDTH / 2
            corridor_y = min(ax_y, bx_y)
            dx_corridor, dy_corridor, dz_corridor = PASSAGEWAY_WIDTH, corridor_length, CORRIDOR_HEIGHT
            create_box(corridor_x, corridor_y, z, dx_corridor, dy_corridor, dz_corridor, color='blue', alpha=0.6)
        else:
            # Вертикально, потом горизонтально
            intermediate_point = (ax_x, bx_y)
            # Коридор 1: Вертикальный
            corridor_length = abs(intermediate_point[1] - ax_y)
            corridor_x = ax_x - PASSAGEWAY_WIDTH / 2
            corridor_y = min(ax_y, intermediate_point[1])
            dx_corridor, dy_corridor, dz_corridor = PASSAGEWAY_WIDTH, corridor_length, CORRIDOR_HEIGHT
            create_box(corridor_x, corridor_y, 0, dx_corridor, dy_corridor, dz_corridor, color='blue', alpha=0.6)
            
            # Коридор 2: Горизонтальный
            corridor_length = abs(bx_x - ax_x)
            corridor_x = min(ax_x, bx_x)
            corridor_y = intermediate_point[1] - PASSAGEWAY_WIDTH / 2
            dx_corridor, dy_corridor, dz_corridor = corridor_length, PASSAGEWAY_WIDTH, CORRIDOR_HEIGHT
            create_box(corridor_x, corridor_y, 0, dx_corridor, dy_corridor, dz_corridor, color='blue', alpha=0.6)

    # Настройки визуализации
    ax.set_xlim(0, MAP_WIDTH)
    ax.set_ylim(0, MAP_HEIGHT)
    ax.set_zlim(0, ROOM_HEIGHT + 5)  # Добавляем немного пространства над комнатами
    ax.set_xlabel('X', fontsize=12)
    ax.set_ylabel('Y', fontsize=12)
    ax.set_zlabel('Z (Высота)', fontsize=12)
    ax.set_title('Случайно сгенерированные комнаты с Ортогональными Коридорами (3D)', fontsize=16)
    
    # Настройка углов обзора
    ax.view_init(elev=20, azim=30)  # можно изменять для разных перспектив

    plt.show()

def main():
    # Добавим аргументы командной строки для выбора типа визуализации
    parser = argparse.ArgumentParser(description="Генерация и визуализация карт с комнатами и коридорами.")
    parser.add_argument('--view', type=str, default='3d', choices=['2d', '3d', 'both'],
                        help="Тип визуализации: '2d', '3d' или 'both'. По умолчанию: '2d'")
    args = parser.parse_args()

    rooms = generate_rooms()
    connections = connect_rooms(rooms)
    
    if args.view in ['2d', 'both']:
        draw_map_2d(rooms, connections)
    if args.view in ['3d', 'both']:
        draw_map_3d(rooms, connections)

if __name__ == "__main__":
    main()
```
Улучши код, оптимизируй код, структурируй код, проведи рефакторинг.
Напиши полный улучшенный код и список изменений