Pico Simon

Pour ce dernier article de l’année, je vous propose un petit jeu. Il s’agit d’un grand classique que vous pouvez très facilement reproduire (à condition bien sûr de posséder les cartes Ludik Hat et PicoHat). Je ne reviendrai pas sur la programmation du Raspberry Pico ou des composants du Ludik Hat puisque j’en ai parlé en détail fin septembre.

 les cartes Ludik Hat et PicoHat

Le jeu Simon

Il suffit de reproduire la suite de note jouée. Au début, c’est très facile, mais à chaque tour, le jeu ajoute une note. Si vous vous trompez ou hésitez trop longtemps, vous avez perdu. Voilà une des publicités de l’époque :

Fabriquer votre Simon

Dans les années 1980, il n’y avait pas d’Arduino, il aurait été difficile pour un particulier de reproduire le jeu. Mais à notre époque, les composants nécessaires sont disponible pour quelques euros seulement (microcontrôleur, buzzer, LED, boutons). Voilà un exemple de jeu Simon fabriqué avec un Arduino. Si cela vous intéresse j’explique tout ça dans mon livre.

Jeu Simon avec un Arduino

Le Ludik Hat

Avec le Ludik Hat, c’est encore plus facile puisqu’il intègre presque tout les composants nécessaires et que les boutons sont parfaitement placés en face des LED (c’est une coïncidence ou c’est fait exprès ?). Il manque juste le microcontrôleur, mais il suffit de relier la carte au PicoHat (ou d’adapter le programme au Raspberry Pi).

Connectez ensemble les 2 éléments (PicoHat et Ludik Hat), lancez Thonny, copiez le code ci dessous dans le fichier main.py, ajoutez les bibliothèques mcp3008.py et neopixel.py et enfin cliquez sur le triangle vert (Exécuter le script courant).

# Appel des bibliothèques
from machine import Pin, PWM, SPI
from time import sleep, ticks_ms
from mcp3008 import MCP3008
from random import randint
from neopixel import Neopixel
# Conversion des numéro de Pin du Pico en numéro de GPIO
GPIO = [None,None,8,9,2,3,14,10,5,4,7,6,20,21,0,1,16,17,18,19,27,28,22,11,12,13,26,15]
# Configuration du bus SPI
spi = SPI(0, sck=Pin(GPIO[11]),mosi=Pin(GPIO[10]),miso=Pin(GPIO[9]), baudrate=100000)
analog = MCP3008(spi, Pin(GPIO[8], Pin.OUT))
# Définition des éléments reliés aux ports du Pico
ledNeopixels = Neopixel(4, 0, GPIO[18], "GRB")
BUZZER = PWM(Pin(GPIO[13]))
BOUTON1 = Pin(GPIO[22], Pin.IN, Pin.PULL_UP)
BOUTON2 = Pin(GPIO[23], Pin.IN, Pin.PULL_UP)
BOUTON3 = Pin(GPIO[24], Pin.IN, Pin.PULL_UP)
BOUTON4 = Pin(GPIO[25], Pin.IN, Pin.PULL_UP)
LED1 = Pin(GPIO[12], Pin.OUT)
LED2 = Pin(GPIO[26], Pin.OUT)
LED3 = Pin(GPIO[27], Pin.OUT)
LED4 = Pin(GPIO[6], Pin.OUT)
# Réglage du score
NIVEAU1 = 5 # 5 bonnes notes
NIVEAU2 = 10 # 10 bonnes notes
NIVEAU3 = 15 # 15 bonnes notes
NIVEAU4 = 20 # 20 bonnes notes
note = [440, 330, 262, 165]
suiteDeNotes = []
resultatBouton = 0

# Animations
def allumeUneLed(numeroLed):
    if numeroLed == 0:
        LED1.value(1)
    elif numeroLed == 1:
        LED2.value(1)
    elif numeroLed == 2:
        LED3.value(1)
    else:
        LED4.value(1)

def toutesLesLed(etat):
    LED1.value(etat)
    LED2.value(etat)
    LED3.value(etat)
    LED4.value(etat)
   
def play(n, d, *p):
    BUZZER.duty_u16(1000 - round(analog.read(3) * 1000 / 1024))
    BUZZER.freq(n)
    sleep(d)
    BUZZER.duty_u16(0)
    if p == ():
        sleep(d)
    else:
        sleep(*p) 

def animationDebut():
    duree = 0.2
    toutesLesLed(0)
    sleep(duree)
    LED1.value(1)
    play(note[0], duree)    
    LED2.value(1)
    play(note[1], duree)    
    LED3.value(1)
    play(note[2], duree)    
    LED4.value(1)
    play(note[3], duree)        
    sleep(duree * 5)
    toutesLesLed(0)
    sleep(duree * 2.5)

def animationGagne():
    duree = 0.05
    toutesLesLed(1)
    play(294, duree)
    play(294, duree * 3)
    play(294, duree)
    toutesLesLed(0)
    play(392, duree * 4)
    toutesLesLed(1)
    play(392, duree * 4)
    toutesLesLed(0)
    play(440, duree * 4)
    toutesLesLed(1)
    play(440, duree * 4)
    toutesLesLed(0)
    play(587, duree * 6)
    toutesLesLed(1)
    play(494, duree * 2)    
    play(392, duree * 3, duree * 4)
    toutesLesLed(0)    
    play(392, duree)
    play(494, duree * 3)
    play(392, duree)
    toutesLesLed(1)    
    play(330, duree * 4)
    toutesLesLed(0)    
    play(523, duree * 8, duree * 5)
    toutesLesLed(1)
    sleep(duree * 4)
    toutesLesLed(0)    
    play(440, duree * 3)
    play(370, duree)
    toutesLesLed(1)
    play(392, duree * 8)
    sleep(duree * 4)
    toutesLesLed(0)

def animationPerdu():
    duree = 0.2
    toutesLesLed(1)
    sleep(duree)
    toutesLesLed(0)
    sleep(duree)
    toutesLesLed(1)
    sleep(duree * 4)
    LED1.value(0)
    play(277, duree * 4, 0)   
    LED2.value(0)
    play(247, duree * 4, 0) 
    LED3.value(0)
    play(233, duree * 4, 0) 
    LED4.value(0)
    play(220, duree * 8, 0) 
    sleep(duree * 4)

# Autres fonctions
def jouerNote(n):
    duree = 0.25
    allumeUneLed(n)
    play(note[n], duree)
    toutesLesLed(0)
    sleep(duree)
    
def lireBouton(parametre):
    global resultatBouton
    resultatBouton = parametre
    ledAllumee = 0
    temps = ticks_ms()
    while resultatBouton > 3 and resultatBouton < 7:
        if BOUTON1.value()==False:
            resultatBouton = 0
        elif BOUTON2.value()==False:
            resultatBouton = 1
        elif BOUTON3.value()==False:
            resultatBouton = 2
        elif BOUTON4.value()==False:
            resultatBouton = 3
        elif resultatBouton == 4 and (ticks_ms() - temps) >= 3000:
            resultatBouton = 9
        elif resultatBouton == 6 and (ticks_ms() - temps) >= 1500:
            toutesLesLed(0)
            if ledAllumee > 3:
                ledAllumee = 0
            allumeUneLed(ledAllumee)
            ledAllumee = ledAllumee + 1
            temps = ticks_ms()
        sleep(0.01)

while True:
    # Attend l'appui sur un bouton sans récupérer sa valeur
    lireBouton(6)
    # Démarrage de la nouvelle partie
    animationDebut()
    score = 0
    finPartie = 0
    while finPartie == 0:
        if len(suiteDeNotes) == NIVEAU4:
            finPartie = 1
            animationGagne()
            score = 1
            break
        # Tirage au sort d'une nouvelle note de 0 à 3 (4-1)
        suiteDeNotes.append(randint(0,3))
        for i in range(0,len(suiteDeNotes)):
            jouerNote(suiteDeNotes[i])
        # Le joueur reproduit la suite de notes
        for i in range(0,len(suiteDeNotes)):
            # récupère la valeur du bouton appuyé
            lireBouton(4)
            if resultatBouton == 9:
                finPartie = 1
                animationPerdu()
                break
            jouerNote(resultatBouton)
            if suiteDeNotes[i] != resultatBouton:
                finPartie = 1
                animationPerdu()
                break
        sleep(1)
    #Fin de la partie
    # Affichage du score de la partie précédente
    score = score + len(suiteDeNotes) - 1
    for i in range(0, 4):        
        ledNeopixels.set_pixel(i, (0, 0, 0))
    if score  >= NIVEAU1:
        ledNeopixels.set_pixel(3, (1, 0, 0))
        if score >= NIVEAU2:
            ledNeopixels.set_pixel(2, (1, 0, 0))
            if score >= NIVEAU3:
                ledNeopixels.set_pixel(1, (1, 0, 0))
                if score >= NIVEAU4:
                    ledNeopixels.set_pixel(0, (1, 0, 0))
    ledNeopixels.show()
    suiteDeNotes[:] = []

Pour démarrer la partie, appuyez sur une touche. Après une petite animation, le jeu commence en vous proposant une note à répéter. Vous avez seulement 3 secondes pour le faire. Si tout va bien, la partie continue et ajoute à chaque fois une nouvelle note. Si vous réussissez à répéter 20 notes (personnellement je n’ai jamais réussi), vous êtes un champion et pour vous récompenser, le Ludik Hat jouera pour vous La Marseillaise. Sinon, une petite animation indique que vous avez perdu et il ne vous reste plus qu’à redémarrer une autre partie. A la fin de la partie le score s’affiche en rouge sur les LED Neopixel :

  • 0 LED, moins de 5 notes justes (Vous avez été déconcentré, recommencez et ça ira mieux)
  • 1 LED entre 5 et 10 notes justes (Allez encore un effort pour atteindre au moins 10)
  • 2 LED entre 10 et 15 notes justes (Pas mal, un coup de chance ou vous êtes capable de le refaire ?)
  • 3 LED entre 15 et 20 notes justes (Waouh, vous êtes doué, vous allez réussir la prochaine fois)
  • 4 LED 20 justes (Bravo, la France est fière de vous. Savourez la douce musique de la victoire)

Sinon, il est possible de changer les seuils en modifiant cette partie du programme :

# Réglage du score
NIVEAU1 = 5 # 5 bonnes notes
NIVEAU2 = 10 # 10 bonnes notes
NIVEAU3 = 15 # 15 bonnes notes
NIVEAU4 = 20 # 20 bonnes notes

Vous pouvez modifier le volume sonore avec le potentiomètre (si tout fonctionne mais que vous n’entendez rien, essayez de tourner le bouton).

Amusez vous bien et passez de joyeuses fêtes de fin d’année.

Sources et liens utiles


Votre commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l’aide de votre compte WordPress.com. Déconnexion /  Changer )

Photo Google

Vous commentez à l’aide de votre compte Google. Déconnexion /  Changer )

Image Twitter

Vous commentez à l’aide de votre compte Twitter. Déconnexion /  Changer )

Photo Facebook

Vous commentez à l’aide de votre compte Facebook. Déconnexion /  Changer )

Connexion à %s