1
\$\begingroup\$

I've made a memory match game, where the users can draw each card. When the program is ran, there would be a canvas that allows the user to draw in. When the user is done drawing, they can press ENTER, and another fresh canvas will appear.

The user may repeat the process, drawing as many card designs as needed, and when enough card designs are drawn, press ENTER without drawing anything, and the memory match game will begin.

Here is a sped-up demonstration how it works:

enter image description here

My code:

import pygame
from time import sleep
from random import shuffle, choice
ROWS = 5
COLUMNS = 8
pygame.init()
wn = pygame.display.set_mode((435, 500))
class CreateShape:
 def __init__(self, x, y, w, h):
 self.rect = pygame.Rect(x, y, w, h)
 self.drawing = False
 self.color = (255, 0, 0)
 self.cors = []
 def under(self, pos):
 return self.rect.collidepoint(pos)
 def draw(self):
 pygame.draw.rect(wn, (255, 255, 255), self.rect)
 for cor in self.cors:
 if len(cor) > 2:
 pygame.draw.polygon(wn, self.color, cor)
 def create(self):
 while True:
 for event in pygame.event.get():
 if event.type == pygame.QUIT:
 pygame.quit()
 elif event.type == pygame.MOUSEBUTTONDOWN:
 if shape.under(event.pos):
 shape.cors.append([])
 shape.drawing = True
 elif event.type == pygame.MOUSEBUTTONUP:
 shape.drawing = False
 elif event.type == pygame.MOUSEMOTION:
 if shape.under(event.pos):
 if shape.drawing:
 shape.cors[-1].append(event.pos)
 elif event.type == pygame.KEYDOWN:
 return self.cors
 wn.fill((0, 0, 0))
 shape.draw()
 pygame.display.update()
class Card:
 def __init__(self, x, y, w, h, shape, original):
 self.x = x
 self.y = y
 self.w = w
 self.h = h
 self.card_color = (200, 200, 200)
 self.shape_color = (255, 0, 0)
 self.rect = pygame.Rect(x, y, w, h)
 self.shape = shape
 self.original = original
 self.turned = False
 def flip(self):
 self.turned = not self.turned
 def clicked(self, pos):
 return self.rect.collidepoint(pos)
 def draw(self):
 pygame.draw.rect(wn, self.card_color, self.rect)
 if self.turned:
 for shape in self.shape:
 pygame.draw.polygon(wn, self.shape_color, shape)
class Deck:
 def __init__(self, x, y, w, h, rows, cols, score_keeper, shapes=[], space=5):
 shapes *= 2
 self.turned = []
 self.cards = []
 index = 0
 while len(shapes) < rows * cols:
 shapes += [choice(shapes)] * 2
 shuffle(shapes)
 for i in range(rows):
 for j in range(cols):
 shapey = [[[c[0] / 2, c[1] / 2] for c in s] for s in shapes[index]]
 card_x, card_y = x + j * (w + space), y + i * (h + space)
 cors_x = sorted([cor[0] for shape in shapey for cor in shape])
 cors_y = sorted([cor[1] for shape in shapey for cor in shape])
 max_x, min_x = cors_x[0], cors_x[-1]
 max_y, min_y = cors_y[0], cors_y[-1]
 shaper = [[(i + card_x - min_x + (w - max_x + min_x) / 2,
 j + card_y - min_y + (h - max_y + min_y) / 2) for i, j in shape] for shape in shapey]
 self.cards.append(Card(card_x, card_y, w, h, shaper, shapes[index]))
 index += 1
 
 def check_equal(self, c1, c2):
 for shape1, shape2 in zip(c1.original, c2.original):
 for s1, s2 in zip(shape1, shape2):
 for cor1, cor2 in zip(s1, s2):
 if cor1 != cor2:
 return False
 return True
 
 def clicked(self, pos):
 for card in self.cards:
 if card.clicked(pos):
 card.flip()
 if card.turned:
 self.turned.append(card)
 else:
 self.turned.remove(card)
 if len(self.turned) == 2:
 self.draw()
 pygame.display.update()
 sleep(0.5)
 if self.check_equal(*self.turned):
 for card in self.turned:
 self.cards.remove(card)
 score.add()
 else:
 for card in self.turned:
 card.flip()
 score.remove()
 self.turned.clear()
 def draw(self):
 for card in self.cards:
 card.draw()
class Score:
 def __init__(self, x, y, size=40):
 self.x = x
 self.y = y
 self.size = size
 self.font = pygame.font.SysFont('Arial', size)
 self.total = 0
 def add(self, amt=10):
 self.total += amt
 def remove(self, amt=5):
 self.total -= amt
 def draw(self):
 text = self.font.render(f'Score: {self.total}', False, (255, 255, 255))
 wn.blit(text, (self.x, self.y))
shapes = []
for i in range(ROWS * COLUMNS // 2):
 shape = CreateShape(168, 200, 100, 100)
 my_shape = shape.create()
 if not my_shape:
 break
 shapes.append(my_shape)
score = Score(20, 20)
deck = Deck(20, 90, 45, 65, ROWS, COLUMNS, score, shapes)
while True:
 for event in pygame.event.get():
 if event.type == pygame.QUIT:
 pygame.quit()
 elif event.type == pygame.MOUSEBUTTONDOWN:
 deck.clicked(event.pos)
 wn.fill((0, 0, 0))
 deck.draw()
 score.draw()
 pygame.display.update()

I believe my check_equal function can be greatly simplified, as all it does is return wehther two lists (c1 and c2) of lists of tuples are equal:

def check_equal(self, c1, c2):
 for shape1, shape2 in zip(c1.original, c2.original):
 for s1, s2 in zip(shape1, shape2):
 for cor1, cor2 in zip(s1, s2):
 if cor1 != cor2:
 return False
 return True

Can you please point out where in my code can be simpliflied, and where can I improve the efficiency of it?

Bug reports will also be greatly appreciated!

asked Dec 2, 2020 at 1:51
\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

check_equal() can be greatly simplified:

def check_equal(self, c1, c2):
 return c1.original is c2.original

The main code creates a list of shapes. Deck.__init__() uses shapes *= 2 to double the list of shapes. That is, shapes now contains two copies of each shape. Actually, it contains two references to the same shape. Then a Card is made from each shape, which stores the shape in Card.original. So you can use is to check if the cars have the same shape.

answered Dec 3, 2020 at 9:00
\$\endgroup\$
1
  • \$\begingroup\$ Awesome! ------ \$\endgroup\$ Commented Dec 3, 2020 at 13:03

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.