"""
generate_mazes.py - генерирует тестовые лабиринты в mazes/.

Состав:
    small_10x10.txt   - маленький с простым путём
    medium_50x50.txt  - средний с тупиками (DFS-генератор)
    large_100x100.txt - большой запутанный (DFS-генератор)
    empty_30x30.txt   - без стен внутри (только периметр)
    nopath_15x15.txt  - без пути от S до E (выход замурован)
    weighted_30x30.txt - со взвешенными клетками (асфальт/песок/болото)
"""

import os
import random

random.seed(2024)

MAZES_DIR = "mazes"
os.makedirs(MAZES_DIR, exist_ok=True)


def write(name, lines):
    path = os.path.join(MAZES_DIR, name)
    with open(path, "w", encoding="utf-8") as f:
        f.write("\n".join(lines) + "\n")
    print("written:", path, f"({len(lines)} строк, ширина {len(lines[0])})")


def make_small():
    """Маленький лабиринт 10x10, ручной."""
    raw = [
        "##########",
        "#S       #",
        "# ###### #",
        "#      # #",
        "###### # #",
        "#    # # #",
        "# ## # # #",
        "# #    # #",
        "# #####  E",
        "##########",
    ]
    write("small_10x10.txt", raw)


def _carve_perfect_maze(w, h, rng):
    """Генератор «идеального» лабиринта DFS (recursive backtracker),
    итеративный - чтобы не упасть в RecursionError на больших размерах."""
    grid = [['#'] * w for _ in range(h)]
    grid[1][1] = ' '
    stack = [(1, 1)]
    while stack:
        x, y = stack[-1]
        dirs = [(0, -2), (0, 2), (-2, 0), (2, 0)]
        rng.shuffle(dirs)
        carved = False
        for dx, dy in dirs:
            nx, ny = x + dx, y + dy
            if 0 < nx < w - 1 and 0 < ny < h - 1 and grid[ny][nx] == '#':
                grid[y + dy // 2][x + dx // 2] = ' '
                grid[ny][nx] = ' '
                stack.append((nx, ny))
                carved = True
                break
        if not carved:
            stack.pop()
    return grid


def make_with_generator(name, w, h):
    """Создаёт перфектный лабиринт и расставляет S/E в противоположных углах."""
    rng = random.Random(hash(name) & 0xFFFF)
    grid = _carve_perfect_maze(w, h, rng)
    grid[1][1] = 'S'
    grid[h - 2][w - 2] = 'E'
    lines = ["".join(row) for row in grid]
    write(name, lines)


def make_empty(name, w, h):
    """Пустая комната - только периметр."""
    lines = []
    for y in range(h):
        if y == 0 or y == h - 1:
            lines.append('#' * w)
        else:
            lines.append('#' + ' ' * (w - 2) + '#')
    # старт в левом верхнем углу, выход в правом нижнем
    row = list(lines[1]); row[1] = 'S'; lines[1] = "".join(row)
    row = list(lines[h - 2]); row[w - 2] = 'E'; lines[h - 2] = "".join(row)
    write(name, lines)


def make_nopath(name, w=15, h=15):
    """Лабиринт, в котором выход замурован - пути нет."""
    lines = ['#' * w]
    for y in range(1, h - 1):
        lines.append('#' + ' ' * (w - 2) + '#')
    lines.append('#' * w)
    # S слева сверху
    row = list(lines[1]); row[1] = 'S'; lines[1] = "".join(row)
    # E в правой нижней клетке, но обнесён стенами с двух сторон
    # делаем «коробочку» 3x3 вокруг E с одним зазором, который мы тут же закроем
    ex, ey = w - 2, h - 2
    # сначала откроем коробочку из стен 1 клетка по периметру вокруг E
    # построим коробочку: на (ex-1, ey-1)..(ex+1, ey+1) поставим '#' кроме E
    for yy in range(ey - 1, ey + 2):
        for xx in range(ex - 1, ex + 2):
            if 0 <= xx < w and 0 <= yy < h and not (xx == ex and yy == ey):
                row = list(lines[yy]); row[xx] = '#'; lines[yy] = "".join(row)
    row = list(lines[ey]); row[ex] = 'E'; lines[ey] = "".join(row)
    write(name, lines)


def make_weighted(name, w=30, h=30):
    """Перфектный лабиринт + случайные взвешенные клетки на проходимых местах."""
    rng = random.Random(7)
    grid = _carve_perfect_maze(w | 1, h | 1, rng)
    # Перекрасим часть проходов в '.', ',' и '~'
    for y, row in enumerate(grid):
        for x, ch in enumerate(row):
            if ch == ' ':
                r = rng.random()
                if r < 0.65:
                    grid[y][x] = ' '   # асфальт (1)
                elif r < 0.90:
                    grid[y][x] = ','   # песок (2)
                else:
                    grid[y][x] = '~'   # болото (3)
    grid[1][1] = 'S'
    grid[len(grid) - 2][len(grid[0]) - 2] = 'E'
    lines = ["".join(row) for row in grid]
    write(name, lines)


def main():
    make_small()
    make_with_generator("medium_51x51.txt", 51, 51)
    make_with_generator("large_101x101.txt", 101, 101)
    make_empty("empty_30x30.txt", 30, 30)
    make_nopath("nopath_15x15.txt", 15, 15)
    make_weighted("weighted_31x31.txt", 31, 31)


if __name__ == "__main__":
    main()
