Mystery Game #8
← Back to Games List
// Simon Says Game Implementation
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
// Game settings
const centerX = canvas.width / 2;
const centerY = canvas.height / 2;
const radius = 150;
const buttonRadius = radius * 0.8;
const colors = ['red', 'blue', 'green', 'yellow'];
const brightColors = ['#ff6666', '#6666ff', '#66ff66', '#ffff66'];
const tones = [329.63, 261.63, 392.00, 196.00]; // E4, C4, G4, G3
// Game state
let sequence = [];
let playerSequence = [];
let gameStarted = false;
let playerTurn = false;
let currentIndex = 0;
let score = 0;
let highlightedButton = -1;
let audioContext = null;
// Calculate button positions
const buttons = colors.map((color, index) => {
const angle = (index * Math.PI / 2) + Math.PI / 4;
return {
x: centerX + Math.cos(angle) * radius * 0.5,
y: centerY + Math.sin(angle) * radius * 0.5,
color: color,
brightColor: brightColors[index],
tone: tones[index]
};
});
// Handle mouse click
canvas.addEventListener('click', function(e) {
if (!gameStarted) {
startGame();
return;
}
if (!playerTurn) return;
const rect = canvas.getBoundingClientRect();
const clickX = e.clientX - rect.left;
const clickY = e.clientY - rect.top;
// Check which button was clicked
buttons.forEach((button, index) => {
const dx = clickX - button.x;
const dy = clickY - button.y;
if (dx * dx + dy * dy < buttonRadius * buttonRadius) {
playerClick(index);
}
});
});
function startGame() {
// Initialize audio context
if (!audioContext) {
audioContext = new (window.AudioContext || window.webkitAudioContext)();
}
sequence = [];
playerSequence = [];
gameStarted = true;
playerTurn = false;
currentIndex = 0;
score = 0;
addToSequence();
}
function addToSequence() {
sequence.push(Math.floor(Math.random() * 4));
playerSequence = [];
currentIndex = 0;
playerTurn = false;
playSequence();
}
function playSequence() {
if (currentIndex < sequence.length) {
highlightedButton = sequence[currentIndex];
playTone(buttons[highlightedButton].tone);
setTimeout(() => {
highlightedButton = -1;
setTimeout(() => {
currentIndex++;
playSequence();
}, 200);
}, 500);
} else {
playerTurn = true;
currentIndex = 0;
}
}
function playerClick(buttonIndex) {
if (!playerTurn) return;
highlightedButton = buttonIndex;
playTone(buttons[buttonIndex].tone);
playerSequence.push(buttonIndex);
setTimeout(() => {
highlightedButton = -1;
// Check if the move was correct
if (buttonIndex !== sequence[currentIndex]) {
gameOver();
return;
}
currentIndex++;
// Check if sequence is complete
if (currentIndex === sequence.length) {
score++;
setTimeout(addToSequence, 1000);
}
}, 200);
}
function playTone(frequency) {
const oscillator = audioContext.createOscillator();
const gainNode = audioContext.createGain();
oscillator.connect(gainNode);
gainNode.connect(audioContext.destination);
oscillator.type = 'sine';
oscillator.frequency.value = frequency;
gainNode.gain.setValueAtTime(0, audioContext.currentTime);
gainNode.gain.linearRampToValueAtTime(0.5, audioContext.currentTime + 0.01);
gainNode.gain.linearRampToValueAtTime(0, audioContext.currentTime + 0.3);
oscillator.start(audioContext.currentTime);
oscillator.stop(audioContext.currentTime + 0.3);
}
function gameOver() {
gameStarted = false;
playerTurn = false;
}
function draw() {
// Clear canvas
ctx.fillStyle = 'black';
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Draw buttons
buttons.forEach((button, index) => {
ctx.beginPath();
ctx.arc(button.x, button.y, buttonRadius, 0, Math.PI * 2);
ctx.fillStyle = index === highlightedButton ? button.brightColor : button.color;
ctx.fill();
ctx.strokeStyle = 'white';
ctx.lineWidth = 2;
ctx.stroke();
});
// Draw score
ctx.fillStyle = 'white';
ctx.font = '24px Arial';
ctx.textAlign = 'center';
ctx.fillText('Score: ' + score, centerX, 30);
// Draw game state message
if (!gameStarted) {
ctx.fillStyle = 'rgba(0, 0, 0, 0.7)';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = 'white';
ctx.font = '30px Arial';
if (score === 0) {
ctx.fillText('Click to Start!', centerX, centerY);
} else {
ctx.fillText('Game Over!', centerX, centerY - 20);
ctx.font = '24px Arial';
ctx.fillText('Final Score: ' + score, centerX, centerY + 20);
ctx.fillText('Click to Play Again', centerX, centerY + 60);
}
}
}
// Game loop
function gameLoop() {
draw();
requestAnimationFrame(gameLoop);
}
// Initialize canvas size
canvas.width = 500;
canvas.height = 500;
// Start game loop
gameLoop();
# Simon Says Game Implementation
import pygame
import random
import math
from dataclasses import dataclass
from typing import List, Tuple
@dataclass
class Button:
x: int
y: int
color: Tuple[int, int, int]
bright_color: Tuple[int, int, int]
tone_freq: float
sound: pygame.mixer.Sound = None
class SimonGame:
def __init__(self):
pygame.init()
pygame.mixer.init()
# Game settings
self.width = 500
self.height = 500
self.center_x = self.width // 2
self.center_y = self.height // 2
self.radius = 150
self.button_radius = self.radius * 0.8
# Initialize display
self.screen = pygame.display.set_mode((self.width, self.height))
pygame.display.set_caption('Simon Says')
self.clock = pygame.time.Clock()
# Colors and tones
self.colors = [
((255, 0, 0), (255, 102, 102), 329.63), # Red, E4
((0, 0, 255), (102, 102, 255), 261.63), # Blue, C4
((0, 255, 0), (102, 255, 102), 392.00), # Green, G4
((255, 255, 0), (255, 255, 102), 196.00) # Yellow, G3
]
# Create buttons
self.buttons = self.create_buttons()
# Game state
self.sequence: List[int] = []
self.player_sequence: List[int] = []
self.game_started = False
self.player_turn = False
self.current_index = 0
self.score = 0
self.highlighted_button = -1
# Generate tone sounds
self.generate_sounds()
def create_buttons(self) -> List[Button]:
buttons = []
for i, (color, bright_color, tone) in enumerate(self.colors):
angle = (i * math.pi / 2) + math.pi / 4
x = self.center_x + math.cos(angle) * self.radius * 0.5
y = self.center_y + math.sin(angle) * self.radius * 0.5
buttons.append(Button(x, y, color, bright_color, tone))
return buttons
def generate_sounds(self):
sample_rate = 44100
duration = 0.3 # seconds
for button in self.buttons:
# Generate a sine wave
samples = []
for i in range(int(duration * sample_rate)):
t = i / sample_rate
amplitude = max(0, 1 - t/duration) # Linear fade out
sample = int(32767 * amplitude * math.sin(2 * math.pi * button.tone_freq * t))
samples.append(sample)
# Convert to pygame sound
sound_array = bytes(samples)
button.sound = pygame.mixer.Sound(buffer=sound_array)
def handle_input(self) -> bool:
for event in pygame.event.get():
if event.type == pygame.QUIT:
return False
if event.type == pygame.MOUSEBUTTONDOWN:
if not self.game_started:
self.start_game()
elif self.player_turn:
self.handle_click(event.pos)
return True
def handle_click(self, pos: Tuple[int, int]):
x, y = pos
for i, button in enumerate(self.buttons):
dx = x - button.x
dy = y - button.y
if dx * dx + dy * dy < self.button_radius * self.button_radius:
self.player_click(i)
break
def start_game(self):
self.sequence = []
self.player_sequence = []
self.game_started = True
self.player_turn = False
self.current_index = 0
self.score = 0
self.add_to_sequence()
def add_to_sequence(self):
self.sequence.append(random.randint(0, 3))
self.player_sequence = []
self.current_index = 0
self.player_turn = False
pygame.time.set_timer(pygame.USEREVENT, 1000) # Start sequence playback
def play_sequence(self):
if self.current_index < len(self.sequence):
self.highlighted_button = self.sequence[self.current_index]
self.buttons[self.highlighted_button].sound.play()
pygame.time.set_timer(pygame.USEREVENT + 1, 500) # Button off timer
else:
self.player_turn = True
self.current_index = 0
pygame.time.set_timer(pygame.USEREVENT, 0) # Stop sequence playback
def player_click(self, button_index: int):
if not self.player_turn:
return
self.highlighted_button = button_index
self.buttons[button_index].sound.play()
self.player_sequence.append(button_index)
pygame.time.set_timer(pygame.USEREVENT + 1, 200) # Button off timer
# Check if move was correct
if button_index != self.sequence[self.current_index]:
self.game_over()
return
self.current_index += 1
# Check if sequence is complete
if self.current_index == len(self.sequence):
self.score += 1
pygame.time.set_timer(pygame.USEREVENT, 1000) # Start next sequence
def game_over(self):
self.game_started = False
self.player_turn = False
pygame.time.set_timer(pygame.USEREVENT, 0)
def draw(self):
# Clear screen
self.screen.fill((0, 0, 0))
# Draw buttons
for i, button in enumerate(self.buttons):
color = button.bright_color if i == self.highlighted_button else button.color
pygame.draw.circle(self.screen, color, (int(button.x), int(button.y)),
int(self.button_radius))
pygame.draw.circle(self.screen, (255, 255, 255), (int(button.x), int(button.y)),
int(self.button_radius), 2)
# Draw score
font = pygame.font.Font(None, 36)
score_text = font.render(f'Score: {self.score}', True, (255, 255, 255))
score_rect = score_text.get_rect(center=(self.center_x, 30))
self.screen.blit(score_text, score_rect)
# Draw game state message
if not self.game_started:
overlay = pygame.Surface((self.width, self.height))
overlay.fill((0, 0, 0))
overlay.set_alpha(178) # 70% opacity
self.screen.blit(overlay, (0, 0))
if self.score == 0:
text = font.render('Click to Start!', True, (255, 255, 255))
text_rect = text.get_rect(center=(self.center_x, self.center_y))
self.screen.blit(text, text_rect)
else:
game_over = font.render('Game Over!', True, (255, 255, 255))
game_over_rect = game_over.get_rect(
center=(self.center_x, self.center_y - 20))
self.screen.blit(game_over, game_over_rect)
score = font.render(f'Final Score: {self.score}', True, (255, 255, 255))
score_rect = score.get_rect(
center=(self.center_x, self.center_y + 20))
self.screen.blit(score, score_rect)
play_again = font.render('Click to Play Again', True, (255, 255, 255))
play_again_rect = play_again.get_rect(
center=(self.center_x, self.center_y + 60))
self.screen.blit(play_again, play_again_rect)
pygame.display.flip()
def run(self):
running = True
while running:
running = self.handle_input()
for event in pygame.event.get():
if event.type == pygame.USEREVENT: # Sequence playback
self.play_sequence()
elif event.type == pygame.USEREVENT + 1: # Button off timer
self.highlighted_button = -1
pygame.time.set_timer(pygame.USEREVENT + 1, 0)
self.draw()
self.clock.tick(60)
pygame.quit()
if __name__ == '__main__':
game = SimonGame()
game.run()
Play Game