Guirlande
Une guirlande est une rangée de lumières qui s'allument et s'éteignent selon un motif répétitif. Dans ce projet, la grille n'a qu'une seule ligne.
Installer metagrid dans le terminal : uv add metagrid
Crée un fichier guirlande.py avec ce squelette :
"""
Guirlande
Contrôler le temps grâce au modulo.
"""
import metagrid
NB_COLONNES = 20
NB_LIGNES = 1
TAILLE_CASE = 60
COULEUR_ALLUMEE = "#FFDD00"
COULEUR_ETEINTE = "#222222"
grille: list[list[bool]]
guirlande: list[bool] # alias de grille[0]
jeu: metagrid.AbstractEngine
def init():
global grille, guirlande
guirlande = []
for _ in range(NB_COLONNES):
guirlande.append(False)
grille = [guirlande]
def update():
global guirlande
pass
def draw():
global guirlande
pass
if __name__ == "__main__":
jeu = metagrid.create(NB_LIGNES, NB_COLONNES, TAILLE_CASE, 4)
jeu.on_init(init)
jeu.on_update(update)
jeu.on_draw(draw)
jeu.start()
Étape 1 - La guirlande
Une grille à une seule ligne
La grille ne contient qu'une liste. guirlande = grille[0] est un alias : c'est un autre nom pour désigner la même liste. Modifier guirlande[3] modifie aussi grille[0][3].
- Combien de lignes a la grille ? Combien de colonnes ?
- Que vaut
guirlande[0]aprèsinit? Etguirlande[19]? - Quelle instruction allume la lampe d'indice 4 ?
Étape 2 - Afficher la guirlande
Puisqu'il n'y a qu'une seule ligne, i vaut toujours 0 dans set_cell_color. La boucle ne porte que sur j.
Fonction draw
Complétez draw pour colorier chaque lampe selon son état :
def draw():
global guirlande
for j in range(NB_COLONNES):
if guirlande[j]:
jeu.set_cell_color(0, j, ...)
else:
jeu.set_cell_color(0, j, ...)
Dans update, allumez uniquement la lampe 0 pour tester :
Lancez le programme. Vous devez voir une seule lampe allumée à gauche.
Étape 3 - Allumer des lampes précises
Lampes individuelles
Dans update, allumez les lampes aux indices 0, 5, 10 et 15 en quatre instructions. Toutes les autres restent éteintes.
def update():
global guirlande
for j in range(NB_COLONNES):
guirlande[j] = False
guirlande[0] = ...
guirlande[5] = ...
guirlande[10] = ...
guirlande[15] = ...
Que remarquez-vous sur les indices 0, 5, 10, 15 ? Quel est l'écart entre eux ?
Toutes les lampes
Modifiez update pour allumer toutes les lampes en utilisant une boucle for.
Toutes les lampes éteintes
Modifiez update pour éteindre toutes les lampes. Combien d'instructions faut-il ?
Étape 4 - Le modulo et le quotient
L'opérateur % donne le reste de la division entière. 7 % 3 vaut 1 car 7 = 2×3 + 1.
L'opérateur // donne le quotient entier. 7 // 3 vaut 2.
Calculer
Modulo à la main
Calculez à la main, puis vérifiez dans l'interpréteur :
| Expression | Résultat |
|---|---|
4 % 2 |
? |
5 % 2 |
? |
9 % 3 |
? |
10 % 3 |
? |
11 % 3 |
? |
0 % 5 |
? |
7 % 5 |
? |
20 % 20 |
? |
21 % 20 |
? |
Quotient entier à la main
Calculez à la main, puis vérifiez dans l'interpréteur :
| Expression | Résultat |
|---|---|
6 // 3 |
? |
7 // 3 |
? |
8 // 3 |
? |
9 // 3 |
? |
5 // 2 |
? |
1 // 5 |
? |
9 // 10 |
? |
Tables croisées
Complétez pour j de 0 à 11 :
j |
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
j % 4 |
? | ? | ? | ? | ? | ? | ? | ? | ? | ? | ? | ? |
j // 4 |
? | ? | ? | ? | ? | ? | ? | ? | ? | ? | ? | ? |
- Que représente
j % 4visuellement ? (indice : imaginez les 12 lampes découpées en groupes de 4) - Que représente
j // 4? - Pour une lampe
jquelconque, si on connaîtj // 4etj % 4, peut-on retrouverj?
Prédire des motifs
Pour chaque question, prédisez quelles lampes sont allumées sur 12 lampes (j = 0 à 11), puis vérifiez dans le programme.
Motifs avec %
| Condition | Lampes allumées (parmi 0..11) |
|---|---|
j % 2 == 0 |
? |
j % 2 == 1 |
? |
j % 4 == 0 |
? |
j % 4 == 3 |
? |
j % 3 < 2 |
? |
j % 5 < 3 |
? |
j % 6 < 1 |
? |
Motifs avec //
| Condition | Lampes allumées (parmi 0..11) |
|---|---|
j // 4 == 0 |
? |
j // 4 == 1 |
? |
j // 4 % 2 == 0 |
? |
j // 3 % 2 == 0 |
? |
Pour la dernière ligne : que vaut j // 3 pour j = 0, 1, 2 ? Pour j = 3, 4, 5 ? Quel motif obtient-on ?
Construire des motifs
Écrire la condition
Pour chaque motif ci-dessous, écrivez la condition guirlande[j] = (...) qui le produit. Testez dans le programme.
- Lampes allumées : 0, 3, 6, 9
- Lampes allumées : 1, 4, 7, 10
- Lampes allumées : 0, 1, 4, 5, 8, 9 (groupes de 2 allumées, 2 éteintes)
- Lampes allumées : 0, 1, 2, 6, 7, 8 (2 blocs de 3)
- Lampes allumées : 2, 3, 6, 7, 10, 11 (2 dernières de chaque groupe de 4)
Motif symétrique
On veut allumer la première et la dernière lampe de chaque groupe de 6 : lampes 0, 5, 6, 11, 12, 17, 18.
- Que vaut
j % 6pour chacune de ces lampes ? - Écrivez la condition.
Étape 5 - Motifs périodiques
Une lampe sur deux
Complétez update pour allumer toutes les lampes paires (indices 0, 2, 4, 6...) :
Puis modifiez pour allumer les lampes impaires (indices 1, 3, 5...).
Une lampe sur trois
Allumez les lampes 0, 3, 6, 9, 12, 15, 18.
Décaler le motif
- Allumez les lampes 1, 4, 7, 10, 13, 16, 19. Quelle condition faut-il utiliser ?
- Allumez les lampes 2, 5, 8, 11, 14, 17. Quelle condition ?
Groupes
L'expression j % 5 < 2 vaut True quand le reste de la division par 5 est 0 ou 1.
- Pour quels indices
j % 5 < 2est-ilTrue? - Décrivez le motif obtenu : combien de lampes allumées ? combien d'éteintes ? dans quel ordre ?
- Modifiez pour avoir 3 lampes allumées suivies de 2 éteintes.
Étape 6 - Animation
jeu.frame_no s'incrémente automatiquement de 1 à chaque frame.
Une lumière qui fait le tour
jeu.frame_no % len(guirlande) donne l'indice de la lampe à allumer à chaque frame.
Complétez update pour qu'une seule lampe soit allumée à la fois, et qu'elle avance d'une position à chaque frame :
def update():
global guirlande
for j in range(NB_COLONNES):
guirlande[j] = (j == jeu.frame_no % ...)
- À la frame 0, quelle lampe est allumée ? À la frame 1 ? À la frame 20 ?
- Pourquoi la lumière repart-elle au début après la dernière lampe ?
- Utilisez
jeu.frame_no // 5à la place dejeu.frame_nopour ralentir. Que change// 5?
Décaler avec frame_no
Remplacez j % 3 == 0 par (j + jeu.frame_no) % 3 == 0 :
def update():
global guirlande
for j in range(NB_COLONNES):
guirlande[j] = ((j + jeu.frame_no) % 3 == 0)
- Que se passe-t-il ?
- À la frame 0, quelles lampes sont allumées ? À la frame 1 ? À la frame 3 ?
- Pourquoi le motif revient-il au même état toutes les 3 frames ?
Ralentir avec la division entière
L'opérateur // donne la division entière : 7 // 3 vaut 2.
jeu.frame_no |
jeu.frame_no // 10 |
|---|---|
| 0 | ? |
| 5 | ? |
| 9 | ? |
| 10 | ? |
| 19 | ? |
| 20 | ? |
jeu.frame_no // 10ne change de valeur que toutes les combien de frames ?- La valeur change donc combien de fois par seconde ?
Appliquer le ralentissement
Remplacez jeu.frame_no par jeu.frame_no // 10 dans update et observez.
Que se passe-t-il si on utilise // 5 ? // 30 ?
Inverser le sens
Pour faire défiler le motif dans l'autre sens, remplacez + par - dans (j + jeu.frame_no // 10) % 3 == 0.
Expliquez pourquoi cela inverse la direction.
Pour aller plus loin
- Plusieurs couleurs : au lieu d'un booléen, calculer
(j + jeu.frame_no // 10) % 3et choisir une couleur selon que le résultat vaut 0, 1 ou 2. Il faudra changerguirlandeenlist[str]. - Vitesse variable : stocker la vitesse dans une variable entière et la modifier avec les touches
+et-. - Motif symétrique : allumer les lampes telles que
j % 6 == 0ouj % 6 == 5(les bords de chaque groupe de 6). Quel motif obtient-on ?