使用 L 系统和 Python 海龟生成树
Tree generation using L-systems and Python turtle
我正在尝试使用 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)
我在海龟身上发现了一个奇怪的纹理图案 window:
我怎样才能得到想要的结果?
您的 +=
操作将生产规则的应用附加到字符串,但想法是 将 每次出现的 "F"
字符替换为生产规则的结果。
您可以使用 string#replace
, which replaces every occurrence of a substring. You used this before your edit, but didn't assign the return value of the function back to the original sentence
variable (replace
doesn't work in-place 执行此操作,字符串是不可变的)。
无论哪种方式,额外的内部循环都是不必要的。
另一个重点:生产规则是递归的,因此单个 location
变量不足以存储 "remember" 可能已执行的推送序列。
为了详细说明,这是在多次迭代中应用生产规则后的 sentence
变量的摘录:
...[-FF+[+F-F-F]-[-F+F+F]+...
很明显,在遇到 ]
之前,这有两个连续的 [
操作。这种嵌套可以任意深。 stack 数据结构是跟踪嵌套、递归位置的最佳方式(location
只能跟踪最后一个,当两个推送操作连续发生时,状态将被破坏)。
每当遇到 [
操作时,将堆栈上的位置压入(在 Python 中表示为仅使用 append
(用于压入)和 pop
没有任何参数来删除列表的后面)。每当遇到 ]
操作时,弹出堆栈并将海龟的位置设置为该位置。
次要的一点是,将硬编码值保留在代码之外是个好主意;将所有 settings/config 变量分组在块的顶部。如果您使用的是函数,请设置这些参数。
这是一个工作版本:
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()
我正在尝试使用 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)
我在海龟身上发现了一个奇怪的纹理图案 window:
我怎样才能得到想要的结果?
您的 +=
操作将生产规则的应用附加到字符串,但想法是 将 每次出现的 "F"
字符替换为生产规则的结果。
您可以使用 string#replace
, which replaces every occurrence of a substring. You used this before your edit, but didn't assign the return value of the function back to the original sentence
variable (replace
doesn't work in-place 执行此操作,字符串是不可变的)。
无论哪种方式,额外的内部循环都是不必要的。
另一个重点:生产规则是递归的,因此单个 location
变量不足以存储 "remember" 可能已执行的推送序列。
为了详细说明,这是在多次迭代中应用生产规则后的 sentence
变量的摘录:
...[-FF+[+F-F-F]-[-F+F+F]+...
很明显,在遇到 ]
之前,这有两个连续的 [
操作。这种嵌套可以任意深。 stack 数据结构是跟踪嵌套、递归位置的最佳方式(location
只能跟踪最后一个,当两个推送操作连续发生时,状态将被破坏)。
每当遇到 [
操作时,将堆栈上的位置压入(在 Python 中表示为仅使用 append
(用于压入)和 pop
没有任何参数来删除列表的后面)。每当遇到 ]
操作时,弹出堆栈并将海龟的位置设置为该位置。
次要的一点是,将硬编码值保留在代码之外是个好主意;将所有 settings/config 变量分组在块的顶部。如果您使用的是函数,请设置这些参数。
这是一个工作版本:
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()