Raspberry Pi Pico
Simon Game

This project is based on a handheld electronic game that was developed in the 1970s. The game consists of 4 coloured buttons. The buttons light up when they are pressed and a different tone is played for each button. In each round of the game, the microcontroller lights up a sequence of buttons. The player has to press the buttons in the same sequence. After each round, the length of the sequence is increased by 1.

I have some nice LED buttons to use for this. This makes for a tidier circuit but you can do the same thing without using these.

Pico Circuit

The Fritzing diagram shows the same concept using separate buttons and LEDs.

Pico Circuit

I found it hard to manage the flow of the game using interrupts. I therefore switched back to using a while loop and monitoring changes in the game state.

from machine import PWM, Pin
from time import sleep
from random import randint

# buzzer, frequency, duration - play tone subroutine
def tone(frequency,duration):
    buzzer.duty_u16(volume)
    buzzer.freq(frequency)
    sleep(duration)
    buzzer.duty_u16(0)

# frequency - plays until stopped
def note_on(frequency):
    buzzer.duty_u16(volume)
    buzzer.freq(frequency)

# stop the noise
def note_off():
    buzzer.duty_u16(0)             

def GetRandomSequence():
    return [randint(0,3) for i in range(100)]

def PlaySequence(t,s):
    for i in range(t):
        leds[s[i]].value(1)
        tone(notes[s[i]],0.5)
        leds[s[i]].value(0)
        sleep(0.2)
        
def Win():
    for i in range(4):
        for j in range(4):
            leds[j].value(1)
            tone(notes[j], 0.05)
            leds[j].value(0)
def Loss():
    tone(131,0.5)
    sleep(1.5)
    
def PlayGame():
    turn = 0
    sequence = GetRandomSequence()
    userSequence = [0]*100
    seqlen = 0
    playing = True
    played = False
    while playing==True:
        if turn==0:
            # Just started
            Win()
            turn = turn + 1
        if seqlen==0 and played==False:
            # Sequence needs playing
            PlaySequence(turn, sequence)
            played = True
        elif seqlen==turn:
            # User has entered the sequence
            Win()
            played = False
            turn = turn + 1
            seqlen = 0
        else:
           # User still entering pattern
           for i in range(0,4):
               if btns[i].value()==0:
                   userSequence[seqlen] = i
                   if userSequence[seqlen]!=sequence[seqlen]:
                       Loss()
                       playing = False
                   else:
                       seqlen = seqlen + 1
                       leds[i].value(1)
                       tone(notes[i], 0.5)
                       leds[i].value(0)
    
# define the pin to use for buzzing
buzzer = PWM(Pin(16))
# the duty cycle to use when the note is on
volume = 2512
# button pins
btn_pins = [21,20,19,18]
# led pins
led_pins = [28,27,26,22]
# notes for our Simon game
notes = [659, 880, 330, 554]

# configure button and led pins in new lists
btns = []
leds = []
for i in range(4):
    btns.append(Pin(btn_pins[i], Pin.IN, Pin.PULL_UP))        
    leds.append(Pin(led_pins[i], Pin.OUT))

To start the game, type PlayGame() in the shell and press enter. It uses a random sequence of no more than 100 lights. This is just the basic outline of the game. It needs some development to improve it. This might be some more equipment to improve the user experience (a scoreboard, for example) or some improvement to the game play, like speeding up the playback the longer the sequence being played.