Memory
Le Memory est un jeu de paires : les cartes sont posées face cachée ; le joueur en retourne deux à la fois ; si elles sont identiques, il les conserve face visible ; sinon, elles sont remises face cachée après un court délai. Le but est de trouver toutes les paires.
Pré-requis
Callbacks metagrid, listes de listes, tuples, variables globales.
Installe metagrid dans le terminal : uv add metagrid
Taille de la grille
Peut-on jouer au Memory sur une grille de 5×5 ? Pourquoi ? Quelle contrainte cela impose-t-il sur les dimensions ?
Crée un fichier memory.py dans un dossier contenant un sous-dossier images/ avec les fichiers 0.png, 1.png, ..., 7.png fournis par le professeur.
"""
Memory - jeu de paires avec images.
"""
import metagrid
from random import shuffle
HAUTEUR_GRILLE = 4
LARGEUR_GRILLE = 4
TAILLE_CASE = 100
NB_IMAGES = HAUTEUR_GRILLE * LARGEUR_GRILLE // 2
DUREE = 120 # frames pendant lesquelles une mauvaise paire reste visible
COULEUR_CACHEE = "#888888"
COULEUR_TROUVEE = "#44FF88"
grille: list[list[int]] # numéro d'image de chaque case
cases_trouvees: list[tuple[int, int]] # cases trouvées définitivement
cases_devoilees: list[tuple[int, int]] # 0, 1 ou 2 cases retournées en cours
timer: int # décompte avant de recouvrir les cartes
jeu: metagrid.AbstractEngine
def init():
"""Remet le jeu à zéro.
grille : NB_IMAGES paires mélangées — chaque entier de 0 à NB_IMAGES-1
apparaît exactement deux fois, dans un ordre aléatoire.
cases_trouvees, cases_devoilees : listes vides.
timer : 0.
"""
global grille, cases_trouvees, cases_devoilees, timer
pass
def update():
"""Appelée à chaque frame avant draw.
Si timer > 0 : le décrémenter.
Quand timer atteint 0 : vider cases_devoilees.
"""
global timer, cases_devoilees
pass
def cliquer(i: int, j: int, _bouton: str):
"""Appelée au clic sur la case (i, j).
Ignorer le clic si :
- la case est déjà dans cases_trouvees ou cases_devoilees,
- deux cases sont déjà dévoilées (timer en cours).
Sinon, ajouter (i, j) à cases_devoilees.
Quand cases_devoilees contient exactement 2 cases :
- même image → les déplacer dans cases_trouvees, vider cases_devoilees.
- images différentes → démarrer le timer (timer = DUREE).
"""
global cases_devoilees, cases_trouvees, timer
pass
def gagne() -> bool:
"""Renvoie True si toutes les cases ont été trouvées."""
pass
def draw():
"""Affiche la grille à chaque frame.
Pour chaque case (i, j) :
- si elle est dans cases_trouvees : fond COULEUR_TROUVEE + image.
- si elle est dans cases_devoilees : image visible.
- sinon : fond COULEUR_CACHEE (carte face cachée).
"""
pass
if __name__ == "__main__":
jeu = metagrid.create(HAUTEUR_GRILLE, LARGEUR_GRILLE, TAILLE_CASE, 4)
for k in range(NB_IMAGES):
jeu.load_image(str(k), f"images/{k}.png")
jeu.on_init(init)
jeu.on_update(update)
jeu.on_click(cliquer)
jeu.on_draw(draw)
jeu.start()
Construire les paires dans init
Constituer une liste [0, 0, 1, 1, 2, 2, ..., NB_IMAGES-1, NB_IMAGES-1], la mélanger avec shuffle, puis remplir grille case par case en parcourant cette liste dans l'ordre.
Vérifier une paire dans cliquer
Quand cases_devoilees contient deux éléments, on peut les récupérer simultanément :
Les images correspondent si grille[i1][j1] == grille[i2][j2].
Ordre des gardes dans cliquer
L'ordre des deux vérifications en début de cliquer est critique.
Si on teste len(cases_devoilees) >= 2 en premier, alors pendant le timer (deux cartes visibles), un clic sur une carte déjà trouvée sera rejeté à tort — le joueur ne peut plus rien faire jusqu'à ce que le timer s'écoule, même pour cliquer ailleurs.
Il faut tester si la case est déjà trouvée ou déjà dévoilée avant de tester le nombre de cartes visibles.