使用海龟图形实现Sierpinski三角形递归

8
我正在尝试使用Python和Turtle绘制Sierpinski树的程序。我的想法如下:
import turtle
def draw_sierpinski(length,depth):
    window = turtle.Screen()
    t = turtle.Turtle()
    if depth==0:
        for i in range(0,3):
            t.fd(length)
            t.left(120)
    else:
        draw_sierpinski(length/2,depth-1)
        t.fd(length/2)
        draw_sierpinski(length/2,depth-1)
        t.bk(length/2)
        t.left(60)
        t.fd(length/2)
        t.right(60)
        draw_sierpinski(length/2,depth-1)
    window.exitonclick()


draw_sierpinski(500,1)

程序没有执行else语句后面的第二行,我不知道为什么。有人能帮帮我吗?
9个回答

11

我认为你不应该在函数内创建turtle或window对象。因为如果你最初使用深度1调用draw_sierpinski,则会调用四次,然后你将创建四个单独的窗口和四个单独的海龟,每个海龟只画一个三角形。相反,我认为你应该只有一个窗口和一个海龟。

import turtle
def draw_sierpinski(length,depth):
    if depth==0:
        for i in range(0,3):
            t.fd(length)
            t.left(120)
    else:
        draw_sierpinski(length/2,depth-1)
        t.fd(length/2)
        draw_sierpinski(length/2,depth-1)
        t.bk(length/2)
        t.left(60)
        t.fd(length/2)
        t.right(60)
        draw_sierpinski(length/2,depth-1)


window = turtle.Screen()
t = turtle.Turtle()
draw_sierpinski(500,1)
window.exitonclick()

结果:

enter image description here


这些深度为1的三角形看起来非常不错,但是当我们调用draw_sierpinski(100,2)时会怎样呢?

enter image description here

噢,不太好。这是因为函数应该绘制形状,然后将海龟返回到其原始起始位置和角度。但正如从深度为1的图像可以看出的那样,海龟没有返回到其起始位置;它停在了左斜坡的一半。你需要一些额外的逻辑来将它送回家。

import turtle
def draw_sierpinski(length,depth):
    if depth==0:
        for i in range(0,3):
            t.fd(length)
            t.left(120)
    else:
        draw_sierpinski(length/2,depth-1)
        t.fd(length/2)
        draw_sierpinski(length/2,depth-1)
        t.bk(length/2)
        t.left(60)
        t.fd(length/2)
        t.right(60)
        draw_sierpinski(length/2,depth-1)
        t.left(60)
        t.bk(length/2)
        t.right(60)

window = turtle.Screen()
t = turtle.Turtle()
draw_sierpinski(100,2)
window.exitonclick()

结果:

在此输入图片描述


1
谢谢。我对解决方案有点困惑...似乎函数只是使用了t,但我们没有将其作为参数传递给函数。这不奇怪吗? - AlexConfused
在这种情况下,t 实际上是一个全局变量。它应该对文件中创建的任何函数都可见。 - Kevin

3
# PEP8 Verified
'''
The Sierpinski function relies heavily on the getMid function. getMid takes
as arguments two endpoints and returns the point halfway between them. In
addition, this program has a function that draws a filled triangle using
the begin_fill and end_fill turtle methods.
'''


import turtle


def drawTriangle(points, color, myTurtle):
    myTurtle.fillcolor(color)
    myTurtle.up()
    myTurtle.goto(points[0][0], points[0][1])
    myTurtle.down()
    myTurtle.begin_fill()
    myTurtle.goto(points[1][0], points[1][1])
    myTurtle.goto(points[2][0], points[2][1])
    myTurtle.goto(points[0][0], points[0][1])
    myTurtle.end_fill()


def getMid(p1, p2):
    return ((p1[0] + p2[0]) / 2, (p1[1] + p2[1]) / 2)


def sierpinski(points, degree, myTurtle):
    colormap = ['blue', 'red', 'green', 'white', 'yellow', 'violet', 'orange']
    drawTriangle(points, colormap[degree], myTurtle)
    if degree > 0:
        sierpinski([points[0],
                    getMid(points[0], points[1]),
                    getMid(points[0], points[2])],
                   degree-1, myTurtle)
        sierpinski([points[1],
                    getMid(points[0], points[1]),
                    getMid(points[1], points[2])],
                   degree-1, myTurtle)
        sierpinski([points[2],
                    getMid(points[2], points[1]),
                    getMid(points[0], points[2])],
                   degree-1, myTurtle)


def main():
    myTurtle = turtle.Turtle()
    myWin = turtle.Screen()
    myPoints = [[-100, -50], [0, 100], [100, -50]]
    sierpinski(myPoints, 3, myTurtle)
    myWin.exitonclick()

main()

1

给你。

import turtle

def sier(side, level):
    if level == 1:
        for i in range(3):
            turtle.fd(side)
            turtle.left(120)
    else:
        sier(side/2, level-1)
        turtle.fd(side/2)
        sier(side/2, level-1)
        turtle.bk(side/2)
        turtle.left(60)
        turtle.fd(side/2)
        turtle.right(60)
        sier(side/2, level-1)
        turtle.left(60)
        turtle.bk(side/2)
        turtle.right(60)
def main():
    sier(200, 4)

if __name__ == '__main__':
    main()
    turtle.mainloop()

1
作为建议,这是我的解决方案。非常感谢任何评论,因为似乎它仍然不是最有效的算法。
import turtle

def sier(tur, order, size):
    """ Draw Sierpinski triangle """
    if order == 0:
        for _ in range(3):
            tur.forward(size)
            tur.left(120)
    else:
        step = size / 2
        for t1, m1, t2, m2 in [(0, step, 0, 0),
                               (120, step, -120, 0),
                               (-60, step, 60, -(step))]:
            sier(tur, order - 1, step)
            tur.left(t1)
            tur.forward(m1)
            tur.left(t2)
            tur.forward(m2)


if __name__ == '__main__':
    odr = int(input("Enter the order: "))
    sz = int(input("Enter the size: "))

    root = turtle.Screen()
    root.bgcolor("lightgreen")

    alex = turtle.Turtle()
    alex.color('blue')
    alex.speed(100)

    sier(alex, odr, sz)

    root.mainloop()

1
from turtle import *
import turtle
t = turtle.Turtle()
Window = turtle.Screen()

Window.bgcolor('white')

turtle.color('white')
goto(-200, -200)
def serp_tri(side, level):
    if level == 1:
        for i in range(3):
            turtle.color('black')
            turtle.ht()
            turtle.fd(side)
            turtle.left(120)
            turtle.speed(100000)

else:
    turtle.ht()
    serp_tri(side/2, level-1)
    turtle.fd(side/2)
    serp_tri(side/2, level-1)
    turtle.bk(side/2)
    turtle.left(60)
    turtle.fd(side/2)
    turtle.right(60)
    serp_tri(side/2, level-1)
    turtle.left(60)
    turtle.bk(side/2)
    turtle.right(60)
    turtle.speed(100000)

def main():
    serp_tri(400, 8)

if __name__ == '__main__':
    main()
    turtle.mainloop()

我看了一个类似的程序,并使用了其中一些内容来编写这个程序。这将给你最大的三角形。希望这能帮到你!


1

这是生成谢尔宾斯基三角形的最佳代码

def sierpinski(a, n):
if n == 0:
    t.begin_fill()
    for i in range(3):
        t.fd(a)
        t.lt(120)
    t.end_fill()
    return
sierpinski(a / 2, n - 1)
t.pu()
t.fd(a / 2)
t.pd()
sierpinski(a / 2, n - 1)
t.pu()
t.lt(120)
t.fd(a / 2)
t.rt(120)
t.pd()
sierpinski(a / 2, n - 1)
#
# We should return home! This is important!
#
t.pu()
t.lt(60)
t.bk(a / 2)
t.rt(60)
t.pd()

1

从Navneet Sinha开始,我建议这样做:

def sierpinski(t,order,size):
try:
    order=int(order)
    size=float(size)
    if order==0:
        for i in range(0,3):
            t.pendown()             
            t.forward(size)         
            t.left(120)
            t.penup()               
    else:
        for (angle,move) in ([0,size],[60,-size],[-60,-size]):
            sierpinski(t,order-1,size/2)       
            t.right(angle)                              
            t.forward(move/2)                           
            t.left(angle)
except ValueError:
    None

def test_turtle():
    import turtle

    screen=turtle.Canvas()
    tess=turtle.Turtle()
    tess.shape("arrow")
    tess.shapesize(0.2)
    tess.speed(0)

    ords=input("define the order of the fractal: ")
    sz=input("define the size of the segment: ")

    tess.penup()
    tess.backward(float(sz)/2)
    tess.right(90)
    tess.forward(float(sz)/3)
    tess.left(90)
    tess.pendown()

    sierpinski(tess,ords,sz)

    screen.mainloop()

test_turtle()    

0

代码非常简单:

def sierpinski(size:int,depth:int,up:bool = True):
    if depth==0:
        t.forward(size)
        return
    size = size/2
    depth = depth-1
    left = lambda deg:t.left(deg)
    right = lambda deg:t.right(deg)
    if not up:
        k = left
        left = right
        right = k
        del k
    left(60)
    sierpinski(size,depth,not up)
    right(60)
    sierpinski(size,depth,up)
    right(60)
    sierpinski(size,depth,not up)
    left(60)

-1
我发现了一种递归的方法来绘制我认为你期望的图形。我的目标实际上是使用成千上万个点来绘制它,但在经过一番思考后,我选择了这个解决方案:
import turtle
def sierpinski(length, level):
    if level == 0:
        for i in range(3):
            turtle.forward(length)
            turtle.left(120)
    else:
        sierpinski(length/2, level-1)
        turtle.forward(length/2)
        sierpinski(length/2, level-1)
        turtle.backward(length/2)
        turtle.left(60)
        turtle.forward(length/2)
        turtle.right(60)
        sierpinski(length/2, level-1)
        turtle.left(60)
        turtle.backward(length/2)
        turtle.right(60)
turtle.speed(0)
sierpinski(200, 4)

你的回答可以通过添加更多支持信息来改进。请[编辑]以添加进一步的细节,例如引用或文档,以便他人可以确认你的答案是正确的。您可以在帮助中心中找到有关如何编写良好答案的更多信息。 - Ethan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接