首页 > 解决方案 > Python海龟图形反复“越界”

问题描述

我试图让Python 中的Turtle随机绘制用户指定的三角形数量。我在将乌龟保持在我定义的范围内时遇到了一些麻烦。例如,乌龟的边界是

border = 300

def drawBorder(border):
    t.pensize(3)
    x = 0
    while x <= 4:
        t.pendown()
        t.forward(border)
        t.left(90)
        t.penup()
        x = x + 1

它绘制了一个 300x300 的正方形。

以下函数应该 - 当 X 或 Y 坐标 + 它要绘制的三角形的长度在边界之外时 - 对于前两次迭代,尝试将海龟旋转 180 度(面向相反方向)并将其向前移动两次它最初要向前移动的距离。如果这不能将海龟带到边界范围内,海龟应该返回到边界的中间 - 在这种情况下,即 (150,150)。这并不总是发生。由于生成的“随机”性质,大多数时候海龟最终都在边界之外,尽管有时它会在边界内绘制所有三角形。

 if t.xcor() + lengthOfTriangle > border or t.xcor() + lengthOfTriangle < 0 or \
    t.ycor() + lengthOfTriangle > border or t.ycor() + lengthOfTriangle < 0:
x = 0
while x < 2:
    t.penup()
    t.left(180)
    t.forward(2 * lengthOfTriangle)
    t.pendown()
    x = x + 1
else:
    t.penup()
    if t.xcor() > border:
        t.seth(180)
    if t.xcor() < border:
        t.seth(0)
    t.forward(t.xcor() - (t.xcor() + border/2))
    if t.ycor() > border:
        t.seth(90)
    if t.ycor() < border:
        t.seth(270)
    t.forward(t.ycor() - (t.ycor() + border/2))

print("Turtle was going to be out of bounds. Xcor would be: ", t.xcor() + lengthOfTriangle,
      ". And Ycor would be: ", t.ycor() + lengthOfTriangle)
return drawFigureRec(numTriangles, lengthOfTriangle=random.randint(1, 20),
                     distanceTriangle=random.randint(1, 40),
                     angleTriangle=random.randint(0, 360), sum=sum)

如果您需要函数变量的上下文,我在这里链接了一个 pastebin 。

这是显示问题的图片。乌龟应该保持在“边界”(红色方块)内,但会在控制台输出中显示出来

标签: pythonpython-3.xrecursionturtle-graphics

解决方案


您的代码有几个问题。例如,这个边界检查逻辑完全忽略了海龟的当前航向:

   if t.xcor() + lengthOfTriangle > border or ... t.ycor() + lengthOfTriangle > border or ...

即它总是假设+45 度所以不能工作。您可以做三角函数,或者简单地将海龟移动到新位置并测试它是否超出范围。如果超出范围,您可以将其移回,调整并重试。该turtle.undo()方法在这里很有帮助。

您的drawFigure*()函数有时会显式返回值,有时则不会。一旦函数显式返回一个值,它应该从所有退出点显式返回一个,而不是 None有时隐式返回。

您的方形边框有五个边:

   x = 0
   while x <= 4:

由于最后一个透支了第一个,这在视觉上并不明显。

让我们尝试一种更简单的迭代方法turtle.circle()来绘制三角形,但在确定它是否在边界内时将每个三角形视为一个圆。我们还将使我们的绘图居中,而不是仅使用右上象限和正数:

from turtle import Screen, Turtle
from random import randint

NUMBER_TRIANGLES = 80
PEN_SIZE = 3
BORDER = 300

def drawBorder(border):
    turtle.pensize(PEN_SIZE)

    turtle.penup()
    turtle.goto(-border/2, -border/2)
    turtle.pendown()

    for _ in range(4):
        turtle.forward(border)
        turtle.left(90)

    turtle.penup()
    turtle.home()

def drawFigure(numTriangles):
    if not 0 < numTriangles < 500:
        exit("Number of triangles is out of range!")

    for _ in range(numTriangles):

        radius = randint(3, 20)
        distance = randint(2, 60)

        turtle.forward(distance)

        while not(radius - BORDER/2 < turtle.xcor() < BORDER/2 - radius and radius - BORDER/2 < turtle.ycor() < BORDER/2 - radius):
            turtle.undo()  # undo last forward()
            turtle.left(37)  # rotate and try again (relative prime angle)
            distance += 1  # increase distance slightly on failure
            turtle.forward(distance)

        angle = randint(1, 360)
        turtle.setheading(angle)

        turtle.right(90)  # turtle represents center so need to adjust
        turtle.forward(radius)  # as turtle.circle() doesn't think that way
        turtle.left(90)

        turtle.pendown()
        turtle.circle(radius, steps=3)
        turtle.penup()

        turtle.left(90)  # undo adjustment to move turtle back to center
        turtle.forward(radius)
        turtle.right(90)

screen = Screen()
screen.tracer(False)

turtle = Turtle()
turtle.speed('fastest')

drawBorder(BORDER)
drawFigure(NUMBER_TRIANGLES)

turtle.hideturtle()

screen.tracer(True)
screen.mainloop()

在此处输入图像描述

我不会包含递归等价物,因为这确实不是递归问题。您可以根据您的任务要求将其强制为一个。


推荐阅读