BBC micro:bit
Simon Game

Introduction

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.

The original game is shown below,

Simon Game

We need 9 pins for this project - an edge connector breakout is a must.

Components Needed

  • BBC micro:bit
  • 4 x LEDs
  • 4 x 220 Ohm Resistors
  • 4 x Pushbuttons
  • 4 x 10 KOhm Resistors
  • 1 x Piezo Buzzer/Speaker/Headphone Hack
  • Jumper Wires

Circuit

This circuit is a bit fiddly and can be hard to fit onto a half-size breadboard. I've shown miniature 2-pin pushbuttons here because they fit better into a small diagram. The principle is the same with larger buttons. You should always use breadboard diagrams to get an idea of what connects to what. The exact positioning is not the issue.

Simon Game Circuit

The pushbuttons are wired with one pin connected to the 3V supply, the other pin is connected via a 10K Ohm resistor to GND. We read the input from the pin that is pulled to ground by the resistor.

The pins have been chosen to avoid the pins that are used for the matrix display. This is the maximum number of pins we can use for GPIO without clashing in some way with the built-in components.

Programming - Wiring Test

With a fiddly circuit, you need a quick test program to make sure that the wiring is all correct and that button presses are being registered. The correct LED should light up when a button is pressed. The buzzer should also sound.

from microbit import *
import music
button_pins = [pin13, pin14, pin15, pin16]
led_pins = [pin1, pin8, pin12, pin2]
notes = [659, 880, 330, 554]
 
while True:
    for i in range(0,4):
         if button_pins[i].read_digital()==1:
             led_pins[i].write_digital(1)
             music.pitch(notes[i],500)
             led_pins[i].write_digital(0)      
    sleep(50)

Programming - The Game

Here's a basic version of the game to get you started. It is broken up into functions.

from microbit import *
import music
import random

button_pins = [pin13, pin14, pin15, pin16]
led_pins = [pin1, pin8, pin12, pin2]
notes = [659, 880, 330, 554]

def GetRandomSequence():
    return [int(4*random.random()) for i in range(0,100)]

def PlaySequence(t, s):
    for i in range(0,t):
        led_pins[s[i]].write_digital(1)
        music.pitch(notes[s[i]],500)
        led_pins[s[i]].write_digital(0)
        sleep(200)

def Win():
    for i in range(0,4):
        for j in range(0,4):
            led_pins[j].write_digital(1)
            music.pitch(notes[j],50)
            led_pins[j].write_digital(0)    
    sleep(1000)
    
def Loss():
    music.pitch(131,500)
    sleep(1500)
    
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 button_pins[i].read_digital()==1:
                   userSequence[seqlen] = i
                   if userSequence[seqlen]!=sequence[seqlen]:
                       Loss()
                       playing = False
                   else:
                       seqlen = seqlen + 1
                       led_pins[i].write_digital(1)
                       music.pitch(notes[i],500)
                       led_pins[i].write_digital(0)   
            
def main():
    sleep(50)
    while True:
        display.show(Image.ARROW_W)
        if button_a.was_pressed():
            display.clear()
            PlayGame()
            sleep(1000)
        sleep(50)

main() 

Explanations & Suggestions

The main() function contains an infinite loop. This is where our game menu logic needs to go. At the moment it shows an arrow pointing to the A button. Pressing the A button starts the game. You could make some major improvements here. A scrolling display of the game title on start-up might be nice.

The Loss() function plays a long, low note when the player gets the pattern wrong. You can add statements to this section to update the matrix with a suitable display or play a longer tune to rub in the fact that the user made a mistake. You could also display a score.

The Win() function is run a the start of the game and every time the user correctly enters the sequence. You could make changes to this and add a suitable matrix image.

The GetRandomSequence() is currently hard-coded for a sequence of length 100. The program will have problems were this to be reached. You could correct that or change the program so that a new item is added to the sequence only when needed.

The PlayGame() function is where all of the hard work goes on. This would be a good place to update the LED matrix. You could help the player by showing them how far they are into the pattern. You could do this by lighting up numbers of pixels. This works well since most people struggle to beat 25 in this game.