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:
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!