To play the Simon game, power up the PyRuler by plugging in a USB cable connected to a computer or a USB cell phone battery.
You will see the 4 leds above each touch pad light up in sequence then turn off.
Next, you will see one of the 4 leds turn on and off.
Then the DotStar RGB LED on the Trinket-sized circuit board will turn green prompting you to touch the pad corresponding to the led that was just on.
If you correctly input the given pattern, the DotStar led will cycle through a random pattern and the next pattern will be shown.
Each future pattern has the same initial sequence from before with one more added to the sequence each time.
When the DotStar is blue, the program is showing you the sequence.
If you get a sequence wrong, the DotStar will turn red then the game will start over with the leds cycling through the intro pattern.
How the code works
Here's what's going on behind the scenes to deliver you the Simon game you know and love.
Initialization
This segment towards the beginning of the program initializes the 4 touch pads on the PyRuler as well as the corresponding 4 leds.
touches = [DigitalInOut(board.CAP0)] for p in (board.CAP1, board.CAP2, board.CAP3): touches.append(touchio.TouchIn(p)) leds = [] for p in (board.LED4, board.LED5, board.LED6, board.LED7): led = DigitalInOut(p) led.direction = Direction.OUTPUT leds.append(led) cap_touches = [False, False, False, False]
Functions
These functions simplify and optimize how the program runs.
DotStar code
This part shows how the rainbow pattern for the dot star works.
def wheel(pos): # Input a value 0 to 255 to get a color value. # The colours are a transition r - g - b - back to r. if pos < 0 or pos > 255: return (0, 0, 0) if pos < 85: return (255 - pos * 3, pos * 3, 0) if pos < 170: pos -= 85 return (0, 255 - pos * 3, pos * 3) pos -= 170 return (pos * 3, 0, 255 - pos * 3) def rainbow_cycle(wait): for j in range(255): for i in range(len(pixels)): rc_index = (i * 256 // len(pixels)) + j pixels[i] = wheel(rc_index & 255) time.sleep(wait)
Detecting capacitive touch and setting a timer
Up next we read input from the PyRuler capacitive touch pads with the read_caps()
function. Then with the timeout_touch()
function we set a 3 second timer after each pattern is displayed as well as in-between each touch.
def read_caps(): t0_count = 0 t0 = touches[0] t0.direction = Direction.OUTPUT t0.value = True t0.direction = Direction.INPUT # funky idea but we can 'diy' the one non-hardware captouch device by hand # by reading the drooping voltage on a tri-state pin. t0_count = t0.value + t0.value + t0.value + t0.value + t0.value + \ t0.value + t0.value + t0.value + t0.value + t0.value + \ t0.value + t0.value + t0.value + t0.value + t0.value cap_touches[0] = t0_count > 2 cap_touches[1] = touches[1].raw_value > 3000 cap_touches[2] = touches[2].raw_value > 3000 cap_touches[3] = touches[3].raw_value > 3000 return cap_touches def timeout_touch(timeout=3): start_time = time.monotonic() # start 3 second timer waiting for user input while time.monotonic() - start_time < timeout: caps = read_caps() for i,c in enumerate(caps): if c: return i
Playing and reading each sequence with leds
-
light_cap()
turns on the led associated with each touch pad if the pad was touched. -
play_sequence()
plays each led for the given sequence and slowly speeds up the playback of each sequence as they get longer. -
read_sequence()
First turns the DotStar green (indicating to user to enter the sequence) then reads the touch pads and determines if they are the right sequence. If the wrong pad was touched, the function returnsFalse
which will cause a game over (more on this later).
def light_cap(cap, duration=0.5): # turn the LED for the selected cap on leds[cap].value = True time.sleep(duration) leds[cap].value = False time.sleep(duration) def play_sequence(seq): duration = max(0.1, 1 - len(sequence) * 0.05) for cap in seq: light_cap(cap, duration) def read_sequence(seq): pixels.fill(green) for cap in seq: if timeout_touch() != cap: # the player made a mistake! return False light_cap(cap, 0.5) return True
The main loop
- First trigger the starting sequence of leds demonstrating the game is beginning.
- Next in a nested loop, turn the DotStar blue demonstrating the sequence is being shown.
- Then add a random number between 0 and 3 to the sequence and play the sequence.
- If the user enters the wrong sequence or the time runs out, turn the DotStar red indicating game over, and exit the loop starting the game over at the top of the main loop.
- Otherwise, trigger the rainbow animation on the DotStar (indicating a correct sequence) and move to next sequence.
while True: # led light sequence at beginning of each game pixels.fill(blue) time.sleep(1) for led in leds: led.value = True time.sleep(0.25) for led in leds: led.value = False sequence = [] while True: pixels.fill(blue) # blue for showing user sequence time.sleep(1) sequence.append(random.randint(0, 3)) # add new light to sequence each time play_sequence(sequence) # show the sequence if not read_sequence(sequence): # if user inputs wrong sequence, gameover # game over, make dot star red pixels.fill(red) time.sleep(3) print("gameover") break else: print("Next sequence unlocked!") rainbow_cycle(0) # Dot star animation after each correct sequence pixels.fill(0) time.sleep(1)
That's it, now you're a CircuitPython wiz!
Simon Says time to make your own game with the PyRuler!
Page last edited March 08, 2024
Text editor powered by tinymce.