Не понимаю как решить задачу "Гирлянда"
Сделал один элемент, но как его соединять с другими - не понимаю, прошу помощи
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 шт):
Развивая исходную модель
В этой части я использую исходный код как черный ящик. Код вполне рабочий. Запишем его в виде функции, заменив 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()
Теперь у нас есть возможность связать звенья между собой. Последовательность действий может быть следующей:
- Построить верхнее и нижнее звено.
- Заменить центр предпоследней строки верхнего звена центром первой строки нижнего.
- Заменить центр второй строки нижнего звена центром последней строки верхнего.
- Удалить последнюю строку верхнего и первую строку нижнего звеньев.
- Выровнять звенья по ширине.
- Состыковать звенья.
Одна из возможных реализаций:
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)))
