Created
October 23, 2024 18:30
-
-
Save jackdpeterson/b929a5837da782e48e18618e5cf856b3 to your computer and use it in GitHub Desktop.
AdaFruit BlueFruit two player game
This file contains hidden or 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
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