Kashyap Garimella
Kashyap Garimella

Reputation: 1

Python Turtle Not Responding--- No apparent issue in code

I recently developed a Turtle program to receive instructions (turn, penup, penddown, circle, etc.), and that worked fine. However, when I tried to add the ability to iterate a certain number of steps a certain number of times, the Turtle program would run through one iteration and then fail to respond for unknown reasons. I think it may be because of the '@' which is necessary for the program to iterate, but nothing has really worked.

The entry syntax for the program is:
F### -- forward for "###" length
B### -- backward for "###" length
L### -- turn to left by "###" degrees
R### -- turn to right by "###" degrees
C### -- draw a circle with the given (###) radius
U -- pick the pen up
D -- put the pen down
I# ... @ -- iterate blocks of instructions "#" number of times

C250 I3 F050 R180 C225 @ B100 C125

CODE:

import turtle


def evaluate(commands):

    """
    It's basically supposed to work
    :param commands:
    :return: None
    """
    counter = 0
    commands_length = len(commands)
    while counter < commands_length:

        # If the letter U is encountered, the turtle goes up
        # counter increases by 2 to parse for the next character
        if commands[counter] == 'U':
            turtle.up()
            print('up')
            counter += 2

        # If the letter D is encountered, the turtle goes down
        # counter increases by 2 to parse for the next character
        elif commands[counter] == 'D':
            turtle.down()
            print('down')
            counter += 2

        # If the letter F is encountered, the turtle moves forward
        # by the amount denoted by the three following numbers
        elif commands[counter] == 'F':
            turtle.forward(int(commands[counter + 1: counter + 4: 1]))
            print('forward(' + commands[counter + 1: counter + 4: 1] + ')')
            counter += 5

        # If the letter C is encountered, the turtle draws a circle
        # with radius denoted by the three following numbers
        elif commands[counter] == 'C':
            turtle.circle(int(commands[counter + 1: counter + 4: 1]))
            print('circle(' + (commands[counter + 1: counter + 4: 1]) + ')')
            counter += 5

        # if the letter B is encountered, the turtle moves backward
        # by the amount denoted by the three following numbers
        elif commands[counter] == 'B':
            turtle.backward(int(commands[counter + 1: counter + 4: 1]))
            print('backward(' + (commands[counter + 1: counter + 4: 1]) + '}')
            counter += 5

        # if the letter L is encountered, the turtle turns to its left
        # by the angle denoted by the three following numbers
        elif commands[counter] == 'L':
            turtle.left(int(commands[counter + 1: counter + 4: 1]))
            print('left(' + (commands[counter + 1: counter + 4: 1]) + ')')
            counter += 5

        # if the letter R is encountered, the turtle turns to its right
        # by the angle denoted by the three following numbers
        elif commands[counter] == 'R':
            turtle.right(int(commands[counter + 1: counter + 4: 1]))
            print('right(' + (commands[counter + 1: counter + 4: 1]) + ')')
            counter += 5

        elif commands[counter] == 'I':
            counter += 3
            loop = commands[counter: commands.index("@") + 1]
            loop_counter = 0
            loop_length = len(loop)
            while loop_counter < loop_length:
                for _ in range(counter + (commands.index("@") - 1)):

                    for x in range(loop.index('@')):
                        # If the letter U is encountered, the turtle goes up
                        # counter increases by 2 to parse for the next character
                        if loop[loop_counter] == 'U':
                            turtle.up()
                            print('up')
                            loop_counter += 2

                        # If the letter D is encountered, the turtle goes down
                        # counter increases by 2 to parse for the next character
                        elif loop[loop_counter] == 'D':
                            turtle.down()
                            print('down')
                            loop_counter += 2

                        # If the letter F is encountered, the turtle moves forward
                        # by the amount denoted by the three following numbers
                        elif loop[loop_counter] == 'F':
                            turtle.forward(int(loop[loop_counter + 1: loop_counter + 4: 1]))
                            print('forward(' + loop[loop_counter + 1: loop_counter + 4: 1] + ')')
                            loop_counter += 5

                        # If the letter C is encountered, the turtle draws a circle
                        # with radius denoted by the three following numbers
                        elif loop[loop_counter] == 'C':
                            turtle.circle(int(loop[loop_counter + 1: loop_counter + 4: 1]))
                            print('circle(' + (loop[loop_counter + 1: loop_counter + 4: 1]) + ')')
                            loop_counter += 5

                        # if the letter B is encountered, the turtle moves backward
                        # by the amount denoted by the three following numbers
                        elif loop[loop_counter] == 'B':
                            turtle.backward(int(loop[loop_counter + 1: loop_counter + 4: 1]))
                            print('backward(' + (loop[loop_counter + 1: loop_counter + 4: 1]) + '}')
                            loop_counter += 5

                        # if the letter L is encountered, the turtle turns to its left
                        # by the angle denoted by the three following numbers
                        elif loop[loop_counter] == 'L':
                            turtle.left(int(loop[loop_counter + 1: loop_counter + 4: 1]))
                            print('left(' + (loop[loop_counter + 1: loop_counter + 4: 1]) + ')')
                            loop_counter += 5

                        # if the letter R is encountered, the turtle turns to its right
                        # by the angle denoted by the three following numbers
                        elif loop[loop_counter] == 'R':
                            turtle.right(int(loop[loop_counter + 1: loop_counter + 4: 1]))
                            print('right(' + (loop[loop_counter + 1: loop_counter + 4: 1]) + ')')
                            loop_counter += 5

    turtle.done()


def main() -> None:

    user_input = input("Enter Commands:")
    evaluate(user_input.upper())
    turtle.mainloop()

if __name__ == '__main__':
    main()

Upvotes: 0

Views: 211

Answers (1)

cdlane
cdlane

Reputation: 41925

I believe your primary problem is this statement: commands.index("@")

This searches from the beginning of commands so if you have two loops, the second one will find the wrong terminator. You need to search starting from the current counter: commands.index("@", counter)

I don't believe your repetition code is correct either. And your call to turtle.done() is suspicious as it is redundant with turtle.mainloop() so I'd leave it out.

Below's a rework of just your I handler code. You can test it with the small double loop program: I4 F050 L090 @ I6 L060 F030 @

import turtle

def evaluate(commands):

    """
    It's basically supposed to work
    :param commands:
    :return: None
    """
    counter = 0
    commands_length = len(commands)
    while counter < commands_length:

        # ...

        if commands[counter] == 'I':
            repeat = int(commands[counter + 1: counter + 2: 1])
            counter += 3
            loop_end = commands.index("@", counter)
            loop = commands[counter: loop_end]
            counter = loop_end + 2
            loop_length = len(loop)
            for _ in range(repeat):
                loop_counter = 0

                while loop_counter < loop_length:   

                    # If the letter U is encountered, the turtle goes up
                    # counter increases by 2 to parse for the next character
                    if loop[loop_counter] == 'U':
                        turtle.up()
                        print('up')
                        loop_counter += 2

                    # If the letter D is encountered, the turtle goes down
                    # counter increases by 2 to parse for the next character
                    elif loop[loop_counter] == 'D':
                        turtle.down()
                        print('down')
                        loop_counter += 2

                    # If the letter F is encountered, the turtle moves forward
                    # by the amount denoted by the three following numbers
                    elif loop[loop_counter] == 'F':
                        turtle.forward(int(loop[loop_counter + 1: loop_counter + 4: 1]))
                        print('forward(' + loop[loop_counter + 1: loop_counter + 4: 1] + ')')
                        loop_counter += 5

                    # If the letter C is encountered, the turtle draws a circle
                    # with radius denoted by the three following numbers
                    elif loop[loop_counter] == 'C':
                        turtle.circle(int(loop[loop_counter + 1: loop_counter + 4: 1]))
                        print('circle(' + (loop[loop_counter + 1: loop_counter + 4: 1]) + ')')
                        loop_counter += 5

                    # if the letter B is encountered, the turtle moves backward
                    # by the amount denoted by the three following numbers
                    elif loop[loop_counter] == 'B':
                        turtle.backward(int(loop[loop_counter + 1: loop_counter + 4: 1]))
                        print('backward(' + (loop[loop_counter + 1: loop_counter + 4: 1]) + '}')
                        loop_counter += 5

                    # if the letter L is encountered, the turtle turns to its left
                    # by the angle denoted by the three following numbers
                    elif loop[loop_counter] == 'L':
                        turtle.left(int(loop[loop_counter + 1: loop_counter + 4: 1]))
                        print('left(' + (loop[loop_counter + 1: loop_counter + 4: 1]) + ')')
                        loop_counter += 5

                    # if the letter R is encountered, the turtle turns to its right
                    # by the angle denoted by the three following numbers
                    elif loop[loop_counter] == 'R':
                        turtle.right(int(loop[loop_counter + 1: loop_counter + 4: 1]))
                        print('right(' + (loop[loop_counter + 1: loop_counter + 4: 1]) + ')')
                        loop_counter += 5


def main() -> None:

    user_input = input("Enter Commands:")
    evaluate(user_input.upper())
    turtle.mainloop()

if __name__ == '__main__':
    main()

I think a nicer solution, rather than reimplement everything for the I handler, would be to design evaluate() such that the I handler can call it recursively to execute the body of the loops.

Upvotes: 1

Related Questions