pythonpython-3.xfractalsl-systems

Strange L-system in python turtle graphics


I tried to use the turtles module in Python 3 to recreate the fractal found here: https://en.wikipedia.org/wiki/L-system#Example_7:_Fractal_plant but whenever I try it it gives me a very strange result...

Here's my code:

import turtle
wn = turtle.Screen()
wn.bgcolor("white")
wn.screensize(10000, 10000)

tess = turtle.Turtle()
tess.color("lightgreen")
tess.pensize(1)
tess.speed(0)
tess.degrees()

inst = 'X'
steps = 3

for counter in range(steps):
    _inst = ''
    for chtr in inst:
        if chtr == 'X':
            _inst += 'F−[[X]+X]+F[+FX]−X'
        elif chtr == 'F':
            _inst += 'FF'
        else:
            _inst += chtr
    inst = _inst
    print(inst)


for chtr in inst:
    if (chtr == 'F'):
        tess.forward(25)
    elif (chtr == '+'):
        tess.right(25)
    elif (chtr == '-'):
        tess.left(25)
    elif (chtr == '['):
        angle = tess.heading()
        pos = [tess.xcor(), tess.ycor()]
    elif (chtr == ']'):
        tess.setheading(angle)
        tess.penup()
        tess.goto(pos[0], pos[1])
        tess.pendown()
wn.exitonclick()

I triple-checked everything and I seem to have no bugs - but it still does not work. What am I doing terribly wrong?

Thanks in advance for any help!


Solution

  • There are two issues in your code.

    The first is that your code doesn't handle nested brackets properly. The inner opening bracket saves its state over the top of the previous state saved when the outer opening bracket was seen. This won't matter for immediately nested brackets like [[X]+X] (since both have the same starting state), but once you get more complicated nesting (as you will after a few substitution loops), the issue starts to make things go wrong.

    To solve this you probably want to store your saved state values to a stack (a list can do). Push the values you want to save, and pop them back off when you're ready to restore them.

    stack = [] # use a list for the stack
    for chtr in inst:
        if (chtr == 'F'):
            tess.forward(25)
        elif (chtr == '+'):
            tess.right(25)
        elif (chtr == '-'):
            tess.left(25)
        elif (chtr == '['):
            angle = tess.heading()
            pos = [tess.xcor(), tess.ycor()]
            stack.append((angle, pos)) # push state to save
        elif (chtr == ']'):
            angle, pos = stack.pop()  # pop state to restore
            tess.setheading(angle)
            tess.penup()
            tess.goto(pos[0], pos[1])
            tess.pendown()
    

    The second issue is more trivial. Your parser looks for the "minus" character (-). But your pattern generating code uses a different, slightly longer kind of dash (). Change one of them to match the other (it doesn't really matter which one) and your code will work as expected.