Reputation: 2831
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!
Upvotes: 0
Views: 1364
Reputation: 104722
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.
Upvotes: 1
Reputation: 4418
According to the Wikipedia page, the symbol '[' means to save the current state (angle and positions). The matching ']' means to restore the previously saved position. Because the '[' and ']' can be nested, a stack is needed.
from collections import deque
...
stack = deque()
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)) ### New statement
elif (chtr == ']'):
angle, pos = stack.pop() ### New statement
tess.setheading(angle)
tess.penup()
tess.goto(pos[0], pos[1])
tess.pendown()
. . .
Upvotes: 1