【问题标题】:Sierpinski triangles using turtle and recursive function使用海龟和递归函数的谢尔宾斯基三角形
【发布时间】:2018-06-02 10:08:55
【问题描述】:

我正在尝试理解递归函数,它们看起来很复杂。到目前为止,我唯一了解的是他们需要成为一个基本案例,并且它基于归纳证明。到目前为止,程序员如何思考简单的基本情况已经超出了思考范围。仅使用一行基本案例在书中解决了示例分形。在谢尔宾斯基三角形中,我需要这么多行代码。好吧,现在我离它很近了,但仍然遥不可及。下面是适用于订单 0 和 1 的代码,但对于更高的订单,它会增加更多空间。我知道这不是 python 代码,但这是我能写的最好的。

import math, turtle

window=turtle.Screen()
window.title('Sierpinski')
window.bgcolor('lightblue')

alex=turtle.Turtle()

def sierpinski(a,t,size):
    if a==0:
        for i in range(3):
            t.forward(size)
            t.left(120)
    else:
       sierpinski(a-1,t,size/3)
       t.forward(size/3)
       sierpinski(a-1,t,size/3)
       t.forward(size/3)
       t.left(120)
       t.forward(size/3)
       sierpinski(a-1,t,size/3)
       t.forward(size/3)
       t.left(120)
       t.forward(size*2/3)
       t.left(120)

sierpinski(3,alex,200)

window.mainloop()

是的,有点长,我的思路还是不太清楚

  1. 谁能解释我的代码有什么问题?
  2. 如何使它更 Pythonic?

【问题讨论】:

    标签: python recursion turtle-graphics fractals


    【解决方案1】:

    好的,我在 video 的帮助下找到了如何做到这一点,它指示我将其分成两半而不是三分之一。

    所以代码应该是

    import math, turtle
    
    window=turtle.Screen()
    window.title('Sierpinski')
    window.bgcolor('lightblue')
    
    alex=turtle.Turtle()
    
    def sierpinski(a,t,size):
        if a==0:
            for i in range(3):
                t.forward(size)
                t.left(120)
    
        else:
           sierpinski(a-1,t,size/2)
           t.forward(size/2)
           sierpinski(a-1,t,size/2)
           t.forward(size/2)
           t.left(120)
           t.forward(size/2)
           sierpinski(a-1,t,size/2)
           t.forward(size/2)
           t.left(120)
           t.forward(size)
           t.left(120)
    
    sierpinski(3,alex,200)
    
    window.mainloop()
    

    但是代码可以更简洁吗?

    编辑

    这就够了:

    def sierpinski(a, t, size):
        half = size / 2
        if a >= 0:
            sierpinski(a-1, t, half)
            t.forward(half)
    
            sierpinski(a-1, t, half)
            t.forward(half)
            t.left(120)
            t.forward(half)
    
            sierpinski(a-1, t, half)
            t.forward(half)
            t.left(120)
            t.forward(size)
            t.left(120)
    

    这很有效,因为 ifelse 块都在绘制三角形(else 块只是为了移动光标,但仍然如此),但 else 块进行了递归调用。

    为了让它“更pythonic”,你可以把它全部放到一个类中:

    class SierpinskiTurtle(turtle.Turtle):
        def sierpinski(self, depth, size):
            half = size / 2
            if depth >= 0:
                self.sierpinski(depth-1, half)
                self.forward(half)
    
                self.sierpinski(depth-1, half)
                self.forward(half)
                self.left(120)
                self.forward(half)
    
                self.sierpinski(depth-1, half)
                self.forward(half)
                self.left(120)
                self.forward(size)
                self.left(120)
    
    alex = SierpinskiTurtle()
    
    alex.sierpinski(3, 200)
    

    【讨论】:

    • 是的,这就是问题所在。小三角形的两个长度适合较大三角形的一个长度。如果您从 if a == 0 中完全删除代码,代码会更简单,因为没有它也可以工作;)否则,我觉得它很好。
    • 太棒了,谢谢@zvone
    【解决方案2】:

    我们可以使用 stamping 而不是 drawing 使sierpinski() 函数更简单、更快:

    from turtle import Turtle, Screen
    
    CURSOR_SIZE = 20
    
    def sierpinski(depth, turtle, size):
    
        turtle.shapesize(size / CURSOR_SIZE)
        turtle.stamp()
    
        if depth < 1:
            return
    
        half = size / 2
        circumradius = half * 3 ** 0.5 / 3
    
        for _ in range(3):
            turtle.forward(circumradius)  # to
            sierpinski(depth - 1, turtle, half)
            turtle.backward(circumradius)  # and fro
            turtle.left(120)
    
    window = Screen()
    window.mode('logo')  # make 0 degrees straight up
    window.title('Sierpinski')
    window.bgcolor('lightblue')
    
    alex = Turtle('triangle')
    alex.fillcolor(window.bgcolor())
    alex.penup()
    
    sierpinski(3, alex, 300)
    
    alex.hideturtle()
    window.mainloop()
    

    这还具有在屏幕上绘制三角形而不是偏向一侧的优点。通过让光标围绕三角形的半径以圆形方式移动而不是围绕中心来回移动,可以进一步优化绘图。

    【讨论】:

    • 为了一笑而过,将alex = Turtle('triangle') 改为alex = Turtle('turtle') 然后尝试一些其他可能的形状,例如squarecirclearrow 等。
    • 引入了很多我不知道的函数,比如window.mode()。非常感谢@cdlane
    猜你喜欢
    • 2014-11-04
    • 1970-01-01
    • 1970-01-01
    • 2015-10-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多