Skip to content

Instantly share code, notes, and snippets.

@jackdpeterson
Created October 23, 2024 18:30
Show Gist options
  • Save jackdpeterson/b929a5837da782e48e18618e5cf856b3 to your computer and use it in GitHub Desktop.
Save jackdpeterson/b929a5837da782e48e18618e5cf856b3 to your computer and use it in GitHub Desktop.
AdaFruit BlueFruit two player game
from adafruit_circuitplayground import cp
import time
import random
# Initialize variables globally at the top of the file
last_press_time_player1 = None
last_press_time_player2 = None
# Define color constants
RED = (255, 0, 0)
YELLOW = (255, 150, 0)
GREEN = (0, 255, 0)
CYAN = (0, 255, 255)
BLUE = (0, 0, 255)
PURPLE = (180, 0, 255)
WHITE = (255, 255, 255)
OFF = (0, 0, 0)
# Set NeoPixel brightness (values between 0.0 to 1.0)
cp.pixels.brightness = 0.2 # Lowered brightness level
# Maximum score to win the game
WINNING_SCORE = 5
# Cooldown time in seconds to prevent button spamming
COOLDOWN_TIME = 1.0
# Current scores for both players (reset before each new game)
player1_score = 0
player2_score = 0
# Index of the single target NeoPixel (will be randomized each round)
target_pixel = 0
def pick_random_target():
"""Pick a single random target pad and blink it twice."""
global target_pixel
# Pick a random target pixel from the entire ring (0-9)
target_pixel = random.randint(0, 9)
# Blink the chosen target twice
for _ in range(2):
cp.pixels.fill(OFF)
cp.pixels[target_pixel] = WHITE
cp.pixels.show()
time.sleep(0.3)
cp.pixels[target_pixel] = OFF
cp.pixels.show()
time.sleep(0.3)
def display_score():
"""Display the current scores using the NeoPixels."""
cp.pixels.fill(OFF) # Turn off all pixels to start
# Define colors for each score level
colors = [RED, YELLOW, GREEN, CYAN, BLUE, PURPLE]
# Display Player 1's score on the left half (pixels 0-4)
for i in range(player1_score):
cp.pixels[i] = colors[i]
# Display Player 2's score on the right half (pixels 5-9)
for i in range(player2_score):
cp.pixels[9 - i] = colors[i]
cp.pixels.show()
time.sleep(1)
def strobe_effect():
"""Strobe all lights three times with an interval of 100 ms on and 200 ms off."""
for _ in range(3):
cp.pixels.fill(WHITE) # Turn on all pixels
cp.pixels.show()
time.sleep(0.1) # On interval
cp.pixels.fill(OFF) # Turn off all pixels
cp.pixels.show()
time.sleep(0.2) # Off backoff
def check_victory():
"""Check if a player has won and display victory."""
if player1_score >= WINNING_SCORE:
print("Player 1 Wins!")
cp.pixels.fill(OFF)
# Highlight Player 1's half of the board
for i in range(5):
cp.pixels[i] = BLUE # Player 1's victory color
cp.pixels.show()
play_victory_tone() # Play victory tone for Player 1
return True
elif player2_score >= WINNING_SCORE:
print("Player 2 Wins!")
cp.pixels.fill(OFF)
# Highlight Player 2's half of the board
for i in range(5, 10):
cp.pixels[i] = GREEN # Player 2's victory color
cp.pixels.show()
play_victory_tone_player2() # Play victory tone for Player 2
return True
return False
def play_correct_hit_tone():
"""Play a happy three-note sequence for a correct hit."""
happy_melody = [523, 659, 784] # C5, E5, G5
note_duration = 0.15 # Duration per note
for freq in happy_melody:
cp.play_tone(freq, note_duration)
def play_correct_hit_tone_player2():
"""Play a unique three-note sequence for Player 2's correct hit."""
player2_melody = [392, 494, 587] # G4, B4, D5
note_duration = 0.15 # Duration per note
for freq in player2_melody:
cp.play_tone(freq, note_duration)
def play_victory_tone():
# List of frequencies to simulate the ascending notes
flagpole_melody = [659, 659, 698, 784, 784, 698, 659, 587, 523, 523, 587, 659, 587, 523, 587]
# Duration of each note in seconds
note_durations = [0.15, 0.15, 0.15, 0.3, 0.15, 0.15, 0.3, 0.15, 0.15, 0.15, 0.15, 0.15, 0.15, 0.15, 0.3]
# Play each note with its corresponding duration
for freq, duration in zip(flagpole_melody, note_durations):
cp.play_tone(freq, duration)
def play_victory_tone_player2():
"""Play a unique victory tone for Player 2."""
# List of frequencies for Player 2's unique victory melody
player2_victory_melody = [587, 784, 880, 784, 659, 523, 587, 392, 494, 392, 587, 523, 587, 392, 494]
# Duration of each note in seconds
note_durations = [0.15, 0.15, 0.15, 0.3, 0.15, 0.15, 0.3, 0.15, 0.15, 0.15, 0.15, 0.15, 0.15, 0.15, 0.3]
# Play each note with its corresponding duration
for freq, duration in zip(player2_victory_melody, note_durations):
cp.play_tone(freq, duration)
def spin_light():
"""Spin a single light around the NeoPixel ring in a random direction, speed, and starting position."""
print("Spinning light started. Press the button at the correct moment!")
# Randomize direction (1 for clockwise, -1 for counterclockwise)
direction = random.choice([1, -1])
# Randomize starting position
current_pixel = random.randint(0, 9)
# Randomize speed (time interval between moves)
speed = random.uniform(0.005, 0.09)
print(
f"Direction: {'Clockwise' if direction == 1 else 'Counterclockwise'}, Starting Position: {current_pixel}, Speed: {speed:.2f} seconds")
for _ in range(30): # Number of spins to allow sufficient chances for a button press
cp.pixels.fill(OFF)
cp.pixels[current_pixel] = WHITE
cp.pixels.show()
# Get the current time
current_time = time.time()
# Check for Player 1's and Player 2's inputs with debouncing
if check_player_input(1, current_pixel, current_time):
return
if check_player_input(2, current_pixel, current_time):
return
# Move to the next pixel based on direction and wrap around
current_pixel = (current_pixel + direction) % 10
time.sleep(speed) # Speed of the spinning
print("No successful button press. Try again!")
def check_player_input(player, current_pixel, current_time):
"""Check if a player's button press is valid, update score, and handle events."""
global last_press_time_player1, last_press_time_player2
global player1_score, player2_score
# Define player-specific parameters
if player == 1:
button_pressed = cp.button_a
last_press_time = last_press_time_player1
cooldown_time = COOLDOWN_TIME
update_score = lambda: increment_score(1)
play_tone = play_correct_hit_tone
update_last_press_time = lambda time: set_last_press_time(1, time)
else:
button_pressed = cp.button_b
last_press_time = last_press_time_player2
cooldown_time = COOLDOWN_TIME
update_score = lambda: increment_score(2)
play_tone = play_correct_hit_tone_player2
update_last_press_time = lambda time: set_last_press_time(2, time)
# Check if the button is pressed and at the correct target pixel
if button_pressed and current_pixel == target_pixel:
# Initialize last press time if it's not set
if last_press_time is None:
update_last_press_time(current_time)
last_press_time = current_time
time_since_last_press = current_time - last_press_time
print(f"Player {player} button pressed. Time since last press: {time_since_last_press:.2f} seconds")
if time_since_last_press >= cooldown_time:
print(f"Player {player} scored!")
update_score()
update_last_press_time(current_time)
display_score()
play_tone()
strobe_effect() # Perform strobe effect on scoring a point
return True # Exit the spin after scoring
return False
def increment_score(player):
"""Increment the score for a given player."""
global player1_score, player2_score
if player == 1:
player1_score += 1
else:
player2_score += 1
def set_last_press_time(player, time):
"""Set the last press time for a given player."""
global last_press_time_player1, last_press_time_player2
if player == 1:
last_press_time_player1 = time
else:
last_press_time_player2 = time
def reset_game():
"""Reset the game variables and display to prepare for a new game."""
global player1_score, player2_score, last_press_time_player1, last_press_time_player2
player1_score = 0
player2_score = 0
# Initialize the last press times to the current time when the game is reset
last_press_time_player1 = time.time()
last_press_time_player2 = time.time()
cp.pixels.fill(OFF)
print("Game Reset! Starting a new game.")
# Main game loop
while True:
if last_press_time_player1 is None or last_press_time_player2 is None:
reset_game()
# Pick a single random target at the beginning of each round
pick_random_target()
# Run the spinning light sequence
spin_light()
# Check for a victory condition after each spin
if check_victory():
print("Game Over. Victory achieved!")
time.sleep(2) # Brief pause for celebration
reset_game() # Reset game variables for a new game
print("Round finished. Restarting...")
time.sleep(1) # Brief pause before restarting the spinning sequence
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment