import pygame
import random
import math
import json
import os
from enum import Enum
from dataclasses import dataclass
from typing import List, Tuple, Optional
# Initialize Pygame
pygame.init()
pygame.mixer.init()
# Constants
WINDOW_WIDTH = 1200
WINDOW_HEIGHT = 800
GRID_SIZE = 20
GRID_WIDTH = WINDOW_WIDTH // GRID_SIZE
GRID_HEIGHT = WINDOW_HEIGHT // GRID_SIZE
# Colors (Neon Theme)
BLACK = (0, 0, 0)
NEON_GREEN = (57, 255, 20)
NEON_BLUE = (0, 255, 255)
NEON_PINK = (255, 20, 147)
NEON_YELLOW = (255, 255, 0)
NEON_PURPLE = (191, 0, 255)
NEON_ORANGE = (255, 165, 0)
WHITE = (255, 255, 255)
DARK_GRAY = (30, 30, 30)
GLOW_GREEN = (57, 255, 20, 100)
class GameMode(Enum):
CLASSIC = "Classic"
ARENA = "Arena"
SURVIVAL = "Survival"
MULTIPLAYER = "Multiplayer"
class PowerUpType(Enum):
SPEED_BOOST = "speed_boost"
SLOW_MOTION = "slow_motion"
DOUBLE_POINTS = "double_points"
SHIELD = "shield"
MAGNET = "magnet"
@dataclass
class PowerUp:
x: int
y: int
type: PowerUpType
duration: int
color: Tuple[int, int, int]
class Particle:
def __init__(self, x, y, color, velocity, life):
self.x = x
self.y = y
self.color = color
self.velocity = velocity
self.life = life
self.max_life = life
def update(self):
self.x += self.velocity[0]
self.y += self.velocity[1]
self.life -= 1
def draw(self, screen):
alpha = int(255 * (self.life / self.max_life))
color_with_alpha = (*self.color, alpha)
size = int(5 * (self.life / self.max_life))
if size > 0:
pygame.draw.circle(screen, self.color, (int(self.x), int(self.y)), size)
class Snake:
def __init__(self, x, y, color, player_id=0):
self.body = [(x, y)]
self.direction = (1, 0)
self.color = color
self.grow_pending = 0
self.score = 0
self.alive = True
self.player_id = player_id
self.power_ups = {}
self.shield_time = 0
def move(self):
if not self.alive:
return
head_x, head_y = self.body[0]
dx, dy = self.direction
new_head = (head_x + dx, head_y + dy)
# Check boundaries
if (new_head[0] < 0 or new_head[0] >= GRID_WIDTH or
new_head[1] < 0 or new_head[1] >= GRID_HEIGHT):
if self.shield_time <= 0:
self.alive = False
return
# Check self collision
if new_head in self.body:
if self.shield_time <= 0:
self.alive = False
return
self.body.insert(0, new_head)
if self.grow_pending > 0:
self.grow_pending -= 1
else:
self.body.pop()
# Update power-up timers
if self.shield_time > 0:
self.shield_time -= 1
def grow(self, amount=1):
self.grow_pending += amount
def change_direction(self, new_direction):
# Prevent reversing into itself
if (new_direction[0] * -1, new_direction[1] * -1) != self.direction:
self.direction = new_direction
def draw(self, screen):
if not self.alive:
return
for i, (x, y) in enumerate(self.body):
rect = pygame.Rect(x * GRID_SIZE, y * GRID_SIZE, GRID_SIZE, GRID_SIZE)
# Draw glow effect
glow_rect = pygame.Rect(x * GRID_SIZE - 2, y * GRID_SIZE - 2,
GRID_SIZE + 4, GRID_SIZE + 4)
pygame.draw.rect(screen, (*self.color, 100), glow_rect)
# Draw body segment
pygame.draw.rect(screen, self.color, rect)
# Draw head differently
if i == 0:
pygame.draw.rect(screen, WHITE, rect, 2)
# Shield effect
if self.shield_time > 0:
shield_color = (*NEON_BLUE, 150)
pygame.draw.rect(screen, NEON_BLUE, rect, 3)
class NeonSnakeGame:
def __init__(self):
self.screen = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))
pygame.display.set_caption("Neon Snake Arena - Premium Edition")
self.clock = pygame.time.Clock()
self.font = pygame.font.Font(None, 36)
self.big_font = pygame.font.Font(None, 72)
# Game state
self.game_mode = GameMode.CLASSIC
self.running = True
self.game_active = False
self.paused = False
# Game objects
self.snakes = []
self.food = []
self.power_ups = []
self.particles = []
self.obstacles = []
# Game settings
self.speed = 8
self.max_food = 5
self.score_multiplier = 1
self.high_scores = self.load_high_scores()
# Visual effects
self.screen_shake = 0
self.glow_pulse = 0
self.setup_game()
def load_high_scores(self):
try:
if os.path.exists('high_scores.json'):
with open('high_scores.json', 'r') as f:
return json.load(f)
except:
pass
return {mode.value: [] for mode in GameMode}
def save_high_scores(self):
try:
with open('high_scores.json', 'w') as f:
json.dump(self.high_scores, f)
except:
pass
def setup_game(self):
self.snakes.clear()
self.food.clear()
self.power_ups.clear()
self.particles.clear()
self.obstacles.clear()
if self.game_mode == GameMode.MULTIPLAYER:
# Two players
self.snakes.append(Snake(GRID_WIDTH // 4, GRID_HEIGHT // 2, NEON_GREEN, 0))
self.snakes.append(Snake(3 * GRID_WIDTH // 4, GRID_HEIGHT // 2, NEON_PINK, 1))
self.snakes[1].direction = (-1, 0)
else:
# Single player
self.snakes.append(Snake(GRID_WIDTH // 2, GRID_HEIGHT // 2, NEON_GREEN, 0))
# Generate initial food
for _ in range(self.max_food):
self.spawn_food()
# Arena mode obstacles
if self.game_mode == GameMode.ARENA:
self.generate_arena_obstacles()
def generate_arena_obstacles(self):
# Create some walls in arena mode
for _ in range(random.randint(5, 10)):
x = random.randint(5, GRID_WIDTH - 5)
y = random.randint(5, GRID_HEIGHT - 5)
size = random.randint(2, 4)
for i in range(size):
for j in range(size):
if x + i < GRID_WIDTH and y + j < GRID_HEIGHT:
self.obstacles.append((x + i, y + j))
def spawn_food(self):
while True:
x = random.randint(0, GRID_WIDTH - 1)
y = random.randint(0, GRID_HEIGHT - 1)
# Don't spawn on snakes or obstacles
valid = True
for snake in self.snakes:
if (x, y) in snake.body:
valid = False
break
if (x, y) in self.obstacles:
valid = False
if valid:
self.food.append((x, y))
break
def spawn_power_up(self):
if len(self.power_ups) >= 3: # Max 3 power-ups
return
power_type = random.choice(list(PowerUpType))
colors = {
PowerUpType.SPEED_BOOST: NEON_YELLOW,
PowerUpType.SLOW_MOTION: NEON_BLUE,
PowerUpType.DOUBLE_POINTS: NEON_PURPLE,
PowerUpType.SHIELD: NEON_ORANGE,
PowerUpType.MAGNET: NEON_PINK
}
while True:
x = random.randint(0, GRID_WIDTH - 1)
y = random.randint(0, GRID_HEIGHT - 1)
# Don't spawn on snakes, food, or obstacles
valid = True
for snake in self.snakes:
if (x, y) in snake.body:
valid = False
break
if (x, y) in self.food or (x, y) in self.obstacles:
valid = False
if valid:
self.power_ups.append(PowerUp(x, y, power_type, 300, colors[power_type]))
break
def create_particles(self, x, y, color, count=10):
for _ in range(count):
velocity = (random.uniform(-3, 3), random.uniform(-3, 3))
life = random.randint(20, 40)
self.particles.append(Particle(x * GRID_SIZE, y * GRID_SIZE, color, velocity, life))
def handle_events(self):
for event in pygame.event.get():
if event.type == pygame.QUIT:
self.running = False
elif event.type == pygame.KEYDOWN:
if not self.game_active:
if event.key == pygame.K_SPACE:
self.game_active = True
self.setup_game()
elif event.key == pygame.K_1:
self.game_mode = GameMode.CLASSIC
elif event.key == pygame.K_2:
self.game_mode = GameMode.ARENA
elif event.key == pygame.K_3:
self.game_mode = GameMode.SURVIVAL
elif event.key == pygame.K_4:
self.game_mode = GameMode.MULTIPLAYER
elif self.game_active:
if event.key == pygame.K_p:
self.paused = not self.paused
elif event.key == pygame.K_ESCAPE:
self.game_active = False
# Player 1 controls
elif event.key == pygame.K_w:
self.snakes[0].change_direction((0, -1))
elif event.key == pygame.K_s:
self.snakes[0].change_direction((0, 1))
elif event.key == pygame.K_a:
self.snakes[0].change_direction((-1, 0))
elif event.key == pygame.K_d:
self.snakes[0].change_direction((1, 0))
# Player 2 controls (multiplayer)
if len(self.snakes) > 1:
if event.key == pygame.K_UP:
self.snakes[1].change_direction((0, -1))
elif event.key == pygame.K_DOWN:
self.snakes[1].change_direction((0, 1))
elif event.key == pygame.K_LEFT:
self.snakes[1].change_direction((-1, 0))
elif event.key == pygame.K_RIGHT:
self.snakes[1].change_direction((1, 0))
def update(self):
if not self.game_active or self.paused:
return
# Update snakes
for snake in self.snakes:
snake.move()
# Check food collision
for snake in self.snakes:
if not snake.alive:
continue
head_x, head_y = snake.body[0]
# Food collision
if (head_x, head_y) in self.food:
self.food.remove((head_x, head_y))
snake.grow(2)
snake.score += 10 * self.score_multiplier
self.create_particles(head_x, head_y, NEON_GREEN)
self.spawn_food()
# Chance to spawn power-up
if random.random() < 0.3:
self.spawn_power_up()
# Power-up collision
for power_up in self.power_ups[:]:
if head_x == power_up.x and head_y == power_up.y:
self.apply_power_up(snake, power_up)
self.power_ups.remove(power_up)
self.create_particles(head_x, head_y, power_up.color)
# Check snake collisions (multiplayer)
if self.game_mode == GameMode.MULTIPLAYER:
for i, snake1 in enumerate(self.snakes):
for j, snake2 in enumerate(self.snakes):
if i != j and snake1.alive and snake2.alive:
if snake1.body[0] in snake2.body:
if snake1.shield_time <= 0:
snake1.alive = False
# Update particles
self.particles = [p for p in self.particles if p.life > 0]
for particle in self.particles:
particle.update()
# Update power-ups
for power_up in self.power_ups[:]:
power_up.duration -= 1
if power_up.duration <= 0:
self.power_ups.remove(power_up)
# Check game over
alive_snakes = [s for s in self.snakes if s.alive]
if not alive_snakes:
self.game_over()
# Update visual effects
self.glow_pulse = (self.glow_pulse + 0.1) % (2 * math.pi)
if self.screen_shake > 0:
self.screen_shake -= 1
def apply_power_up(self, snake, power_up):
if power_up.type == PowerUpType.SPEED_BOOST:
self.speed = min(15, self.speed + 2)
elif power_up.type == PowerUpType.SLOW_MOTION:
self.speed = max(3, self.speed - 2)
elif power_up.type == PowerUpType.DOUBLE_POINTS:
self.score_multiplier = 2
elif power_up.type == PowerUpType.SHIELD:
snake.shield_time = 180
elif power_up.type == PowerUpType.MAGNET:
# Attract nearby food
for food_pos in self.food[:3]:
self.create_particles(food_pos[0], food_pos[1], NEON_PINK)
def game_over(self):
# Save high scores
for snake in self.snakes:
mode_scores = self.high_scores[self.game_mode.value]
mode_scores.append(snake.score)
mode_scores.sort(reverse=True)
self.high_scores[self.game_mode.value] = mode_scores[:10] # Keep top 10
self.save_high_scores()
self.game_active = False
def draw_glow_rect(self, surface, color, rect, glow_size=5):
for i in range(glow_size):
alpha = 255 // (i + 1)
glow_color = (*color, alpha)
expanded_rect = rect.inflate(i * 4, i * 4)
pygame.draw.rect(surface, color, expanded_rect)
def draw(self):
self.screen.fill(BLACK)
# Draw grid
for x in range(0, WINDOW_WIDTH, GRID_SIZE):
pygame.draw.line(self.screen, DARK_GRAY, (x, 0), (x, WINDOW_HEIGHT))
for y in range(0, WINDOW_HEIGHT, GRID_SIZE):
pygame.draw.line(self.screen, DARK_GRAY, (0, y), (WINDOW_WIDTH, y))
if self.game_active:
# Draw obstacles
for obs_x, obs_y in self.obstacles:
rect = pygame.Rect(obs_x * GRID_SIZE, obs_y * GRID_SIZE, GRID_SIZE, GRID_SIZE)
pygame.draw.rect(self.screen, NEON_BLUE, rect)
pygame.draw.rect(self.screen, WHITE, rect, 2)
# Draw food with pulsing glow
glow_intensity = int(50 + 30 * math.sin(self.glow_pulse))
for food_x, food_y in self.food:
rect = pygame.Rect(food_x * GRID_SIZE, food_y * GRID_SIZE, GRID_SIZE, GRID_SIZE)
glow_rect = rect.inflate(10, 10)
# Draw glow
pygame.draw.rect(self.screen, (*NEON_YELLOW, glow_intensity), glow_rect)
pygame.draw.rect(self.screen, NEON_YELLOW, rect)
pygame.draw.circle(self.screen, WHITE, rect.center, 3)
# Draw power-ups
for power_up in self.power_ups:
rect = pygame.Rect(power_up.x * GRID_SIZE, power_up.y * GRID_SIZE, GRID_SIZE, GRID_SIZE)
pygame.draw.rect(self.screen, power_up.color, rect)
pygame.draw.rect(self.screen, WHITE, rect, 2)
# Draw power-up symbol
center = rect.center
if power_up.type == PowerUpType.SPEED_BOOST:
pygame.draw.polygon(self.screen, WHITE, [(center[0]-5, center[1]),
(center[0]+5, center[1]-5),
(center[0]+5, center[1]+5)])
elif power_up.type == PowerUpType.SHIELD:
pygame.draw.circle(self.screen, WHITE, center, 6, 2)
# Draw snakes
for snake in self.snakes:
snake.draw(self.screen)
# Draw particles
for particle in self.particles:
particle.draw(self.screen)
# Draw UI
score_text = f"Score: {self.snakes[0].score}"
if len(self.snakes) > 1:
score_text += f" | P2: {self.snakes[1].score}"
text_surface = self.font.render(score_text, True, WHITE)
self.screen.blit(text_surface, (10, 10))
mode_text = f"Mode: {self.game_mode.value}"
mode_surface = self.font.render(mode_text, True, NEON_GREEN)
self.screen.blit(mode_surface, (10, 50))
if self.paused:
pause_text = self.big_font.render("PAUSED", True, NEON_YELLOW)
text_rect = pause_text.get_rect(center=(WINDOW_WIDTH//2, WINDOW_HEIGHT//2))
self.screen.blit(pause_text, text_rect)
else:
# Main menu
title = self.big_font.render("NEON SNAKE ARENA", True, NEON_GREEN)
title_rect = title.get_rect(center=(WINDOW_WIDTH//2, 150))
self.screen.blit(title, title_rect)
subtitle = self.font.render("Premium Edition", True, NEON_BLUE)
subtitle_rect = subtitle.get_rect(center=(WINDOW_WIDTH//2, 200))
self.screen.blit(subtitle, subtitle_rect)
# Menu options
menu_items = [
"1 - Classic Mode",
"2 - Arena Mode",
"3 - Survival Mode",
"4 - Multiplayer Mode",
"",
"SPACE - Start Game",
"WASD - Player 1 Controls",
"Arrow Keys - Player 2 Controls",
"P - Pause | ESC - Menu"
]
y_start = 300
for i, item in enumerate(menu_items):
color = NEON_PINK if item.startswith(str(list(GameMode).index(self.game_mode) + 1)) else WHITE
text = self.font.render(item, True, color)
text_rect = text.get_rect(center=(WINDOW_WIDTH//2, y_start + i * 40))
self.screen.blit(text, text_rect)
# High scores
high_score_title = self.font.render(f"High Scores - {self.game_mode.value}", True, NEON_YELLOW)
score_rect = high_score_title.get_rect(center=(WINDOW_WIDTH//2, y_start + len(menu_items) * 40 + 50))
self.screen.blit(high_score_title, score_rect)
scores = self.high_scores[self.game_mode.value][:5]
for i, score in enumerate(scores):
score_text = self.font.render(f"{i+1}. {score}", True, WHITE)
score_rect = score_text.get_rect(center=(WINDOW_WIDTH//2, y_start + len(menu_items) * 40 + 90 + i * 30))
self.screen.blit(score_text, score_rect)
pygame.display.flip()
def run(self):
while self.running:
self.handle_events()
self.update()
self.draw()
self.clock.tick(self.speed)
pygame.quit()
if __name__ == "__main__":
game = NeonSnakeGame()
game.run()