Last active
November 27, 2023 13:37
-
-
Save rbricheno/5d52b2a3749cc59d15d6112f8291435d to your computer and use it in GitHub Desktop.
Simon game for the pocketmoneytronics Christmas trees
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Simon game for the pocketmoneytronics Christmas trees | |
# By Rob! | |
# Public Domain and / or CC0 at your choice, share and enjoy! | |
import time | |
from time import sleep | |
from machine import Pin | |
from random import randint | |
game_states = { | |
'WAIT_START': 1, | |
'RUNNING_SEQUENCE': 2, | |
'CHECKING_RESPONSE': 3, | |
'FAILED': 4 | |
} | |
trees = { | |
'RED': 1, | |
'AMBER': 2, | |
'GREEN': 3 | |
} | |
start_btn = machine.Pin(22, machine.Pin.IN, machine.Pin.PULL_UP) | |
green_btn = machine.Pin(21, machine.Pin.IN, machine.Pin.PULL_UP) | |
amber_btn = machine.Pin(20, machine.Pin.IN, machine.Pin.PULL_UP) | |
red_btn = machine.Pin(19, machine.Pin.IN, machine.Pin.PULL_UP) | |
# This is a rudimentary sort of "debouncing" of the start button. | |
# It isn't required for the UI buttons because you have to press a | |
# different one for each next tree :-) | |
start_last = time.ticks_ms() | |
# The most recent button that was pressed | |
previous_button = None | |
# The sequence in which the trees will be displayed | |
sequence = [] | |
# The buttons that the user pressed in response (so far) | |
user_input = [] | |
# Simple state machine to handle game modes | |
state = game_states['WAIT_START'] | |
# Some utility functions to handle common forrestry managment tasks :-) | |
def trees_off(): | |
for led in range(15): | |
Pin(led, Pin.OUT).low() | |
def tree_name_on(tree_name): | |
# There are five LEDs in each tree, and they are numbered from one to fifteen. | |
# The five LEDs of each tree are next to each other, in order, so the first five are red, the next five amber | |
# and the final five are green. Just like traffic lights! | |
offset = 5 * trees[tree_name] - 5 | |
for led in range(5): | |
Pin(led + offset, Pin.OUT).high() | |
def tree_number_on(tree): | |
# A more fancy way of turning a tree on, where it slowly lights around the edge before displaying the full thing | |
offset = 5 * tree - 5 | |
trees_off() | |
for led in range(5): | |
Pin(led + offset, Pin.OUT).high() | |
sleep(0.05) | |
trees_off() | |
for led in range(5): | |
Pin(led + offset, Pin.OUT).high() | |
def tree_number_on_speed(tree, speed): | |
# Like the fancy thing above, but can be done more or less quickly for when we speed up the game | |
offset = 5 * tree - 5 | |
trees_off() | |
for led in range(5): | |
Pin(led + offset, Pin.OUT).high() | |
sleep(0.05 * speed) | |
trees_off() | |
for led in range(5): | |
Pin(led + offset, Pin.OUT).high() | |
def red_on(): | |
tree_name_on("RED") | |
def amber_on(): | |
tree_name_on("AMBER") | |
def green_on(): | |
tree_name_on("GREEN") | |
def trees_on(): | |
red_on() | |
amber_on() | |
green_on() | |
def twinkle(): | |
# Twinkle effect, to entice and bewitch the user. | |
for led in range(15): | |
Pin(led, Pin.OUT).low() | |
for i in range(50): | |
led = randint(0,14) | |
Pin(led, Pin.OUT).toggle() | |
sleep(0.01) | |
def any_other_tree(most_recent_tree): | |
# Make sure that we add a different tree to the end of the sequence each time | |
choose_one = randint(1,2) | |
if most_recent_tree == 1: | |
return choose_one + 1 | |
elif most_recent_tree == 3: | |
return choose_one | |
else: | |
if choose_one == 1: | |
return 1 | |
else: | |
return 3 | |
def button_handler(pin): | |
global start_last, start_btn, green_btn, amber_btn, red_btn, state, game_states, trees, sequence, user_input, previous_button | |
if pin is start_btn: | |
if time.ticks_diff(time.ticks_ms(), start_last) > 200: | |
if state != game_states['WAIT_START']: | |
# Reset a running game | |
state = game_states['WAIT_START'] | |
else: | |
# Start a new game | |
sequence = [] | |
user_input = [] | |
state = game_states['RUNNING_SEQUENCE'] | |
start_last = time.ticks_ms() | |
elif pin is green_btn: | |
if state == game_states['CHECKING_RESPONSE'] and previous_button != "GREEN": | |
trees_off() | |
green_on() | |
user_input.append(trees['GREEN']) | |
previous_button = "GREEN" | |
elif pin is amber_btn: | |
if state == game_states['CHECKING_RESPONSE'] and previous_button != "AMBER": | |
trees_off() | |
amber_on() | |
user_input.append(trees['AMBER']) | |
previous_button = "AMBER" | |
elif pin is red_btn: | |
if state == game_states['CHECKING_RESPONSE'] and previous_button != "RED": | |
trees_off() | |
red_on() | |
user_input.append(trees['RED']) | |
previous_button = "RED" | |
start_btn.irq(trigger = machine.Pin.IRQ_RISING, handler = button_handler) | |
green_btn.irq(trigger = machine.Pin.IRQ_RISING, handler = button_handler) | |
amber_btn.irq(trigger = machine.Pin.IRQ_RISING, handler = button_handler) | |
red_btn.irq(trigger = machine.Pin.IRQ_RISING, handler = button_handler) | |
while True: | |
if state==game_states['WAIT_START']: | |
# Play a sort of demo mode when we aren't doing anything. | |
if randint(1,60) == 42: | |
twinkle() | |
led = randint(0,14) | |
Pin(led, Pin.OUT).toggle() | |
sleep(0.3) | |
if state==game_states['FAILED']: | |
# This is where I would sound a buzzer, IF I HAD ONE! :P | |
for i in range(3): | |
trees_on() | |
sleep(0.5) | |
trees_off() | |
sleep(0.5) | |
sleep(1) | |
state = game_states['WAIT_START'] | |
if state==game_states['RUNNING_SEQUENCE']: | |
# Speed up as we go along | |
speed = 1 - 0.1 * len(sequence) | |
if speed < 0.2: | |
speed = 0.2 | |
# Start the sequence with any random tree | |
if sequence == []: | |
next_tree = randint(1,3) | |
else: | |
# Always show a different tree next... | |
most_recent_tree = sequence[len(sequence) - 1] | |
next_tree = any_other_tree(most_recent_tree) | |
sequence.append(next_tree) | |
for tree in sequence: | |
trees_off() | |
sleep(speed/2) | |
tree_number_on_speed(tree, speed) | |
sleep(speed) | |
trees_off() | |
user_input = [] | |
previous_button = None | |
state = game_states['CHECKING_RESPONSE'] | |
if state==game_states['CHECKING_RESPONSE']: | |
counter = 0 | |
if user_input: | |
# Check every inputted tree for correctness | |
for sequence_number in range(len(user_input)): | |
if user_input[sequence_number] != sequence[sequence_number]: | |
state = game_states['FAILED'] | |
counter = counter + 1 | |
if state == game_states['CHECKING_RESPONSE'] and counter == len(sequence): | |
# All of the inputs have been given, and none of them were wrong. | |
# A winner is you! | |
twinkle() | |
# But the princess is in another castle... | |
user_input = [] | |
state = game_states['RUNNING_SEQUENCE'] | |
sleep(0.2) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment