Не понимаю как решить задачу "Гирлянда"

Сделал один элемент, но как его соединять с другими - не понимаю, прошу помощи

введите сюда описание изображения

n = int(input())
maxn = n * 2 + 1

for i in range(maxn):
    if i <= maxn // 2:
        dots = maxn // 2 - i
        thing = 2 * i + 1
    else:
        dots = i - maxn // 2
        thing = 2 * (maxn - i) - 1
    
    print("." * dots, end="")
    if i == 0 or i == maxn - 1:
        print("#" * thing, end="")
    else: 
        print("#" + "." * (thing - 2) + "#", end="")

    print("." * dots)

Ответы (1 шт):

Автор решения: Vitalizzare ушел в монастырь

Развивая исходную модель

В этой части я использую исходный код как черный ящик. Код вполне рабочий. Запишем его в виде функции, заменив n на size, "#" на brick и задав их в качестве параметров:

def print_link(size: int, brick: str) -> None:
    maxn = size * 2 + 1
    for i in range(maxn):
        if i <= maxn // 2:
            dots = maxn // 2 - i
            thing = 2 * i + 1
        else:
            dots = i - maxn // 2
            thing = 2 * (maxn - i) - 1
        print("." * dots, end="")
        if i == 0 or i == maxn - 1:
            print(brick * thing, end="")
        else: 
            print(brick + "." * (thing - 2) + brick, end="")
        print("." * dots)

В таком подходе данные выводятся на экран, после чего мы не можем их изменить. Исправим это, подменив стандартное устройство вывода управляемым текстовым буфером:

def get_link(size: int, brick: str) -> list[str]:
    from io import StringIO
    from contextlib import redirect_stdout

    buffer = StringIO()
    with redirect_stdout(buffer):
        print_link(size, brick)
    return buffer.getvalue().splitlines()

Теперь у нас есть возможность связать звенья между собой. Последовательность действий может быть следующей:

  1. Построить верхнее и нижнее звено.
  2. Заменить центр предпоследней строки верхнего звена центром первой строки нижнего.
  3. Заменить центр второй строки нижнего звена центром последней строки верхнего.
  4. Удалить последнюю строку верхнего и первую строку нижнего звеньев.
  5. Выровнять звенья по ширине.
  6. Состыковать звенья.

Одна из возможных реализаций:

from collections.abc import Sequence, Generator


def replace_middle(outer: str, inner: str) -> str:
    half_outer = len(outer) // 2
    left, right = outer[:half_outer], outer[half_outer + 1:]
    middle = inner[len(inner) // 2]
    return left + middle + right


def generate_chain(n: int, sizes: Sequence[int]) -> Generator[str]:
    from itertools import cycle

    if n < 1:
        return
    brick = cycle("#*")
    top = get_link(sizes[0], next(brick))
    if n == 1:
        yield from top
    else:
        align_width = f"{{:.^{1+2*max(sizes)}}}".format
        for size in sizes[1:]:
            bottom = get_link(size, next(brick))
            top[-2] = replace_middle(top[-2], bottom[0])
            bottom[1] = replace_middle(bottom[1], top[-1])
            yield from map(align_width, top[:-1])
            top = bottom[1:]
        yield from map(align_width, top)


def main():
    data = input("Количество звеньев и их размеры: ")
    n, *sizes = map(int, data.split())
    print(*generate_chain(n, sizes), sep="\n")

Пример результата:

Количество звеньев и их размеры: 3 1 1 2
..#..
.#*#.
.*#*.
.#*#.
#...#
.#.#.
..#..

Альтернативный взгляд

Как вы смотрите на то, чтобы вместо печати звеньев работать с двумерным массивом ячеек для рисования? В такой модели вы можете продвигаться по массиву сверху вниз как по холсту, изменяя ячейки с некоторым сдвигом от центральной вертикали. А приступая к рисованию следующего звена вы сдвигаетесь не вниз, а вверх на одну строку. Например:

from itertools import cycle, chain

# Читаем данные
data = input('Количество и размеры звеньев: ')
n, *sizes = map(int, data.split())
assert n == len(sizes)

# Строим пустой холст для рисования
width = 1 + 2 * max(sizes)
height = 2 + 2 * sum(sizes) - n
canvas = [["."] * width for _ in range(height)]

# Рисуем гирлянду
bricks = cycle("#*")
middle = width // 2
row = 0
for size in sizes:
    brick = next(bricks)
    canvas[row][middle] = brick
    row += 1
    for shift in chain(range(1, size), range(size, 0, -1)):
        canvas[row][middle - shift] = brick
        canvas[row][middle + shift] = brick
        row += 1
    canvas[row][middle] = brick
    row -= 1

# Печатаем содержимое холста
print('\n'.join(map(''.join, canvas)))
→ Ссылка