Генерация дерева с использованием L-систем и черепахи Python

Я пытаюсь создать простое дерево, используя L-систему. Однако, когда я запускаю код, который у меня есть:

import turtle


def generate(length):
    sentence = "F"
    for j in range(1, length):
        for i in sentence:
            if i == "F":
                sentence += "FF+[+F-F-F]-[-F+F+F]"

        print(sentence)


    gen = turtle.Turtle()
    window = turtle.Screen()
    gen.left(90)

    for k in sentence:
        if k == "F":
            gen.forward(10)
        elif k == "+":
            gen.right(10)
        elif k == "-":
            gen.left(10)
        elif k == "[":
            location = gen.position()
        elif k == "]":
            gen.setposition(location)

Я получаю странный рисунок зерна в окне черепахи:

черепашье окно

Как я могу добиться желаемого результата?


person Newbie    schedule 22.01.2020    source источник
comment
››› generate(3), 3 — это длина строки или сложность дерева   -  person Newbie    schedule 22.01.2020
comment
Хорошо, когда я запускаю это, я не вижу твоего образа. Я получаю спам F на консоли, и окно немедленно закрывается. Можете ли вы опубликовать точный код, который вы используете для создания изображения, которое вы разместили? Я могу с уверенностью сказать, что sentence.replace не делает того, что вы думаете, - он заменяет каждое вхождение первого параметра вторым, а не делает это на месте. Кроме того, я не уверен, чего вы пытаетесь достичь.   -  person ggorlen    schedule 22.01.2020
comment
Я сделал небольшую ошибку в выражении if i == F, замените предложение. замените(i, FF+[+FFF]-[-F+F+F]) предложением += FF+[+FFF]-[-F+ Ж+Ж]   -  person Newbie    schedule 22.01.2020
comment
Я тоже не думаю, что ты этого хочешь. Пожалуйста, отредактируйте свой пост, чтобы предоставить эти обновления.   -  person ggorlen    schedule 22.01.2020
comment
Хорошо, я отредактировал его. Как мне улучшить свой код, чтобы получить желаемый результат?   -  person Newbie    schedule 22.01.2020


Ответы (1)


Ваша операция += добавляет к строке применение производственного правила, но идея состоит в том, чтобы заменять каждое вхождение символа "F" результатом производственного правила.

Вы можете сделать это с помощью string#replace, который заменяет каждое вхождение подстрока. Вы использовали это перед редактированием, но не присвоили возвращаемое значение функции обратно исходной переменной sentence (replace не работает на месте, а строки неизменяемы).

В любом случае дополнительный внутренний цикл не нужен.

Еще один важный момент: производственное правило является рекурсивным, поэтому одной переменной location недостаточно места для «запоминания» последовательности толчков, которые могли быть выполнены.

Чтобы уточнить, вот выдержка из вашей переменной sentence после применения производственного правила на нескольких итерациях:

...[-FF+[+F-F-F]-[-F+F+F]+...

Понятно, что здесь есть две последовательные операции [, прежде чем встретится ]. Это вложение может расти сколь угодно глубоко. Структура данных стека — лучший способ отслеживать вложенные рекурсивные позиции. (location может отслеживать только последнее, и состояние будет повреждено, если две операции push будут выполняться последовательно).

Всякий раз, когда встречается операция [, помещайте позицию в стек (представленную в Python как список, который использует только append (для отправки) и pop без каких-либо аргументов, чтобы удалить конец списка). Всякий раз, когда встречается операция ], извлекайте стек и устанавливайте положение черепахи в это место.

В качестве второстепенного момента рекомендуется убрать жестко закодированные значения из кода; сгруппируйте все ваши настройки / конфигурации в верхней части блока. Если вы используете функцию, задайте эти параметры.

Вот рабочая версия:

import turtle

generations = 3
size = 10
rule = ("F", "FF+[+F-F-F]-[-F+F+F]")
sentence = "F"
positions = []
gen = turtle.Turtle()
gen.speed(10)
gen.left(90)

for i in range(generations):
    sentence = sentence.replace(*rule)

for op in sentence:
    if op == "F":
        gen.forward(size)
    elif op == "+":
        gen.right(size)
    elif op == "-":
        gen.left(size)
    elif op == "[":
        positions.append(gen.position())
    elif op == "]":
        gen.setposition(positions.pop())

turtle.exitonclick()
person ggorlen    schedule 22.01.2020