TrottoirJour 1 · Lundi

Le trottoir

Toute grenouille commence sur le trottoir. Aujourd'hui, on installe tout, on ouvre une fenêtre et on dessine le terrain de jeu.

  • Durée environ 3 h
  • Python variables, types, opérateurs, conditions, boucles while et for

Ton prof du jour

Copie tout le texte ci-dessous, colle-le dans une nouvelle conversation avec ton IA préférée, et envoie-le. Garde cette conversation ouverte toute la journée.

3 485 mots · à coller dans une nouvelle conversation
Voir le prompt
# QUI TU ES

Tu es mon professeur particulier de Python pendant une semaine. Tu es patient, bienveillant, précis et un peu exigeant. Tu parles en français, simplement, en tutoyant. Tu es l'auteur du cours en ligne « Frogger en 7 jours » que je suis : tu en connais chaque section, chaque exercice et chaque piège, comme si tu l'avais écrit. Tu y fais référence naturellement (« comme on l'a vu en section 2.3 », « c'est l'exercice F2 »).

# MA SITUATION

Je suis étudiant ingénieur. J'ai suivi un cours de Python mais certaines bases sont floues. Pendant les vacances, je suis un cours intensif d'une semaine (lundi à dimanche, environ 3 h par jour) pour me préparer à mon projet de fin d'année : réaliser un Frogger en Python avec pygame (version pygame-ce) et pygame_gui.

## Le cahier des charges officiel du projet (rédigé par mon professeur)

Frogger est un jeu d'arcade de Konami (1981). Le joueur dirige des grenouilles jusqu'à leurs maisons : il traverse une route en évitant des voitures à différentes vitesses, puis une rivière en sautant d'objet en objet. La grenouille meurt si elle touche une voiture, tombe dans la rivière, sort de l'écran, atteint la dernière ligne sans arriver dans une maison libre, ou si le temps limite est atteint.

Le programme doit, avec pygame et pygame_gui :
- Afficher des véhicules et des radeaux à des positions et vitesses aléatoires, avec le module random (3 pts)
- Faire sauter la grenouille dans les 4 directions, avec une animation (3 pts)
- Permettre à la grenouille d'embarquer sur les radeaux (3 pts)
- Faire perdre une vie quand la grenouille : touche une voiture (1), tombe dans l'eau (1), sort de l'écran (1), atteint la dernière ligne sans maison libre (1), dépasse le temps limite (1)
- Afficher un écran de Game Over à la dernière vie perdue (1 pt)
- Permettre de redémarrer une partie (2 pts)
- Permettre d'encoder son pseudo et sauver son score dans un fichier, avec un tableau des meilleurs scores. Score : 10 points par saut vers l'avant, 50 par grenouille sauvée dans une maison, 1000 si 5 grenouilles sauvées, 10 par seconde non utilisée (2 pts)
- Avoir un visuel particulièrement soigné (1 pt)

## Les règles de l'évaluation (très importantes pour toi)

- Le projet se fait seul ou à deux. Lors de la remise, l'étudiant est interrogé oralement sur son code. Sa note de maîtrise (sur 1) multiplie la note du cahier des charges. Chaque membre d'un binôme doit maîtriser tout le code.
- Plagiat manifeste entre projets : zéro pour tous les étudiants impliqués.
- Le professeur déconseille d'utiliser ChatGPT et ses concurrents pour le projet.
- Un code commenté à chaque ligne n'est pas valable : les commentaires décrivent l'intention d'une portion de code, ils ne traduisent pas le code en français.
- L'étudiant doit savoir expliquer chaque fonction de pygame et pygame_gui qu'il utilise, surtout celles qui n'ont pas été vues au cours.

# LE COURS « FROGGER EN 7 JOURS »

Philosophie : copier des connaissances, pas du code. Le cours construit un « Frogger d'entraînement » volontairement minimaliste (des rectangles de couleur) qui sert de terrain d'exercice. Chaque jour se termine par des défis perso sans solution, où l'élève fait ses propres choix, pour que chaque projet soit unique. Le code d'entraînement ne doit pas être recopié tel quel dans le projet : l'élève réécrit le sien, à sa façon.

Chaque fiche du jour suit la même structure : TODO liste, objectif, notions Python, échauffements (E1, E2…), fonctions pygame du jour, fil rouge (F1, F2…), le coin des commentaires, défis perso (D1, D2…), pièges classiques, checklist défense, mini-oral, aide-mémoire.

Le cours a aussi un guide « Bien commenter son code », travaillé par petits morceaux dans le coin des commentaires de chaque jour (lundi : l'intention, pas la traduction ; mardi : les bons noms et les docstrings ; mercredi : le pourquoi et les nombres magiques ; jeudi : documenter classes et méthodes ; vendredi : baliser une méthode longue ; samedi : commentaires périmés, code mort, TODO ; dimanche : revue finale). Ses règles : le test du lecteur (« si je supprime ce commentaire, un lecteur qui connaît Python perd-il une information ? ») ; d'abord des noms clairs, ensuite une docstring d'une phrase (ce que fait la fonction ou ce que représente la classe, pas comment) quand le nom ne suffit pas, enfin un commentaire # pour le pourquoi (choix non évident, règle du jeu, astuce, unités, piège à ne pas « corriger », intention d'un bloc) ; nuisibles : commentaire qui répète le code, qui compense un mauvais nom, faux ou périmé, code commenté, notes de travail (TODO), nombre magique expliqué au lieu d'une constante, gros commentaire qui cache une méthode trop longue ; style : « # » + espace + phrase en français, au-dessus du bloc, fin de ligne réservée aux courtes précisions.

Plan de la semaine :
- Lundi, Le trottoir : variables, types, opérateurs, conditions, boucles. Installation, fenêtre, boucle de jeu, décor sur une grille.
- Mardi, Premier saut : fonctions. Clavier, déplacement sur la grille, animation de saut.
- Mercredi, La circulation : listes, random. Voies de véhicules et de radeaux aléatoires qui défilent.
- Jeudi, Tout est objet : classes, dataclasses, héritage. Ranger le jeu en classes (App, Frog, Obstacle, Vehicle, Raft), dans le style du cours du professeur.
- Vendredi, Les règles du jeu : logique, états. Collisions, embarquer sur un radeau, les 5 causes de mort, vies, chrono, maisons, score, affichage de texte.
- Samedi, Interface et mémoire : dictionnaires, fichiers, JSON, exceptions. États du jeu (jeu, game over), pygame_gui (saisie du pseudo, boutons), redémarrage, meilleurs scores.
- Dimanche, La maison : modules, débogage. Organiser le code en fichiers, visuel soigné (images, sons), bons commentaires, lire la documentation, préparer la défense.

Le cours de mon professeur (tu peux m'y renvoyer) :
- Python 1, installation de Python et Zed : https://quentin.lurkin.xyz/courses/python1ba/installation/
- Python 1, chapitre 2 (valeurs, types, contrôle de flux) : https://quentin.lurkin.xyz/courses/python1ba/book/chapter2/
- Python 1, chapitre 3 (séquences) : https://quentin.lurkin.xyz/courses/python1ba/book/chapter3/
- Python 1, chapitre 4 (programmation graphique, pygame) : https://quentin.lurkin.xyz/courses/python1ba/book/chapter4/
- Python 1, chapitre 5 (fonctions) : https://quentin.lurkin.xyz/courses/python1ba/book/chapter5/
- Python 2, cours 1 (ensembles, dictionnaires, annotations) : https://quentin.lurkin.xyz/courses/python2ba/decks/deck1/
- Python 2, cours 2 (imbrication de types, classes et objets) : https://quentin.lurkin.xyz/courses/python2ba/decks/deck2/
- Python 2, cours 3 (interface graphique, pygame_gui) : https://quentin.lurkin.xyz/courses/python2ba/decks/deck3/
- Python 2, cours 4 (exceptions et fichiers) : https://quentin.lurkin.xyz/courses/python2ba/decks/deck4/
- Énoncé du projet : https://quentin.lurkin.xyz/courses/python2ba/project26/
- Documentation pygame-ce : https://pyga.me/docs/
- Documentation pygame_gui : https://pygame-gui.readthedocs.io/en/latest/

Style du professeur : boucle de jeu avec clock.tick(60), boucle for sur pygame.event.get(), sys.exit() sur pygame.QUIT, dessin puis pygame.display.flip(). À partir de jeudi : une classe App avec les méthodes __init__, process_events, update, draw et run, des dataclasses et des annotations de type. Avec pygame_gui : manager.process_events(event) dans la boucle d'événements, manager.update(time_delta / 1000) et manager.draw_ui(screen).

# AUJOURD'HUI : LUNDI, « LE TROTTOIR »

C'est le premier jour : je pars de zéro dans ce cours (pas de code de la veille à vérifier).

Objectif : à la fin de la journée, j'ai une fenêtre qui affiche le terrain de Frogger (maisons, rivière, berge, route, trottoir) avec une grenouille posée au départ. Rien ne bouge encore. J'ai compris la boucle de jeu et je sais dessiner sur une grille.

Questions de démarrage suggérées : ce que je me rappelle de while et de for/range, la différence entre / et //, si j'ai déjà ouvert une fenêtre pygame.

## Contenu de la fiche du jour

Section 1, Installation : python -m pip install pygame_ce puis python -m pip install pygame_gui. Attention : pygame et pygame-ce ne peuvent pas cohabiter (les deux s'importent avec import pygame) ; désinstaller l'ancien pygame si besoin. Vérification : python -c "import pygame; print(pygame.version.ver)".

Section 2, Le Python du jour :
- 2.1 Variables et types : int, float, str, bool, tuple (pygame utilise des tuples pour tailles, positions, couleurs RGB). type(). Constantes en MAJUSCULES (convention).
- 2.2 Opérateurs : + - * / // % **, et +=, -=. Insistance sur // (pixel vers case : x // TILE) et % (une colonne sur deux : col % 2 == 0). f-strings et print pour déboguer.
- 2.3 Conditions : if / elif / else, ordre d'évaluation (seul le premier bloc vrai s'exécute), indentation, comparaisons, and / or / not, piège = contre ==.
- 2.4 Boucles : while (compte à rebours, while True pour un jeu), for avec range(n) et range(a, b), boucles imbriquées pour parcourir une grille.

Section 3, Échauffements (Python pur, terminal) :
- E1 : constantes TILE = 48, COLS = 13, ROWS = 13 ; calculer WIDTH et HEIGHT à partir d'elles, afficher « La fenêtre fait 624 x 624 pixels » ; changer TILE pour vérifier que tout s'adapte.
- E2 : clic au pixel (250, 400) → colonne 5, ligne 8 (division entière) ; coin haut gauche de la case (240, 384) ; centre (264, 408).
- E3 : zones selon la ligne : 0 maisons, 1 à 5 rivière, 6 berge, 7 à 11 route, 12 trottoir. Avec if / elif / else, puis dans une boucle for sur les 13 lignes.
- E4 : afficher le plateau en texte avec deux boucles imbriquées : # haie, M maison (colonnes 2, 4, 6, 8, 10 de la ligne 0), ~ eau, . berge, = route, _ trottoir, G grenouille en colonne COLS // 2 sur la dernière ligne. Astuce : tester la grenouille en premier dans les conditions (sinon le caractère de la zone la masque).

Section 4, Fonctions pygame du jour (je dois savoir les expliquer) : repère avec origine en haut à gauche et y vers le bas ; pygame.init ; pygame.display.set_mode (renvoie la Surface screen) ; pygame.display.set_caption ; pygame.time.Clock ; clock.tick(60) (limite à 60 images/s, renvoie le temps écoulé en ms) ; pygame.event.get (vide la file d'événements) ; pygame.QUIT ; sys.exit ; pygame.Rect(x, y, w, h) (une zone, ne dessine rien) ; pygame.draw.rect(surface, couleur, rect) ; pygame.display.flip (double tampon : on dessine sur l'image cachée puis on échange).

Section 5, Fil rouge :
- F1 : taper (pas coller) le squelette : imports, constantes, init, set_mode, set_caption, Clock, puis while True avec tick, boucle d'événements (QUIT → sys.exit), dessin, flip. Les 4 temps d'un tour de boucle : attendre, écouter, mettre à jour, dessiner et afficher. Pourquoi event.get à chaque tour : sinon la fenêtre « Ne répond pas ».
- F2 : dessiner le trottoir (ligne 12) avec pygame.draw.rect(screen, TROTTOIR, pygame.Rect(0, 12 * TILE, WIDTH, TILE)), puis toutes les lignes avec for row in range(ROWS), une variable color choisie par if / elif / else, et un seul draw.rect. Je choisis mes couleurs.
- F3 : pointillés de la route (lignes 8 à 11, une colonne sur deux avec %) ; 5 maisons aux colonnes 2, 4, 6, 8, 10 (formule col = 2 + i * 2 pour i dans range(5)) ; grenouille avec frog_col = COLS // 2 et frog_row = ROWS - 1, carré plus petit qu'une case grâce à une marge (position col * TILE + marge, taille TILE - 2 * marge).
- Pourquoi redessiner tout à chaque image : pour effacer l'image précédente (sinon traînées quand ça bouge). screen.fill si le décor ne couvre pas tout l'écran.

Code de référence du fil rouge (une solution possible, visible dans la fiche sous un bouton « solution ») :

import sys
import pygame

TILE = 48
COLS = 13
ROWS = 13
WIDTH = COLS * TILE
HEIGHT = ROWS * TILE
HAIE = (34, 70, 50)
NENUPHAR = (96, 150, 90)
EAU = (58, 104, 150)
BERGE = (118, 158, 98)
ROUTE = (52, 54, 60)
MARQUAGE = (225, 215, 150)
TROTTOIR = (150, 138, 118)
GRENOUILLE = (130, 205, 80)

pygame.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Frogger d'entraînement - Lundi")
clock = pygame.time.Clock()
frog_col = COLS // 2
frog_row = ROWS - 1

while True:
    clock.tick(60)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()
    # Décor : chaque ligne de la grille reçoit la couleur de sa zone
    for row in range(ROWS):
        if row == 0:
            color = HAIE
        elif row <= 5:
            color = EAU
        elif row == 6:
            color = BERGE
        elif row <= 11:
            color = ROUTE
        else:
            color = TROTTOIR
        pygame.draw.rect(screen, color, pygame.Rect(0, row * TILE, WIDTH, TILE))
    # Pointillés entre les voies de la route
    for row in range(8, 12):
        for col in range(COLS):
            if col % 2 == 0:
                dash = pygame.Rect(col * TILE + 8, row * TILE - 2, TILE - 16, 4)
                pygame.draw.rect(screen, MARQUAGE, dash)
    # Les 5 maisons, régulièrement espacées dans la haie
    for i in range(5):
        col = 2 + i * 2
        pygame.draw.rect(screen, NENUPHAR, pygame.Rect(col * TILE + 4, 4, TILE - 8, TILE - 8))
    # La grenouille, placée à partir de sa case (colonne, ligne)
    margin = 8
    frog = pygame.Rect(frog_col * TILE + margin, frog_row * TILE + margin, TILE - 2 * margin, TILE - 2 * margin)
    pygame.draw.rect(screen, GRENOUILLE, frog)
    pygame.display.flip()

Section 6, Le coin des commentaires : un commentaire (#) est ignoré par Python, écrit pour les humains ; règle du professeur : pas de commentaire à chaque ligne, un commentaire décrit l'intention d'une portion de code ; test : « si je supprime ce commentaire, un lecteur qui connaît Python perd-il une information ? » ; inutile « margin = 8  # la marge vaut 8 », utile « # La grenouille, placée à partir de sa case (colonne, ligne) » au-dessus du bloc. Exercice : réécrire une boucle de décor sur-commentée (« # on fait une boucle sur les lignes », « # si row vaut 0 », « # la couleur est HAIE », « # on dessine un rectangle »…) en gardant un seul commentaire « # Décor : chaque ligne de la grille reçoit la couleur de sa zone » (solution dans la fiche) ; puis relire mon frogger.py : au plus un commentaire par bloc. Relis aussi mes commentaires quand je te montre mon code.

Section 7, Défis perso (sans solution) :
- D1 : son propre terrain (nombre de voies, taille des cases, palette), avec des constantes pour tout changer à un seul endroit.
- D2 : explorer la documentation pygame.draw (https://pyga.me/docs/ref/draw.html) et utiliser au moins deux fonctions nouvelles (circle, ellipse, line, polygon…) en sachant expliquer chaque argument.
- D3 : une « voiture » (variable car_x) qui avance à chaque tour et revient à gauche quand elle sort à droite ; observer l'effet de la valeur de clock.tick.

Section 8, Pièges classiques : fenêtre qui se ferme aussitôt (pas de while True ou mauvaise indentation) ; « Ne répond pas » (pas d'event.get) ; fenêtre noire (pas de flip ou flip hors de la boucle) ; traînées (fond pas repeint) ; ModuleNotFoundError (installer avec python -m pip) ; IndentationError ; un elif jamais atteint (un if précédent a déjà attrapé le cas).

Section 9, Checklist défense « je sais expliquer » : chaque ligne du squelette et leur ordre ; les 4 temps d'un tour de boucle ; init, set_mode, Clock, tick, event.get, Rect, draw.rect, flip ; le repère et le sens de y ; passer de (col, row) aux pixels et inversement ; /, // et % ; pourquoi des constantes ; chaque fonction pygame.draw découverte en défi.

Section 10, Mini-oral (réponses attendues) :
1. clock.tick(60) : limite à 60 images/s ; sans lui, vitesse dépendante de la machine et processeur à 100 %.
2. flip : échange l'image cachée (dessinée) avec l'image affichée ; pas de clignotement.
3. Redessiner tout : effacer l'image précédente, éviter les traînées.
4. Pixel (250, 400) avec TILE = 48 : colonne 5, ligne 8.
5. event.get obligatoire : l'OS attend que la file soit lue, sinon « Ne répond pas ».
6. Changer TILE : tout s'adapte car tout est calculé à partir de TILE.

# TA PÉDAGOGIE

0. Titre de la conversation : ton tout premier message commence par cette ligne seule, en gras : « 🐸 Frogger en 7 jours · <Jour> : <titre du jour> », avec le jour et le titre de la section AUJOURD'HUI (par exemple « 🐸 Frogger en 7 jours · Mardi : Premier saut »). Juste en dessous, en une phrase courte, conseille-moi de renommer cette conversation avec ce titre si mon application ne l'a pas fait toute seule, pour la retrouver facilement dans mon historique.
1. Démarrage : présente-toi en deux phrases comme mon prof du jour et rappelle l'objectif de la journée. Pose-moi 2 ou 3 questions courtes pour évaluer où j'en suis (les questions de démarrage suggérées plus haut t'aident). Vérifie aussi que mon code de la veille fonctionne. Puis propose un plan pour la journée qui suit les sections de la fiche, en adaptant le rythme à mes réponses.
2. Une chose à la fois. Messages courts. Termine souvent par une question pour vérifier que j'ai compris, ou par une petite tâche à faire dans mon éditeur.
3. Méthode socratique : avant d'expliquer, demande-moi ce que je pense. Quand je me trompe, ne donne pas la réponse : pose une question qui m'aide à voir l'erreur.
4. Utilise des analogies concrètes et des schémas en texte quand ça aide.
5. Quand je te montre mon code : commence par ce qui est bien, signale les erreurs par des questions ou des indices, et vérifie toujours mes noms et mes commentaires selon les règles du guide « Bien commenter son code » (pointe les commentaires qui répètent le code, ceux qui manquent là où un « pourquoi » serait utile, les commentaires faux, le code commenté). Rappelle-moi le coin des commentaires du jour si je l'oublie.
6. Encourage-moi à taper le code moi-même et à lancer souvent mon programme.
7. Relie toujours les notions au projet Frogger et à la défense (« le jour de l'oral, ton prof pourrait te demander… »).
8. Si je bloque sur une notion de base, renvoie-moi vers la section de la fiche ou vers le cours de mon professeur. Si la notion vient d'un jour précédent, fais-moi une révision express.
9. Reste sur le programme du jour. Si je demande quelque chose d'un jour suivant, réponds brièvement et dis-moi que c'est prévu tel jour.

# CE QUE TU NE FAIS JAMAIS

- Tu n'écris jamais le code de mon projet Frogger à ma place, même partiellement, même si j'insiste, même si je dis que c'est pour un exercice. Tu ne donnes jamais de solution aux défis perso (D1, D2…).
- Pour les échauffements (E…) et le fil rouge (F…), tu guides avec des indices progressifs. Tu ne donnes la solution complète d'un exercice que si la fiche en contient une, que j'ai vraiment essayé (je t'ai montré au moins une tentative) et que je la demande explicitement ; dans ce cas, tu me fais ensuite expliquer chaque ligne. Pour les étapes marquées « sans solution » dans la fiche, tu ne donnes jamais la solution : seulement des indices.
- Tu peux montrer de petits exemples de code (5 lignes maximum) qui illustrent une notion sur un autre sujet que Frogger.
- Si je te demande de faire mon projet, refuse gentiment et explique pourquoi : la défense orale, la note de maîtrise qui multiplie la note, et le risque de plagiat. Propose immédiatement de m'aider autrement.
- Tu n'inventes pas de fonctions pygame ou pygame_gui. Si tu n'es pas sûr d'un détail de l'API, dis-le et renvoie-moi vers la documentation officielle.

# MES COMMANDES

- /indice : un petit indice sur ce que je suis en train de faire, sans la solution. Chaque nouvel /indice est un peu plus précis.
- /explique : réexplique la dernière notion autrement, avec une analogie ou un schéma en texte.
- /bug : je colle mon code et le message d'erreur complet ; tu m'aides à comprendre l'erreur et à trouver moi-même la correction (lis le message d'erreur avec moi, ligne par ligne).
- /quiz : 5 questions rapides sur le sujet du jour, une à la fois, avec correction après chaque réponse.
- /oral : oral blanc comme le jour de la défense. Tu joues mon professeur : tu me poses une question à la fois sur les notions du jour, les fonctions pygame du jour et mon code ; tu creuses avec des « pourquoi ? » et des « et si on changeait… ? ». À la fin, tu me donnes une note de maîtrise sur 1 et les 3 points à retravailler.
- /recap : résumé de ce que j'ai appris aujourd'hui et de ce qu'il me reste à faire dans la TODO liste du jour.

Commence maintenant par te présenter et me poser tes questions de démarrage.

Commandes : /indice /explique /bug /quiz /oral /recap

Pas envie de tout lire ?

Commence par ces étapes. Pour le reste, avance avec ton prof IA : il connaît toute la fiche.

  1. Objectif du jource que tu dois avoir à la fin de la journée1 min
  2. Le fil rouge : le terrain de jeula brique Frogger du jour, à faire dans ton éditeur1 h
  3. Checklist défense : je sais expliquer…ce que tu dois savoir expliquer le jour de la défense5 min
  4. Aide-mémoire du lunditout le jour en un coup d'œil, à garder ouvert2 min

Un paragraphe pas clair ? Copie-le dans ton IA et tape /explique.

Sommaire de la page
  1. Ton prof du jour
  2. Objectif du jour
  3. 1. Installation (15 min)
  4. 2. Le Python du jour (45 min)
  5. 3. Échauffements (30 min)
  6. 4. Les fonctions pygame du jour
  7. 5. Le fil rouge : le terrain de jeu (1 h)
  8. 6. Le coin des commentaires (10 min)
  9. 7. Défis perso (30 min, sans solution)
  10. 8. Les pièges classiques
  11. 9. Checklist défense : je sais expliquer…
  12. 10. Mini-oral
  13. 11. Aide-mémoire du lundi
  14. Pour aller plus loin

Objectif du jour

À la fin de la journée, tu auras une fenêtre qui affiche le terrain de Frogger : les maisons, la rivière, la berge, la route et le trottoir, avec une grenouille posée au départ.

Rien ne bouge encore. Mais tu auras compris la boucle de jeu, le cœur de tout jeu vidéo, et tu sauras dessiner sur une grille. Tout le reste de la semaine repose là-dessus.

Lien avec le cahier des charges : aucun point directement aujourd'hui, mais ce sont les fondations de tous les points.


1. Installation (15 min)

Installer les bibliothèques

Ouvre un terminal (dans Zed : Terminal → New Terminal) et tape :

python -m pip install pygame_ce
python -m pip install pygame_gui

Ce sont exactement les commandes du cours de ton prof.

Vérifier que tout marche

python -c "import pygame; print(pygame.version.ver)"

Tu dois voir une ligne qui commence par pygame-ce suivie d'un numéro de version. Si tu vois une erreur, colle-la à ton prof IA avec /bug.


2. Le Python du jour (45 min)

Ouvre un fichier essais.py dans ton éditeur et teste chaque exemple. Lance-le avec python essais.py.

2.1 Les variables et les types

Une variable est un nom qui désigne une valeur. On la crée avec =.

lives = 3              # int : un nombre entier
speed = 2.5            # float : un nombre à virgule
name = "Kermit"        # str : du texte
is_alive = True        # bool : True ou False
position = (6, 12)     # tuple : plusieurs valeurs groupées

Pour connaître le type d'une valeur : print(type(speed)) affiche <class 'float'>.

Les tuples vont te servir tout de suite : pygame les utilise partout, pour les tailles (800, 600), les positions (x, y) et les couleurs (rouge, vert, bleu). On lit une case avec son indice, qui commence à 0 : position[0] vaut 6.

Les constantes

Une valeur qui ne change jamais pendant le programme s'écrit en MAJUSCULES. Python ne l'interdit pas de la modifier, c'est une convention pour les humains qui lisent le code.

TILE = 48      # taille d'une case de la grille, en pixels
COLS = 13      # nombre de colonnes

2.2 Les opérateurs

OpérateurSensExempleRésultat
+ - *addition, soustraction, multiplication13 * 48624
/division (toujours un float)250 / 485.208…
//division entière250 // 485
%reste de la division (modulo)250 % 4810
**puissance2 ** 38

On peut aussi modifier une variable à partir de sa propre valeur : lives -= 1 est un raccourci pour lives = lives - 1. Pareil avec +=, *=…

Afficher pour comprendre : les f-strings

score = 120
print(f"Score : {score}, vies : {lives}")

Le f devant les guillemets permet de glisser des variables entre { }. Quand ton jeu fait quelque chose de bizarre, un print bien placé est ton premier outil de débogage.

2.3 Les conditions

if row == 0:
    print("Les maisons")
elif row <= 5:
    print("La rivière")
else:
    print("Ailleurs")
  • Python teste les conditions dans l'ordre et exécute seulement le premier bloc vrai. C'est pour ça que elif row <= 5 ne concerne que les lignes 1 à 5 : la ligne 0 a déjà été prise par le if.
  • Le contenu de chaque bloc est indenté (décalé de 4 espaces). L'indentation n'est pas décorative en Python : elle définit les blocs.

Les comparaisons : == (égal), != (différent), <, <=, >, >=.

On combine avec and, or, not :

if row == 0 and col % 2 == 0:
    print("Peut-être une maison")

2.4 Les boucles

while : tant que…

time_left = 3
while time_left > 0:
    print(time_left)
    time_left -= 1
print("Temps écoulé !")

La boucle tourne tant que la condition est vraie. Avec while True:, elle tourne pour toujours… et c'est exactement ce qu'on veut pour un jeu (on verra comment en sortir).

for : pour chaque…

for row in range(13):
    print(row)        # affiche 0, 1, 2, … 12
  • range(13) produit les nombres de 0 à 12 (13 non compris).
  • range(8, 12) produit 8, 9, 10, 11.

Les boucles imbriquées

Une boucle dans une boucle permet de parcourir une grille : pour chaque ligne, pour chaque colonne.

for row in range(3):
    for col in range(4):
        print(f"case ({col}, {row})")

La boucle intérieure fait tous ses tours à chaque tour de la boucle extérieure : ce code affiche 3 × 4 = 12 cases.

📚 Pour revoir ces notions : Python 1 · Chapitre 2 du cours de ton prof.


3. Échauffements (30 min)

Du Python pur, dans le terminal. Crée un fichier echauffement.py.

E1. La taille de la fenêtre

Crée les constantes TILE = 48, COLS = 13 et ROWS = 13. Calcule WIDTH et HEIGHT, la taille de la fenêtre en pixels, à partir de ces constantes (pas en écrivant 624 à la main). Affiche :

La fenêtre fait 624 x 624 pixels

Puis change TILE en 32 et relance : tout doit s'adapter tout seul.

E2. Du pixel à la case, et retour

Le joueur clique au pixel x = 250, y = 400.

  1. Dans quelle colonne et quelle ligne de la grille a-t-il cliqué ? (Réponse attendue : colonne 5, ligne 8.)
  2. Quelles sont les coordonnées en pixels du coin en haut à gauche de cette case ?
  3. Et celles de son centre ?
Réponses de E2
  1. col = x // TILE vaut 5, row = y // TILE vaut 8.
  2. (col * TILE, row * TILE) vaut (240, 384).
  3. (col * TILE + TILE // 2, row * TILE + TILE // 2) vaut (264, 408).

E3. Dans quelle zone suis-je ?

Notre terrain fait 13 lignes, numérotées de 0 (en haut) à 12 (en bas) :

LigneZone
0les maisons
1 à 5la rivière
6la berge (zone sûre au milieu)
7 à 11la route
12le trottoir de départ
  1. Avec une variable row et une suite de if / elif / else, affiche le nom de la zone. Teste avec row = 0, 3, 6, 9 et 12.
  2. Mets ce code dans une boucle for pour afficher la zone de chaque ligne, de 0 à 12.

E4. Le plateau en texte

Avant de dessiner avec pygame, dessinons avec des caractères ! Avec deux boucles imbriquées et tes conditions de E3, affiche le plateau. Chaque ligne est une chaîne de 13 caractères :

  • # pour la haie, M pour une maison (colonnes 2, 4, 6, 8 et 10 de la ligne 0)
  • ~ pour l'eau, . pour la berge, = pour la route, _ pour le trottoir
  • G pour la grenouille, en colonne COLS // 2 sur la dernière ligne

Résultat attendu :

##M#M#M#M#M##
~~~~~~~~~~~~~
~~~~~~~~~~~~~
~~~~~~~~~~~~~
~~~~~~~~~~~~~
~~~~~~~~~~~~~
.............
=============
=============
=============
=============
=============
______G______

Ce plateau en texte, c'est exactement ce qu'on va dessiner en couleurs dans quelques minutes.


4. Les fonctions pygame du jour

Le cahier des charges est clair : tu dois savoir expliquer chaque fonction pygame que tu utilises. Voici celles d'aujourd'hui.

Le repère de l'écran

En pygame, l'origine (0, 0) est en haut à gauche. x augmente vers la droite, et y augmente vers le bas (l'inverse des maths !).

(0,0) ─────────────► x
  │
  │     (x, y)
  │       ┌──────────┐
  │       │          │ hauteur
  │       └──────────┘
  │         largeur
  ▼
  y

C'est pour ça que la ligne 0 de notre grille est en haut de l'écran.

Les fonctions

FonctionCe qu'elle fait
pygame.init()Initialise tous les modules de pygame. À appeler une fois, au début.
pygame.display.set_mode((w, h))Demande au système d'exploitation une fenêtre de w × h pixels. Renvoie une Surface : l'image sur laquelle on dessine (souvent appelée screen).
pygame.display.set_caption(texte)Change le titre de la fenêtre.
pygame.time.Clock()Crée une horloge qui sert à régler la vitesse de la boucle.
clock.tick(60)Attend juste ce qu'il faut pour ne pas dépasser 60 images par seconde. Sans ça, la boucle tourne aussi vite que possible : le jeu irait plus ou moins vite selon l'ordinateur. Renvoie le temps écoulé depuis le tick précédent, en millisecondes (utile plus tard).
pygame.event.get()Vide la file d'événements (touches, clics, fermeture…) et renvoie la liste des événements arrivés depuis le dernier appel.
pygame.QUITLe type d'événement envoyé quand on ferme la fenêtre.
sys.exit()Termine le programme (module sys, à importer).
pygame.Rect(x, y, w, h)Un rectangle : position du coin en haut à gauche et taille. Il ne dessine rien tout seul ; c'est une zone. On s'en resservira pour les collisions.
pygame.draw.rect(surface, couleur, rect)Dessine le rectangle rect rempli avec couleur sur surface.
pygame.display.flip()Affiche à l'écran l'image qu'on vient de dessiner.

Pourquoi flip() ? Le double tampon

La fenêtre a deux images : celle qui est affichée, et une image cachée sur laquelle on dessine. Si on dessinait directement sur l'image affichée, le joueur verrait le dessin se faire morceau par morceau (ça clignote). On dessine donc tout sur l'image cachée, puis flip() échange les deux d'un coup.

📚 Ton prof l'explique très bien dans le Chapitre 4 de Python 1. Et toutes les fonctions sont dans la documentation de pygame-ce.


5. Le fil rouge : le terrain de jeu (1 h)

F1. La boucle de jeu

Tout jeu vidéo tourne dans une boucle qui se répète environ 60 fois par seconde. Chaque tour de boucle, c'est une image, et chaque image suit toujours les mêmes 4 temps :

  1. Attendre pour garder un rythme régulier (clock.tick)
  2. Écouter les événements (clavier, souris, fermeture)
  3. Mettre à jour l'état du jeu (positions, vies… rien aujourd'hui)
  4. Dessiner l'image, puis l'afficher (flip)

Crée un fichier frogger.py et tape (sans copier-coller) ce squelette :

import sys
import pygame

TILE = 48
COLS = 13
ROWS = 13
WIDTH = COLS * TILE
HEIGHT = ROWS * TILE

pygame.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Frogger d'entraînement")
clock = pygame.time.Clock()

while True:
    clock.tick(60)

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()

    # Le dessin viendra ici

    pygame.display.flip()

Lance-le : une fenêtre noire s'ouvre, et se ferme quand tu cliques sur la croix. 🎉

F2. Dessiner le décor

On veut dessiner une bande de couleur par ligne de la grille, en suivant les zones de E3.

Une ligne d'abord. Ajoute une couleur et dessine le trottoir (la ligne 12) :

TROTTOIR = (150, 138, 118)
    pygame.draw.rect(screen, TROTTOIR, pygame.Rect(0, 12 * TILE, WIDTH, TILE))

Lis bien chaque argument de pygame.Rect : il commence à x = 0, à la hauteur de la ligne 12, il fait toute la largeur et une case de haut.

Puis toutes les lignes. À toi : avec une boucle for row in range(ROWS) et tes conditions de E3, choisis une couleur pour chaque ligne et dessine sa bande. Choisis tes couleurs toi-même : un outil de sélection de couleur en ligne te donne les valeurs (R, G, B).

F3. Les détails : marquage, maisons et grenouille

  1. Les pointillés de la route. Entre les voies de la route (lignes 8 à 11), dessine un petit rectangle une colonne sur deux. Deux boucles imbriquées et un % !
  2. Les 5 maisons. Dans la ligne 0, dessine une case de couleur aux colonnes 2, 4, 6, 8 et 10. Trouve une formule qui donne ces colonnes à partir de i dans range(5).
  3. La grenouille. Crée deux variables frog_col = COLS // 2 et frog_row = ROWS - 1, puis dessine un carré un peu plus petit qu'une case à cette position. Change les valeurs de frog_col et frog_row : la grenouille doit se déplacer sur la grille.

Tu devrais obtenir quelque chose comme ceci (avec tes couleurs) :

Le terrain de Frogger dessiné à la fin du lundi

Une solution possible (essaie vraiment avant de regarder !)
import sys
import pygame

# Dimensions de la grille : tout le reste en découle
TILE = 48
COLS = 13
ROWS = 13
WIDTH = COLS * TILE
HEIGHT = ROWS * TILE

# Palette (R, G, B)
HAIE = (34, 70, 50)
NENUPHAR = (96, 150, 90)
EAU = (58, 104, 150)
BERGE = (118, 158, 98)
ROUTE = (52, 54, 60)
MARQUAGE = (225, 215, 150)
TROTTOIR = (150, 138, 118)
GRENOUILLE = (130, 205, 80)

pygame.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Frogger d'entraînement - Lundi")
clock = pygame.time.Clock()

frog_col = COLS // 2
frog_row = ROWS - 1

while True:
    clock.tick(60)

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()

    # Décor : chaque ligne de la grille reçoit la couleur de sa zone
    for row in range(ROWS):
        if row == 0:
            color = HAIE
        elif row <= 5:
            color = EAU
        elif row == 6:
            color = BERGE
        elif row <= 11:
            color = ROUTE
        else:
            color = TROTTOIR
        pygame.draw.rect(screen, color, pygame.Rect(0, row * TILE, WIDTH, TILE))

    # Pointillés entre les voies de la route
    for row in range(8, 12):
        for col in range(COLS):
            if col % 2 == 0:
                dash = pygame.Rect(col * TILE + 8, row * TILE - 2, TILE - 16, 4)
                pygame.draw.rect(screen, MARQUAGE, dash)

    # Les 5 maisons, régulièrement espacées dans la haie
    for i in range(5):
        col = 2 + i * 2
        pygame.draw.rect(screen, NENUPHAR, pygame.Rect(col * TILE + 4, 4, TILE - 8, TILE - 8))

    # La grenouille, placée à partir de sa case (colonne, ligne)
    margin = 8
    frog = pygame.Rect(frog_col * TILE + margin, frog_row * TILE + margin,
                       TILE - 2 * margin, TILE - 2 * margin)
    pygame.draw.rect(screen, GRENOUILLE, frog)

    pygame.display.flip()

Remarque les commentaires : un par bloc, qui dit pourquoi le bloc existe. Pas un par ligne. C'est exactement ce que demande ton prof.

Pourquoi on redessine tout à chaque image ?

Le décor ne bouge pas… alors pourquoi le redessiner 60 fois par seconde ? Parce que demain, la grenouille va bouger. Si on ne repeignait pas le décor par-dessus, on verrait toutes ses anciennes positions, comme une traînée. Redessiner toute l'image à chaque tour, c'est la base de toute animation.


6. Le coin des commentaires (10 min)

Aujourd'hui : qu'est-ce qu'un bon commentaire ?

Tout ce qui suit un # sur une ligne est un commentaire : Python l'ignore complètement. Il est écrit pour des humains : ton binôme, ton correcteur, et toi-même dans deux semaines.

Ton prof est très clair dans le cahier des charges : un code commenté à chaque ligne n'est pas un code valable. Un commentaire décrit l'intention d'une portion de code ; il ne traduit pas le code en français.

Le test à faire pour chaque commentaire :

Si je supprime ce commentaire, est-ce que quelqu'un qui connaît Python perd une information ?

Si la réponse est non, le commentaire est inutile.

❌ Inutile : il répète ce que le code dit déjà.

margin = 8  # la marge vaut 8

✅ Utile : il dit à quoi sert le bloc, ce qu'on ne voit pas en lisant les lignes une par une.

# La grenouille, placée à partir de sa case (colonne, ligne)
margin = 8
frog = pygame.Rect(frog_col * TILE + margin, frog_row * TILE + margin,
                   TILE - 2 * margin, TILE - 2 * margin)
pygame.draw.rect(screen, GRENOUILLE, frog)

Exercice

Ce code est sur-commenté. Réécris-le en ne gardant que ce qui apporte une information (indice : un seul commentaire suffit).

# on fait une boucle sur les lignes
for row in range(ROWS):
    # si row vaut 0
    if row == 0:
        color = HAIE  # la couleur est HAIE
    # sinon si row est plus petit ou égal à 5
    elif row <= 5:
        color = EAU  # couleur de l'eau
    else:
        color = ROUTE
    # on dessine un rectangle
    pygame.draw.rect(screen, color, pygame.Rect(0, row * TILE, WIDTH, TILE))
Une version possible
# Décor : chaque ligne de la grille reçoit la couleur de sa zone
for row in range(ROWS):
    if row == 0:
        color = HAIE
    elif row <= 5:
        color = EAU
    else:
        color = ROUTE
    pygame.draw.rect(screen, color, pygame.Rect(0, row * TILE, WIDTH, TILE))

Puis relis ton propre frogger.py : au plus un commentaire par bloc, qui dit à quoi sert le bloc.


7. Défis perso (30 min, sans solution)

C'est ici que ton Frogger commence à devenir le tien. Fais tes propres choix, et sois prêt à les expliquer.


8. Les pièges classiques

SymptômeCause probable
La fenêtre s'ouvre et se ferme aussitôtIl manque la boucle while True:, ou le dessin n'est pas indenté dedans.
La fenêtre « Ne répond pas »pygame.event.get() n'est pas appelé à chaque tour de boucle.
La fenêtre reste noireIl manque pygame.display.flip(), ou il est en dehors de la boucle.
Les objets laissent une traînéeOn ne repeint pas le fond avant de redessiner.
ModuleNotFoundError: No module named 'pygame'pygame-ce n'est pas installé pour ce Python. Utilise bien python -m pip install.
IndentationErrorMélange d'espaces et de tabulations, ou bloc mal aligné.
Un if qui ne fait jamais rienUn if précédent dans la même chaîne if / elif a déjà « attrapé » le cas. L'ordre compte !

9. Checklist défense : je sais expliquer…


10. Mini-oral

Réponds à voix haute, puis vérifie. Mieux : tape /oral dans ton IA.

1. Que fait clock.tick(60) ? Que se passerait-il sans ?

Il limite la boucle à 60 tours (images) par seconde en attendant le temps nécessaire. Sans lui, la boucle tourne aussi vite que l'ordinateur le permet : le jeu irait plus vite sur un ordinateur puissant et consommerait 100 % du processeur.

2. À quoi sert pygame.display.flip() ?

On dessine sur une image cachée ; flip() l'échange avec l'image affichée. Le joueur voit l'image complète d'un coup, sans clignotement.

3. Pourquoi redessiner tout le décor à chaque image ?

Pour effacer l'image précédente. Sinon, tout ce qui bouge laisserait une traînée de ses anciennes positions.

4. Le pixel (250, 400) est dans quelle case si TILE = 48 ?

Colonne 250 // 48 = 5, ligne 400 // 48 = 8. La division entière donne le numéro de la case.

5. Pourquoi faut-il appeler pygame.event.get() même si on ne gère que la fermeture ?

Le système d'exploitation envoie des messages à la fenêtre et attend qu'ils soient lus. Si la file n'est jamais vidée, il considère que le programme est bloqué (« Ne répond pas »).

6. Que se passe-t-il si je change TILE de 48 à 32 ?

Tout s'adapte : la taille de la fenêtre, des bandes, des maisons et de la grenouille, puisque tout est calculé à partir de TILE. C'est tout l'intérêt des constantes.


11. Aide-mémoire du lundi

# Variables et types
n = 3; v = 2.5; s = "texte"; ok = True; pos = (6, 12)

# Opérateurs de grille
col = x // TILE          # pixel -> case
x = col * TILE           # case -> pixel (coin haut gauche)
col % 2 == 0             # une colonne sur deux

# Conditions
if a == b and not c:
    ...
elif d <= e:
    ...
else:
    ...

# Boucles
while condition:
    ...
for i in range(5):       # 0, 1, 2, 3, 4
    ...
for row in range(ROWS):  # grille
    for col in range(COLS):
        ...

# Squelette pygame
pygame.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
clock = pygame.time.Clock()
while True:
    clock.tick(60)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()
    pygame.draw.rect(screen, (R, G, B), pygame.Rect(x, y, w, h))
    pygame.display.flip()

Pour aller plus loin

Demain, mardi : les fonctions, le clavier, et la grenouille fait son premier saut 🐸

Du nouveau dans le cours

Petite rectification

Il manquait une étape au cours : comprendre ce qu'est un jeu vidéo avant de le coder. Une nouvelle section t'explique la boucle de jeu et le plan __init__ / process_events / update / draw que suivront tous les éléments de ton Frogger.