'How do I get all the turtles to respond to a click using python turtle onclick?

I am trying to make a game where you have to collect the turtle so when you click a turtle it moves into a box. The problem with this is that when you click one of the turtles a turtle moves that you didn't click. I think that it is because I created one variable to control multiple turtles, but I don't know how to fix this. Here is my code: (btw, I was having trouble adding in the code using the 'code' button on stack overflow)

import turtle

import random

s = turtle. Screen()

s.bgcolor("lightgreen")

print("Welcome! this pond is infested with turtles! Can you catch all the turtles?")

for x in range(0,5):

  t = turtle.Turtle()

  c = 'yellow', 'gold', 'orange', 'red', 'magenta', 'navy', 'blue', 'purple', 'cyan', 'brown', 'black', 'gray', 'white'

  t.color(random.choice(c))

  t.shape("turtle")

  t.penup()

  t.hideturtle()

  r = random.randint(-75,75)

  r2 = random.randint(-75,75)

  r3 = random.randint(1,10)

  t.goto(r,r2)

  t.showturtle()

  def fxn (x, y):

    t.goto(95,-122)

    print("yes")

  t.onclick(fxn)


Solution 1:[1]

We can patch your code using partial from functools. This allows us to pass "which turtle" through to your onclick() function:

from random import choice, randint
from functools import partial
from turtle import Screen, Turtle

COLORS = ['yellow', 'gold', 'orange', 'red', 'magenta', 'navy', 'blue', 'purple', 'cyan', 'brown', 'black', 'gray', 'white']

def fxn(t, x, y):
    t.goto(95, -122)

    print("yes")

screen = Screen()
screen.bgcolor('lightgreen')

print("Welcome! This pond is infested with turtles! Can you catch all the turtles?")

for x in range(5):
    t = Turtle()
    t.hideturtle()
    t.shape('turtle')
    t.color(choice(COLORS))
    t.penup()

    x = randint(-75, 75)
    y = randint(-75, 75)

    t.goto(x, y)
    t.onclick(partial(fxn, t))
    t.showturtle()

screen.mainloop()

The changes to accommodate partial() are minimal, most of the changes above were for style. I do agree with @Nathcat that using an object oriented approach would be better. But, since it's turtles we're chasing, I'd make MyTurtle be a turtle instead of contain a turtle:

from random import choice, randint
from turtle import Screen, Turtle

COLORS = ['yellow', 'gold', 'orange', 'red', 'magenta', 'navy', 'blue', 'purple', 'cyan', 'brown', 'black', 'gray', 'white']

class MyTurtle(Turtle):
    def __init__(self, color):
        super().__init__()

        self.hideturtle()
        self.color(color)
        self.shape('turtle')
        self.penup()

        x = randint(-75, 75)
        y = randint(-75, 75)

        self.goto(x, y)
        self.onclick(self.on_turtle_clicked)
        self.showturtle()

    def on_turtle_clicked(self, x, y):
        self.goto(95, -122)
        print("yes")


screen = Screen()
screen.bgcolor('lightgreen')

print("Welcome! This pond is infested with turtles! Can you catch all the turtles?")

turtles = [MyTurtle(choice(COLORS)) for _ in range(5)]

screen.mainloop()

Solution 2:[2]

I would suggest doing this using Object Oriented Programming, because it will probably be significantly easier than doing it procedurally. It should be possible to do it procedurally, but tedious.

An Object Oriented example:

import turtle
import random

# Create MyTurtle class
class MyTurtle:
    def __init__(self, colour):
        self.t = turtle.Turtle()
        self.t.color(colour)
        self.t.shape("turtle")
        self.t.penup()
        self.t.hideturtle()
        r = random.randint(-75,75)
        r2 = random.randint(-75,75)
        r3 = random.randint(1,10)
        self.t.goto(r,r2)
        self.t.onclick(self.on_turtle_clicked)
        self.t.showturtle()

    def on_turtle_clicked(self, x, y):
        self.t.goto(95, -122)
        print("yes")


s = turtle.Screen()
s.bgcolor("lightgreen")

colours = ['yellow', 'gold', 'orange', 'red', 'magenta', 'navy', 'blue', 'purple', 'cyan', 'brown', 'black', 'gray', 'white']

print("Welcome! this pond is infested with turtles! Can you catch all the turtles?")

turtles = []
for x in range(0, 5):
    turtles.append(MyTurtle(random.choice(colours)))

Here is a tutorial for Object Oriented Programming in Python if you need it. https://realpython.com/python3-object-oriented-programming/

Hope that helps!

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 cdlane
Solution 2