Tetris (et Snake) est le « Hello World » du développement de jeux. On pourrait penser qu'il est difficile de le gâcher, mais l'auteur de ce dépôt a fait de son mieux. Analysons un projet présenté comme « matériel pédagogique pour débutants ». Oui, le code fonctionne, le projet est terminé, il y a même une vidéo YouTube. Mais en réalité, on y apprend de mauvaises habitudes.

1️⃣ Absence de point d'entrée
Dans main.py, le code est simplement jeté à la racine du fichier. Pas de if __name__ == "__main__":. Si vous essayez d'importer quelque chose depuis ce fichier (pourquoi faire ?), Pygame sera immédiatement initialisé et une fenêtre s'ouvrira.

2️⃣ Problème d'espace de noms
Dans game.py, on voit du beau : from blocks import *.
Souvenez-vous : chaque fois que vous utilisez import *, vous encombrez l'espace de noms avec des déchets. Quelles classes arrivent ? D'où ? Personne ne le sait.

3️⃣ Classe orchestre
La classe Game est un couteau suisse. Elle gère la logique, compte les points, charge les sons, joue la musique et... dessine les blocs.
Violation du SRP (Single Responsibility Principle) évidente. La logique du jeu ne devrait pas connaître l'existence de pygame.mixer ni comment dessiner des rectangles.

# Dans les entrailles de Game.__init__
self.rotate_sound = pygame.mixer.Sound("Sounds/rotate.ogg")
pygame.mixer.music.load("Sounds/music.ogg")

Vous voulez changer de bibliothèque audio ? Bonne chance pour réécrire tout le cœur du jeu.

4️⃣ POO de cerveau : Héritage pour... rien
Dans blocks.py, on voit l'erreur classique : créer sept classes différentes (LBlock, JBlock, etc.) qui héritent de Block uniquement pour écrire un dictionnaire de coordonnées dans __init__.

C'est du sur-ingénierie classique. Toutes ces classes n'ont pas de comportement unique, seulement des données différentes.

Comment faire : Une seule classe Block qui accepte le type de pièce ou une configuration à l'initialisation. Les données séparément, la logique séparément.

5️⃣ Classe Position — pourquoi ?
class Position:
def __init__(self, row, column):
self.row = row
self.column = column

Créer une classe entière pour stocker deux entiers est redondant. En Python, il y a namedtuple, dataclasses, ou tout simplement des tuples (row, col).

6️⃣ Nombres magiques et code en dur
if self.next_block.id == 3:
self.next_block.draw(screen, 255, 290)
elif self.next_block.id == 4:
self.next_block.draw(screen, 255, 280)

C'est de l'UI « bricolée » à l'état pur. Au lieu de calculer le centre de la zone d'aperçu, l'auteur a simplement ajusté les coordonnées en fonction des ID des blocs. Ajoutez un nouveau bloc et toute la mise en page s'effondre.

7️⃣ Gestion du score de l'époque des mammouths
Dans game.py, on voit ceci :

def update_score(self, lines_cleared, move_down_points):
if lines_cleared == 1:
self.score += 100
elif lines_cleared == 2:
self.score += 300
# ... et ainsi de suite


Comment faire : Un simple dictionnaire ou une liste de coefficients aurait rendu ce code en une ligne. Les chaînes de elif pour des correspondances simples sont un signe certain que l'auteur ne maîtrise pas les structures de données.

🧑‍⚖️ Verdict :
En tant que projet d'apprentissage, ça peut aller. Si vous apprenez avec de tels tutoriels, rappelez-vous : leur but est de montrer un résultat en 20 minutes de vidéo, pas de vous apprendre à écrire du code correct. N'emportez pas ces schémas en production.

#on_critique_le_code