Microbit Snake

Aide le serpent à manger son plat favoris, les pommes ! Pour l’aider, tu vas devoir coder le célèbre jeu snake. 🍎🐍

Code à compléter

Le jeu de Snake

Le but de cet exercice est de coder le célèbre jeu Snake sur une carte micro:bit.

Principe du jeu

Le serpent

Dans Snake, le joueur contrôle un serpent dans une zone quadrillée. Le serpent peut bouger dans les quatre directions (haut, bas, gauche et droite) et réapparaît de l’autre côté quand il rentre dans un mur. Le but du jeu est de survivre le plus longtemps possible.

Les pommes

Pendant la partie, des pommes vont apparaître à des endroits aléatoires sur l’écran, représentées sous la forme de simples pixels. Quand le serpent mange une pomme (c’est-à-dire quand la tête du serpent arrive sur une pomme), il grandit d’une case, et une nouvelle pomme apparaît sur l’écran.

Sur notre micro:bit, ça ressemble à ça :

On distingue que la tête du serpent (entourée en blanc) est plus lumineuse que le corps. On voit aussi une pomme qui est entourée en vert.

Fin de la partie

La partie s’arrête quand le serpent se mord la queue (c’est-à-dire quand la tête du serpent arrive sur une case de son corps). Le score du joueur est la taille du serpent. En général, on considère la partie comme gagnée si le score est égal au nombre de pixels sur l’écran (ça veut dire que le serpent a complètement rempli l’écran).

Notions

Dans ce TP tu apprendras deux nouvelles notions un peu complexes mais très utile : les fonctions et les tuples.

On te le répètera tout au long du TP, mais n’hésite surtout pas à appeler un organisateur en cas de besoin, que ce soit pour corriger les erreurs de ton code, te réexpliquer une ancienne notion ou même pour t’expliquer plus en détail les fonctions et les tuples si tu n’as pas compris.

Passe à la section suivante pour apprendre comment utiliser ton micro:bit !

Fonctionnement de la carte micro:bit

Petit rappel

Même si maintenant tu dois quasiment toutes les connaître, faisons un petit rappel sur les fonctions de base utiles pour manipuler le micro:bit.

L’écran

Les fonctions suivantes te seront utiles pour jouer avec l’écran :

    
1
display.set_pixel(0, 2, 6)
2
display.clear()
3
display.scroll(message)
Allume le pixel sur la 1ère colonne et 3ème ligne avec une intensité de 6
Éteint tous les pixels de l’écran
Fait défiler la chaîne de caractères message
Appuie sur Run pour lancer le code :

        

    

Les boutons

Les boutons nous seront utiles pour faire tourner le serpent. Lorsque l’on appuiera sur le bouton A, on voudra faire tourner dans le sens anti-horaire, tandis que lorsque l’on appuiera sur le bouton B, on fera tourner le serpent dans le sens horaire.

    
1
2
button_a.is_pressed()
button_b.is_pressed()
3
4
button_a.was_pressed()
button_b.was_pressed()
5
6
button_a.get_presses()
button_b.get_presses()
Renvoie True ou False si les boutons sont appuyés au moment où la ligne est exécutée par le micro:bit
Renvoie True ou False si les boutons ont été appuyés depuis le dernier appel de ces fonctions
Renvoie le nombre d’appuis effectués sur le bouton depuis le dernier appel de ces fonctions
Appuie sur Run pour lancer le code :

        

    

Si tu veux t’amuser à tester la fonction idéale à utiliser pour le déplacement fais toi plaisir. Sinon, clique sur la bande noire ci-dessous pour voir celle qu’on utilisera.

La fonction idéale pour le déplacement sera la fonction `was_pressed()`.

C’est parti !

Les fonctions

Tu peux commencer à coder en téléchargeant le code à compléter (tout en haut de la page). Celui-ci est composé de plusieurs fonctions à compléter, ainsi que de la boucle principale de jeu (qui commence à la ligne while longueur_serpent < 25:).

On mettra dans la boucle du jeu les actions qu’il faudra effectuer tant que la partie n’est pas finie : déplacer le serpent, placer une pomme sur le terrain, etc.

Attention, les pass dans les fonctions sont à enlever une fois la fonction completée.

Mais qu’est ce qu’une fonction ?

Une fonction est un bout de programme qui effectue une action, et que l’on va pouvoir utiliser plusieurs fois.

Pour créer une fonction, il faut 5 éléments :

  • le mot-clé def
  • le nom de la fonction
  • des parenthèses
  • deux points (:)
  • une indentation à la suite

Voici un exemple de déclaration de fonction : def hello_world():.

L’indentation est l’espace que l’on mets devant une parti de code pour le considérer dans un bloc. N’hésite pas à appeler un organisateur si tu n’est plus sûre de ce que c’est.

Prenons un exemple:

Appuie sur le bouton Run pour exécuter le code python ci-dessous
Le résultat :

        

    

Les fonctions sont très utiles et utilisées car elles peuvent aussi prendre des paramètres et renvoyer une valeur.

Les paramètres : à l’intérieur des parenthèses qui suivent le nom de la fonction, on peut mettre un ou plusieurs paramètres qui seront utilisés comme des variables dans la fonction. Le résultat de la fonction peut dépendre ainsi des paramètres donnés.

Le return: ce mot-clé se trouve à la fin d’une fonction et permet de renvoyer une valeur.

Appuie sur le bouton Run pour exécuter le code python ci-dessous
Le résultat :

        

    

Analysons ensemble le code ci-dessus (n’hésite pas à l’exécuter avant pour bien comprendre) :

    
1
def puissance_2(nombre):
2
    carre = nombre * nombre
3
    return carre
4
resultat = puissance_2(5)
5
print(resultat)
On définit notre fonction qui prend un paramètre nombre
On utilise nombre pour effectuer un calcul
On renvoie la valeur de carre
On appelle puissance_2 avec 5 comme paramètre
On affiche la valeur renvoyée par la fonction
Appuie sur Run pour lancer le code :

        

    

Et voilà, tu sais tout ce qu’il a à savoir sur les fonctions pour faire ton Snake ! Si tu n’as pas compris quelque chose ou que tu n’es pas sûre d’avoir tout compris, n’hésite pas à appeler un organisateur.

Notre version de Snake sur micro:bit

Le serpent

Création

Dans notre code, nous allons représenter le serpent comme une liste de coordonnées sur l’écran. Ces coordonnées sont composées de 2 valeurs : une position sur l’axe X et une autre sur l’axe Y. Pour pouvoir regrouper les coordonnées entre elles, nous utiliserons les tuples.

Le pixel aux coordonnées (2, 4) est allumé

Le pixel aux coordonnées (2, 4) est allumé

Sur le micro:bit, on représente l’axe X à l’horizontal et l’axe Y à la verticale. Le pixel en haut à gauche est aux coordonnées (0, 0).

Les tuples en bref

Un tuple c’est un couple de valeurs. Nous allons alors avoir deux valeurs assignées à une seule variable, comme une petite liste de deux éléments. Comme toujours, un petit exemple ne fait jamais de mal :

    
1
mon_tuple = (1, 2)
2
print(mon_tuple)
3
print(mon_tuple[0])
4
5
x = mon_tuple[1]
print(x)
6
7
mon_tuple = (9, 4)
print(mon_tuple)
Création du tuple
Affiche : (1, 2)
Affiche : 1
Affiche : 2
Affiche : (9, 4)
Appuie sur Run pour lancer le code :

        

    

Attention, tu ne peux pas modifier une seule valeur d’un tuple !

Appuie sur le bouton Run pour exécuter le code python ci-dessous
Le résultat :

        

    

Notre serpent est donc une liste de tuples de nombres entiers, où chaque tuple donne les coordonnées d’une partie du corps du serpent. On a donc les coordonnées de la tête au début de la liste, et les coordonnées de la queue ensuite.

1
2
serpent = [(2, 2), (2, 3), (3, 3), (3, 4)]
longueur_serpent = 4 # Le serpent a une taille de 4 cases

L’exemple ci-dessus correspond au serpent sur l’image suivante (la tête est le pixel le plus lumineux en coordonnées (2, 2)).

Mission 1 : As-tu tout compris ?

Tout ce que tu as à faire dans cette partie est de t'assurer que tu as bien tout compris sur ce que l'on t'a expliqué précédemment. N'oublie pas de lire le code fourni aussi. Il n'y a pas grand chose mais assure toi de bien comprendre ce que chaque partie fait et fera.

Si tu n’es pas sûre, n’hésite pas à demander à un organisateur.

Direction

Passons donc aux déplacements du serpent. Pour cela, il faut savoir dans quelle direction il va. C’est à ça que sert la variable direction que l’on initialise par défaut à HAUT dans le code donné. Au début de la partie, le serpent ira donc vers le haut.

Rappel

Pour rappel, nous souhaitons diriger le serpent avec les boutons A et B du micro:bit de la façon suivante :

  • si l’on appuie sur A, le serpent tourne dans le sens anti-horaire
  • si l’on appuie sur B, il tourne dans le sens horaire
  • sinon, le serpent ne change pas de direction

Mission 2 : Haut, droit, bas, gauche… Quel sera ton choix ?

Implémente la fonction nouvelle_direction() qui :

  1. prend en paramètre la direction actuelle du serpent
  2. vérifie si les boutons ont été pressés
  3. renvoie la nouvelle direction du serpent

Pour cela, tu peux t’aider des variables définies au début du ficher :

1
2
3
4
5
# Directions
HAUT = 0
DROITE = 1
BAS = 2
GAUCHE = 3

Tu peux utiliser des conditions ou t’aider de modulos pour connaître la prochaine direction ! Si tu te demandes ce qu’est un modulo, c’est simplement le reste d’une division.

Prenons un exemple, lorsqu’on divise 13 par 5 on obtient 2 au quotient et il nous reste 3. Ainsi le modulo de 13 par 5 est 3. En Python, cela ressemblerait à ça :

Appuie sur le bouton Run pour exécuter le code python ci-dessous
Le résultat :

        

    

Si la notion n’est pas encore claire pour toi tu peux essayer de dessiner un schéma de l’exemple ci dessus ou appeler un organisateur.

Déplacement

Après avoir trouvé la direction du serpent, il faut le déplacer. Imaginons que dans l’exemple précédent, le serpent aille vers la gauche. Après s’être déplacé, l’écran ressemblera à l’image suivante.

Avant déplacement

Avant déplacement

Après déplacement

Après déplacement

Comme tu peux le voir sur l’image, la tête du serpent s’est déplacée d’une case vers la gauche, et le bout de la queue du serpent a disparu !

Mission 3 : Une nouvelle position ?

Implémente la fonction nouvelle_position_tete() qui :

  1. prend en paramètres le serpent et sa direction actuelle
  2. renvoie les coordonnées de sa nouvelle tête

Attention : Si le serpent arrive contre le bord, il passe de l’autre côté de l’écran !

Le coeur du code

Maintenant que les fonctions nouvelle_direction() et nouvelle_position_tete() fonctionnent, tu peux les appeler dans la boucle principale du jeu. La première étape est de mettre à jour la direction du serpent. Après ça, tu vas devoir trouver la nouvelle tête du serpent pour l’insérer au début de ta liste.

Pour finir, il faut supprimer le dernier élément de la liste à condition que la longueur de la liste, qui représente le serpent, soit plus grande que longueur_serpent.

Pour insérer la nouvelle tête dans la liste du serpent en première place, tu peux utiliser la fonction insert() :

Appuie sur le bouton Run pour exécuter le code python ci-dessous
Le résultat :

        

    

Tu peux utiliser la méthode suivante pour retirer le dernier élément d’une liste :

Appuie sur le bouton Run pour exécuter le code python ci-dessous
Le résultat :

        

    

Mission 4 : Mise en commun

Maintenant que tu as tous les outils en main, mets à jour la boucle principale pour que ton serpent puisse bouger librement.

À cette étape, tu devrais être capable de faire bouger ton serpent sur le micro:bit en appuyant sur les boutons ! Mais il n’y a pas encore de challenge car le serpent ne grandit pas encore.

Un p’tit bilan ?

Avant de passer à la prochaine partie, assure toi bien que les précédentes étapes sont bien implémentées. Ton serpent doit :

  • Avancer tout seul, d’une case toute les demi-secondes (sleep(500))
  • S’il touche un mur, se retrouver de l’autre côté de l’écran
  • Tourner dans le bon sens lorsqu’on appuie sur le bouton A ou le bouton B

N’hésite pas à interpeler un organisateur si tu veux t’assurer que ton jeu marche bien ou si tu as un quelconque problème.

La pomme

Maintenant que le serpent peut se déplacer, nous pouvons placer des pommes sur le terrain pour le faire grandir.

À chaque tour de boucle :

  • S’il n’y a pas de pomme sur le terrain, on en place une de manière aléatoire qui ne soit pas sur le serpent. Pour cela, on choisit aléatoirement deux nombres X et Y, compris entre 0 et 4, et si le tuple (X, Y) ne fait pas partie du serpent, on y ajoute la pomme. Sinon, on recommence le choix de la position.
  • Si la tête du serpent atteint une pomme, celle-ci disparait et la taille du serpent augmente de 1.

Un peu de challenge ?

Pour pimenter un peu le jeu, nous te mettons au défi de chercher sur Internet :

  • Comment créer un nombre aléatoire en Python (pour créer les nouvelles coordonnées de la pomme).

  • Comment vérifier si un élément est présent dans une liste en Python (pour savoir si ta nouvelle pomme n’est pas dans le serpent).

Si tu ne trouves pas ou que tu veux rester concentrée sur le TP, tu peux aller voir dans la partie Astuces (dans la prochaine section) pour savoir comment générer un nombre aléatoire et comment vérifier si des coordonnées (X, Y) sont présentes dans une liste.

Mission 5 : Abracadabra, les pommes, me voilà

On arrive à la dernière étape avant que ton jeu corresponde totalement au Snake original ! Implémente l'apparition des pommes et ajoute la possibilité qu'elles se fassent manger pour que le serpent augmente de taille.

Conclusion

À ce point, ton jeu Snake devrait être fonctionnel. Bien joué ! Tu peux essayer ton jeu pour atteindre le score maximal ! Si c’est trop simple, tu peux augmenter la vitesse de déplacement du serpent en mettant un plus petit nombre dans l’instruction sleep().

Astuces (utiles pour certaines parties du projet)

On peut vérifier qu’une valeur est présente dans une liste de la manière suivante :

Appuie sur le bouton Run pour exécuter le code python ci-dessous
Le résultat :

        

    

Pour choisir aléatoirement un nombre entier, tu peux utiliser la fonction randint (tu peux appuyer plusieurs fois sur Run du sujet pour constater que le nombre est bien aléatoire) :

Appuie sur le bouton Run pour exécuter le code python ci-dessous
Le résultat :

        

    

En savoir plus

Dans le code fourni, la ligne suivante permet de vérifier si le serpent se mord la queue :

1
if serpent[0] in serpent[1:]:

Lorsqu’on écrit ma_liste[x:], on crée la sous-liste de ma_liste qui commence à l’index x. Tu peux vérifier ce fonctionnement avec le code suivant :

Appuie sur le bouton Run pour exécuter le code python ci-dessous
Le résultat :

        

    

Tu peux aussi le faire dans l’autre sens d’ailleurs :

Appuie sur le bouton Run pour exécuter le code python ci-dessous
Le résultat :

        

    

Si tu as d’autres questions sur la manière de comment fonctionne le slicing, n’hésite pas à demander à un organisateur.

Retour au Menu