Here is a CircuitPython version of the Simple Simon code.

CircuitPython only works on the Circuit Playground Express.
Download: file
# Circuit Playground Express Simple Simon
#
# Game play based on information provided here:
# http://www.waitingforfriday.com/?p=586
#
# Author: Carter Nelson
# MIT License (https://opensource.org/licenses/MIT)
import time
import random
import math
import board
from analogio import AnalogIn
from adafruit_circuitplayground.express import cpx

FAILURE_TONE        = 100
SEQUENCE_DELAY      = 0.8
GUESS_TIMEOUT       = 3.0
DEBOUNCE            = 0.250
SEQUENCE_LENGTH = {
  1 : 8,
  2 : 14,
  3 : 20,
  4 : 31
}
SIMON_BUTTONS = {
  1 : { 'pads':(4,5), 'pixels':(0,1,2), 'color':0x00FF00, 'freq':415 },
  2 : { 'pads':(6,7), 'pixels':(2,3,4), 'color':0xFFFF00, 'freq':252 },
  3 : { 'pads':(1, ), 'pixels':(5,6,7), 'color':0x0000FF, 'freq':209 },
  4 : { 'pads':(2,3), 'pixels':(7,8,9), 'color':0xFF0000, 'freq':310 },  
}

def choose_skill_level():
    # Default
    skill_level = 1
    # Loop until button B is pressed
    while not cpx.button_b:
        # Button A increases skill level setting
        if cpx.button_a:
            skill_level += 1
            skill_level = skill_level if skill_level < 5 else 1
            # Indicate current skill level
            cpx.pixels.fill(0)
            for p in range(skill_level):
                cpx.pixels[p] = 0xFFFFFF
            time.sleep(DEBOUNCE)
    return skill_level

def new_game(skill_level):
    # Seed the random function with noise
    a4 = AnalogIn(board.A4)
    a5 = AnalogIn(board.A5)
    a6 = AnalogIn(board.A6)
    a7 = AnalogIn(board.A7)

    seed  = a4.value
    seed += a5.value
    seed += a6.value
    seed += a7.value

    random.seed(seed)    

    # Populate the game sequence
    return [random.randint(1,4) for i in range(SEQUENCE_LENGTH[skill_level])]

def indicate_button(button, duration):
    # Turn them all off
    cpx.pixels.fill(0)
    # Turn on the ones for the given button
    for p in button['pixels']:
        cpx.pixels[p] = button['color']
    # Play button tone
    if button['freq'] == None:
        time.sleep(duration)
    else:
        cpx.play_tone(button['freq'], duration)
    # Turn them all off again
    cpx.pixels.fill(0)
    
def show_sequence(sequence, step):
    # Set tone playback duration based on current location
    if step <= 5:
        duration = 0.420
    elif step <= 13:
        duration = 0.320
    else:
        duration = 0.220
    
    # Play back sequence up to current step
    for b in range(step):
        time.sleep(0.05)
        indicate_button(SIMON_BUTTONS[sequence[b]], duration)    

def cap_map(b):
    if b == 1: return cpx.touch_A1
    if b == 2: return cpx.touch_A2
    if b == 3: return cpx.touch_A3
    if b == 4: return cpx.touch_A4
    if b == 5: return cpx.touch_A5
    if b == 6: return cpx.touch_A6
    if b == 7: return cpx.touch_A7    
    
def get_button_press():
    # Loop over all the buttons
    for button in SIMON_BUTTONS.values():
        # Loop over each pad
        for pad in button['pads']:
            if cap_map(pad):
                indicate_button(button, DEBOUNCE)
                return button
    return None

def game_lost(step):
    # Show button that should have been pressed
    cpx.pixels.fill(0)
    for p in SIMON_BUTTONS[sequence[step]]['pixels']:
        cpx.pixels[p] = SIMON_BUTTONS[sequence[step]]['color']
   
    # Play sad sound :(
    cpx.play_tone(FAILURE_TONE, 1.5)
    
    # And just sit here until reset
    while True:
        pass
    
def game_won():
    # Play 'razz' special victory signal
    for i in range(3):
        indicate_button(SIMON_BUTTONS[4], 0.1)        
        indicate_button(SIMON_BUTTONS[2], 0.1)        
        indicate_button(SIMON_BUTTONS[3], 0.1)        
        indicate_button(SIMON_BUTTONS[1], 0.1)        
    indicate_button(SIMON_BUTTONS[4], 0.1)            
    indicate_button(SIMON_BUTTONS[2], 0.1)

    # Change tones to failure tone
    for button in SIMON_BUTTONS.values():
        button['freq'] = FAILURE_TONE
        
    # Continue for another 0.8 seconds
    for i in range(2):
        indicate_button(SIMON_BUTTONS[3], 0.1)        
        indicate_button(SIMON_BUTTONS[1], 0.1)        
        indicate_button(SIMON_BUTTONS[4], 0.1)        
        indicate_button(SIMON_BUTTONS[2], 0.1)        
    
    # Change tones to silence
    for button in SIMON_BUTTONS.values():
        button['freq'] = None
    
    # Loop lights forever
    while True:
        indicate_button(SIMON_BUTTONS[3], 0.1)        
        indicate_button(SIMON_BUTTONS[1], 0.1)        
        indicate_button(SIMON_BUTTONS[4], 0.1)        
        indicate_button(SIMON_BUTTONS[2], 0.1)                

# Initialize setup    
cpx.pixels.fill(0)
cpx.pixels[0] = 0xFFFFFF
skill_level = choose_skill_level()
sequence = new_game(skill_level)
current_step = 1

#Loop forever
while True:
    # Show sequence up to current step
    show_sequence(sequence, current_step)
    
    # Read player button presses
    for step in range(current_step):
        start_guess_time = time.monotonic()
        guess = None
        while (time.monotonic() - start_guess_time < GUESS_TIMEOUT) and (guess == None):
            guess = get_button_press()
        if not guess == SIMON_BUTTONS[sequence[step]]:
            game_lost(sequence[step])

    # Advance the game forward
    current_step += 1
    if current_step > len(sequence):
        game_won()
    
    # Small delay before continuing    
    time.sleep(SEQUENCE_DELAY)

This guide was first published on Jan 23, 2017. It was last updated on Jan 23, 2017.

This page (CircuitPython Version) was last updated on Mar 05, 2021.

Text editor powered by tinymce.