What you can do is define a list, turned to store cards that are turned over.
Here is an example of a Card class:
class Card(turtle.Turtle):
def __init__(self, number):
super(Card, self).__init__()
self.number = number
def click(self, x, y):
if self in turned:
self.clear()
turned.remove(self)
else:
self.sety(self.ycor() - self.shapesize()[1] * 7)
self.write(self.number, align='center', font=('Arial', 20, 'bold'))
self.sety(self.ycor() + self.shapesize()[1] * 7)
turned.append(self)
The super(Card, self).__init__() will give the Card class all the attributes a turtle.Turtle class has. Use self.number = number to add a class variable to the Card class.
In the click function:
if self in turned:
self.clear()
turned.remove(self)
That will allow to user to unselect a card that is selected by removing it from the turned list, and clearing the text, and
else:
self.sety(self.ycor() - self.shapesize()[1] * 7)
self.write(self.number, align='center', font=('Arial', 20, 'bold'))
self.sety(self.ycor() + self.shapesize()[1] * 7)
turned.append(self)
will write the text and append the card into the turned list.
I also defined a Deck class that will use the Card class to create a whole grid of cards:
class Deck:
def __init__(self, rows, cols, width, height, x, y):
self.cards = []
for i in range(cols):
for j in range(rows):
card = Card(randint(2, 10))
card.shape("square")
card.color('black', 'white')
card.shapesize(height / 20, width / 20)
card.goto(i * width + x, j * height + y)
card.onclick(card.click)
self.cards.append(card)
Example:
import turtle
from random import randint
wn = turtle.Screen()
wn.tracer(0)
turned = []
class Card(turtle.Turtle):
def __init__(self, number):
super(Card, self).__init__()
self.number = number
def click(self, x, y):
if self in turned:
self.clear()
turned.remove(self)
else:
self.sety(self.ycor() - self.shapesize()[1] * 7)
self.write(self.number, align='center', font=('Arial', 20, 'bold'))
self.sety(self.ycor() + self.shapesize()[1] * 7)
turned.append(self)
print([card.number for card in turned]) # print to display the clicked cards
class Deck:
def __init__(self, rows, cols, width, height, x, y):
self.cards = []
for i in range(cols):
for j in range(rows):
card = Card(randint(2, 10))
card.shape("square")
card.color('black', 'white')
card.shapesize(height / 20, width / 20)
card.goto(i * width + x, j * height + y)
card.onclick(card.click)
self.cards.append(card)
deck = Deck(8, 8, 45, 62.5, -165, -210)
wn.update()
wn.mainloop()
Output:

The above code may seem simpler, but it used one global variable, turned, and the numbers will only display for half a second with tracer left on. And clicking directly on the displayed number will not change the status of the cards.
The below code corrects those flaws:
What you can do is define a class to be each card, and a class to be the deck of cards. In the deck class, define a class variable list, turned to store cards that are turned over.
Here is an example of a Card class:
class Card(turtle.Turtle):
def __init__(self, number):
super(Card, self).__init__()
self.number = number
self.penup()
def write_number(self, pen):
pen.goto(self.xcor(), self.ycor() - self.shapesize()[1] * 7)
pen.write(self.number, align='center', font=('Arial', 20, 'bold'))
def clicked(self, x, y):
h, w = self.shapesize()[:-1]
half_width = w * 10
half_height = h * 10
return self.xcor() + half_width > x > self.xcor() - half_width and \
self.ycor() + half_height > y > self.ycor() - half_height
The super(Card, self).__init__() will give the Card class all the attributes a turtle.Turtle class has. Use self.number = number to add a class variable to the Card class.
The write_number function will, as you can probably guess, display a number on the current turtle object using a separate turtle object so that the number will be display on the center of the card.
The clicked function will basically take in two coordinates, and detect whether the coordinates are on the current turtle object. The reason I defined a clicked function instead of using the built-in turtle.onclick method, is because I want it to return a Boolean value rather than to execute a function.
The Deck class that will use the Card class to create a whole grid of cards.:
class Deck:
def __init__(self, rows, cols, width, height, x, y):
self.pen = turtle.Turtle(visible=False)
self.pen.penup()
self.pen.speed(0)
self.cards = []
self.numbers = []
self.turned = []
for i in range(cols):
for j in range(rows):
card = Card(randint(2, 10))
card.shape("square")
card.color('black', 'white')
card.shapesize(height / 20, width / 20)
card.goto(i * width + x, -j * height - y)
self.cards.append(card)
def click(self, x, y):
for card in self.cards:
if card.clicked(x, y):
if card in self.turned:
card.clear()
self.turned.remove(card)
else:
self.turned.append(card)
self.draw()
print([card.number for card in self.turned])
def draw(self):
for card in self.turned:
card.write_number(self.pen)
The self.cards list store all the Card objects, and the self.turned stores the cards that are turned over.
The click function will use the clicked function from the Card class to detect clicks on all the Card objects inside the Deck class variable, cards.
Finally, the draw function will display the number on all the cards in the turned list, using the self.pen defined in the Deck.
Full working code:
import turtle
from random import randint
wn = turtle.Screen()
class Card(turtle.Turtle):
def __init__(self, number):
super(Card, self).__init__()
self.number = number
self.penup()
def write_number(self, pen):
pen.goto(self.xcor(), self.ycor() - self.shapesize()[1] * 7)
pen.write(self.number, align='center', font=('Arial', 20, 'bold'))
def clicked(self, x, y):
h, w = self.shapesize()[:-1]
half_width = w * 10
half_height = h * 10
return self.xcor() + half_width > x > self.xcor() - half_width and \
self.ycor() + half_height > y > self.ycor() - half_height
class Deck:
def __init__(self, rows, cols, width, height, x, y):
self.pen = turtle.Turtle(visible=False)
self.pen.penup()
self.pen.speed(0)
self.cards = []
self.numbers = []
self.turned = []
for i in range(cols):
for j in range(rows):
card = Card(randint(2, 10))
card.shape("square")
card.color('black', 'white')
card.shapesize(height / 20, width / 20)
card.goto(i * width + x, -j * height - y)
self.cards.append(card)
def click(self, x, y):
for card in self.cards:
if card.clicked(x, y):
if card in self.turned:
card.clear()
self.turned.remove(card)
else:
self.turned.append(card)
self.draw()
print([card.number for card in self.turned])
def draw(self):
for card in self.turned:
card.write_number(self.pen)
deck = Deck(8, 8, 45, 62.5, -165, -210)
wn.onscreenclick(deck.click)
wn.mainloop()