【问题标题】:Infinite loop with two randomly walking turtles带有两只随机行走的海龟的无限循环
【发布时间】:2026-01-12 06:40:01
【问题描述】:

在我掌握了我之前的程序的窍门后(乌龟随机行走并从墙上反弹,直到撞到墙壁 4 次),我尝试在指南中做以下练习,它要求两只乌龟的起始位置是随机的它们在屏幕上走来走去,从墙壁上反弹,直到它们撞到彼此——没有计数器变量来决定它们什么时候应该停下来。我设法写了整个事情,除了它们碰撞和停止的部分:我想出了一个布尔函数,如果海龟的 X 和 Y 坐标相同,则返回 True,如果不是,则返回 False工作,但他们继续走,终止程序的唯一方法是强制解释器退出。我做错了什么?

import turtle
import random

def setStart(t):
    tx = random.randrange(-300,300,100)
    ty = random.randrange(-300,300,100)

    t.penup()
    t.goto(tx,ty)
    t.pendown()

def throwCoin(t):
    coin = random.randrange(0,2)

    if coin == 0:
        t.left(90)
    else:
        t.right(90)

def isInScreen(w,t):
    leftBound = w.window_width() / -2
    rightBound = w.window_width() / 2
    bottomBound = w.window_height() / -2
    topBound = w.window_height() / 2

    turtlex = t.xcor()
    turtley = t.ycor()

    stillIn = True

    if turtlex < leftBound or turtlex > rightBound or turtley < bottomBound or turtley > topBound:
        stillIn = False

    return stillIn

def collide(t,u):
    if t.xcor() == u.xcor() and t.ycor() == u.ycor():
        return True
    return False

def randomWalk(t,w):
        if not isInScreen(w,t):
            t.left(180)
        else:
            throwCoin(t)
        t.forward(100)

def doubleRandom(t,u,w):
    while not collide(t,u):
        randomWalk(t,w)
                if collide(t,u):
                   break
        randomWalk(u,w)

wn = turtle.Screen()
wn.bgcolor('lightcyan')

steklovata = turtle.Turtle()
steklovata.color('darkslategray')
steklovata.shape('turtle')
setStart(steklovata)

catshower = turtle.Turtle()
catshower.color('orangered')
catshower.shape('turtle')
setStart(catshower)

doubleRandom(steklovata,catshower,wn)

wn.exitonclick()

编辑: 为了测试错误是在 collide(t,u) 函数中还是在调用它的 while 循环中,我编写了另一个函数,将两个海龟发送到同一个位置并如果collide(t,u) 返回True,则打印出一些文本(如果有人想知道,这是一个内部笑话,就像我想出的每个翻转名称一样)。当我运行它时,文本 DID 打印出来,这告诉我碰撞检测工作正常......但循环不知何故并没有告诉 Python 海龟在碰撞时应该停止。这是函数:

def raul(t,u,w):
    t.goto(1,1)
    u.goto(1,1)
    if collide(t,u):
        t.write('RAUL SUNTASIG')

这是否让你们知道它为什么不起作用?

【问题讨论】:

  • 我还没有看过代码,但问题是它们在碰撞检查发生之前就停止了相交吗?比如(0, 0)的一只乌龟去(1, 0),另一只乌龟从(1, 0)(0, 0),那么碰撞逻辑认为它们没有撞到对方?
  • 我认为按照 Python 的逻辑,一个是从 0,10,0,然后另一个从 1,00,0,所以我认为坐标应该是一样,但是第一只乌龟又走了,然后另一只也走了,而不是都停在原地。
  • 只有当他们开始时彼此相距偶数步时才会发生这种情况。如果它们从(0, 0)(0, 1) 开始,碰撞检测器将永远不会注意到它们何时发生碰撞。
  • 您的代码有时会停止吗?如果有,大约多久一次?一半时间?少一点?
  • 发现问题。查看我的编辑。

标签: python python-3.x turtle-graphics


【解决方案1】:

编辑:完全改变了答案。

我在collide 例程中添加了打印语句并得到了这个:

-300.0 -200.0 -100.0 -100.0
-300.0 -100.0 -100.0 -100.0
-300.0 -100.0 -200.0 -100.0
-300.0 -100.0 -200.0 -100.0
-300.0 1.13686837722e-13 -200.0 -100.0
-300.0 1.13686837722e-13 -200.0 1.27897692437e-13
-300.0 1.13686837722e-13 -200.0 1.27897692437e-13
-200.0 4.02080297728e-14 -200.0 1.27897692437e-13
-200.0 4.02080297728e-14 -200.0 100.0
-200.0 4.02080297728e-14 -200.0 100.0

以下是您解决问题的方法:

def collide(t,u):
    if abs(t.xcor() - u.xcor()) < 1 and abs(t.ycor() - u.ycor()) < 1:
        return True
    return False

哦,您应该在每个randomWalk() 之后检查collide(),而不仅仅是第一个。

【讨论】:

  • 三面硬币? :)
  • @jwygralak67:10 面。 :)
【解决方案2】:

使用更大的海龟。

如果您目前仅在两只海龟的 x 和 y 坐标完全匹配时才称其为碰撞,那么这将是一个非常难以满足的条件。

如果你想象你的海龟的半径是 5 个点,那么任何时候两个海龟的中心点之间的距离小于 10,它们就会发生碰撞。

【讨论】:

  • 他们一次只移动 100 步,而且他们的起始坐标总是 100 的倍数,这使得他们相遇的几率更大(事实上我见过他们相遇几次)。如果我将条件更改为(abs(t.xcor()-u.xcor) &lt; 10 等等,我可能会尝试会发生什么。
  • 我改变了它,使它们在每次距离小于 10 时发生碰撞,并且它们走了 100 步然后停下来,即使它们彼此相距很远。每次我跑它时,它们每转一圈后就停下来。您知道为什么会发生这种情况吗?
  • 您还必须检查 y 坐标。你真的应该做类似 sqrt(xx + yy) 的事情,其中​​ x 是 x 坐标和 y 之间的差异 - 两只海龟的 y 坐标之间的差异。
【解决方案3】:

您的代码仅在两个海龟移动后才检查碰撞。大约有一半的时间,海龟会从彼此相距奇数步开始,在这种情况下,当碰撞检测运行时,它们总是会彼此相距奇数步。即使其中一个移动到另一个位置,另一个也会在您检查碰撞之前离开。要解决此问题,请在移动之间运行额外的碰撞检查:

while not collide(t, u):
    randomWalk(t, w)
    if collide(t, u):
        break
    randomWalk(u, w)

还有一件事需要考虑;海龟总是右转,或者当他们撞到墙上时 180 秒。这引入了与上述类似的奇偶性问题,如果海龟无法进行右转序列或必须等到它们进行正确的墙壁碰撞以将它们指向正确的方向,这可能会阻止或延迟碰撞。你可以通过让海龟从所有 4 个方向随机选择来解决这个问题:

def throwCoin(t):
    # 4-sided Ruritanian nickel
    t.left(90*random.randrange(4))

【讨论】:

  • 我只试了一次,它成功了,所以我又试了 2 次,看看它是否每次都有效,但没有。我认为不同之处在于第一次海龟都没有撞到墙,但第二次他们撞到了墙,但我不明白这会如何影响碰撞检测,我很惊讶它不起作用,因为你的代码似乎很有意义。
  • @reggaelizard:发布了另一个问题。我不确定它是否真的可以防止碰撞,但修复它可能会使碰撞发生得更快,如果您等待的时间不够长才能看到结果,这可能很重要。
  • 仍然无法正常工作,碰撞已经发生了好几次,但它们并没有停止。 (不过,不错的 Ruritanian 镍币,很适合我的乌龟,它以俄罗斯男孩乐队的名字命名)。