BBC micro:bit
Touch:bit Noise:bit Simon Game

Introduction

This project is another reworking of the Simon game described more fully in other pages on this site. This one features two micro:bit accessories from Pimoroni. The stars of the show are the two boards at the bottom of the image.

micro:bit circuit

The Noise:bit is on the left of the image, is a speaker. You can get tone and speech output through it and it sounds great. The Touch:bit is the board to the right of the image. It is similar to the Touch pHAT Raspberry Pi accessory that Pimoroni make but has the LEDs wired directly, making it easier to use.

These, and the other Pimoroni micro:bit accessories, can be used in radio networks to combine their features and make more interesting projects. The radio on the micro:bit is good enough to send control instructions for a game like Snake and, with some experimentation and care with your timings, you can get pretty good performance for all sorts of network-based setups.

Programming

I started by setting up receiver in this pair. The micro:bit with the Noise:bit just has to make the right noises for us when we tell it to.

Putting all of the sound logic into this program frees up a little space for the hard work that our other micro:bit will have to do.

from microbit import *
import radio
import music

chnl = 10
radio.config(channel=chnl)
radio.on()

notes = [659, 880, 330, 554]

def Win():
    for i in range(0,4):
        for j in range(0,4):            
            music.pitch(notes[j],50)                
    
def Loss():
    music.pitch(131,500)
    
    
while True:
    s = radio.receive()
    if s is not None:
        if s=="w":
            Win()
        elif s=="l":
            Loss()
        else:
            s = int(s)
            music.pitch(notes[s],500)

The micro:bit with the Touch:bit is where the game is really being played. There are some delays in the game code to keep it from regsitering innocent double presses. You have to wait a few milliseconds sometimes for your press to be registered, but the program just about gets there.

I stuck with only 4 inputs and used A to D for the game play. The other two pads are not used.

from microbit import *
import radio
import random
from math import log

chnl = 10
radio.config(channel=chnl)
radio.on()

def w_i2c(r,v):
    i2c.write(0x2c, bytes([r,v]))

def get_tou():
    w_i2c(0,0)
    i2c.write(0x2c,b'\x03')
    d = i2c.read(0x2c,1)[0]    
    if d>0:
        return log(d,2)
    else:
        return -1    
    
def track(v):
    if v:
        w_i2c(0x72,0x3F)
    else:
        w_i2c(0x72,0)       
   
def set_led(index, state):
    i2c.write(0x2c,b'\x74')
    current = i2c.read(0x2c, 1)[0]   
    if state:
        current |= 1 << index
    else:
        current &= ~(1 << index)
    w_i2c(0x74, current)
    
def GetRandomSequence():
    return [int(4*random.random()) for i in range(0,100)]

def PlaySequence(t, s):
    for i in range(t):
        set_led(s[i]+1,True)
        radio.send(str(s[i]))
        sleep(450)
        set_led(s[i]+1,False)
        sleep(300)
    


w_i2c(0x41,0x30)
w_i2c(0x74, 0)
sleep(1)
track(False)
def main():
    sleep(50)
    while True:
        display.show(Image.ARROW_W)
        if button_a.was_pressed():
            display.clear()
            turn = 0
            sequence = GetRandomSequence()
            userSequence = [0]*100
            seqlen = 0
            playing = True
            played = False
            while playing==True:
                if turn==0:
                    # Just started
                    radio.send("w")
                    sleep(800)
                    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
                    radio.send("w")
                    sleep(800)
                    played = False
                    turn = turn + 1
                    seqlen = 0
                else:
                    # User still entering pattern
                    a = 0
                    while a<1 or a>4:
                        a = get_tou()
                        if a>0 and a<5:
                            a = int(a)
                            userSequence[seqlen] = a-1
                            if userSequence[seqlen]!=sequence[seqlen]:
                                radio.send("l")
                                sleep(800)
                                playing = False
                            else:
                                set_led(a,True)
                                radio.send(str(sequence[seqlen]))
                                seqlen = seqlen + 1                                                       
                                sleep(500)
                                set_led(a,False)
                        sleep(20)
                    sleep(1000)
        sleep(50)

main()    

Review

I did just enough here to get a basic game working, or at least as far as my testing went. The game play is not perfect, by any means, and there are many ways that the experience could be improved.

The code is on the edge of the recursion limit. This never mattered in the language that it started in, it does here. A rethink of the game loop would lead to a better game, making it easier to add more features.

Another approach to the end of the game might also avoid the game crashing if the player can manage 100 correct presses.