Quang Huy
Quang Huy

Reputation: 59

Why does loop miss checking condition

I have a small loop for turtle to turn at 90 degrees after meeting the corner of the square. The first loop is fine but Python seem to forget to check condition at the next loop.

I start to draw at

t.setpos(-300,300)

This work fine for the first loop:

for i in range(4):
t.forward(600)
print(t.pos())
if t.pos() > (300,300):
    t.right(90)
elif t.pos() > (300,-300):
    t.right(90)
elif t.pos() > (-300, -300):
    t.right(90)
elif t.pos() > (-300,300):
    t.right(90)

But when I increase range() to 5, the code forgets to check the elif t.pos() > (-300,300): to t.right(90) but instead Python continues to draw t.forward(600) to this position:

(-300.00,900.00)

for i in range(5):
t.forward(600)
print(t.pos())
if t.pos() > (300,300):
    t.right(90)
elif t.pos() > (300,-300):
    t.right(90)
elif t.pos() > (-300, -300):
    t.right(90)
elif t.pos() > (-300,300):
    t.right(90)

Any idea why Python forgets to check a condition like this? Somehow I feel like I did wrong somewhere.

Upvotes: 1

Views: 118

Answers (2)

cdlane
cdlane

Reputation: 41872

The seemingly easy fix is this comparision is backward:

elif t.pos() > (-300, 300):

it should be:

elif t.pos() < (-300, 300):

The reason you don't see it in the range(4) case is the loop quits before ever executing it. In the range(5) case it finally executes and the inverted comparision causes the failure.

However, there are significant problems with this code which will show up as you build upon it. Although your debugging print(t.pos()) statement shows:

(300.00,300.00)
(300.00,-300.00)
(-300.00,-300.00)
(-300.00,300.00)
(-300.00,900.00)

What's really happening is:

(300.0, 300.0)
(300.00000000000006, -300.0)
(-299.99999999999994, -300.00000000000006)
(-300.00000000000006, 299.99999999999994)
(-300.00000000000017, 900.0)

The reason you don't see this, is because t.pos() doesn't return a generic tuple, it returns a specialization of tuple called Vec2D which has it's own repr() method which masks the floating point fuzziness, by only showing two digits of precision:

 def __repr__(self):
        return "(%.2f,%.2f)" % self

You might expect your clauses to fire in order, but they don't:

Position: (300.0, 300.0)

trips the second clause: elif t.pos() > (300,-300):

position: (300.00000000000006, -300.0)

trips the first clause: if t.pos() > (300,300):

position: (-299.99999999999994, -300.00000000000006)

trips the third clause: elif t.pos() > (-300, -300):

and positions:

(-300.00000000000006, 299.99999999999994)
(-300.00000000000017, 900.0)

don't trip any of the clauses. Add some print() statements to convince yourself of this.

Upvotes: 1

Quang Huy
Quang Huy

Reputation: 59

Here is my solution, it might not be efficient but it work, somehow...

if myturtle[count].xcor() > 300 and myturtle[count].heading() == 0:
   myturtle[count].right(90)
if myturtle[count].ycor() < -300 and myturtle[count].heading() == 270:
   myturtle[count].right(90)
if myturtle[count].xcor() < -300 and myturtle[count].heading() ==180:
   myturtle[count].right(90)
if myturtle[count].ycor() > 300 and myturtle[count].heading() == 90:
   myturtle[count].right(90)

Upvotes: 1

Related Questions