โถ Run Project
๐ fireworks.py
โ entry point
"""
๐ ASCII Fireworks Show ๐
Run this in your terminal for a colorful fireworks display!
"""
import random
import time
import math
# ANSI color codes
COLORS = [
"\033[91m", # Red
"\033[92m", # Green
"\033[93m", # Yellow
"\033[94m", # Blue
"\033[95m", # Magenta
"\033[96m", # Cyan
"\033[97m", # White
]
RESET = "\033[0m"
CLEAR = "\033[2J\033[H"
PARTICLES = ["โ
", "โฆ", "โข", "โ", "โธ", "โบ", "โป", "โ", "โท", "*", "ยท", "+"]
WIDTH = 80
HEIGHT = 24
class Particle:
def __init__(self, x, y, vx, vy, color, char, lifetime):
self.x = x
self.y = y
self.vx = vx
self.vy = vy
self.color = color
self.char = char
self.lifetime = lifetime
self.age = 0
self.gravity = 0.15
def update(self):
self.x += self.vx
self.y += self.vy
self.vy += self.gravity
self.vx *= 0.97
self.age += 1
def is_alive(self):
return self.age < self.lifetime and 0 <= self.x < WIDTH and 0 <= self.y < HEIGHT
class Firework:
def __init__(self):
self.x = random.randint(10, WIDTH - 10)
self.launch_y = HEIGHT - 1
self.target_y = random.randint(3, HEIGHT // 2)
self.vy = -random.uniform(0.8, 1.4)
self.y = float(self.launch_y)
self.color = random.choice(COLORS)
self.exploded = False
self.particles = []
self.trail = []
def update(self):
if not self.exploded:
self.y += self.vy
self.trail.append((int(self.x), int(self.y)))
if len(self.trail) > 4:
self.trail.pop(0)
if self.y <= self.target_y:
self.explode()
else:
self.particles = [p for p in self.particles if p.is_alive()]
for p in self.particles:
p.update()
def explode(self):
self.exploded = True
num_particles = random.randint(20, 35)
char = random.choice(PARTICLES)
second_color = random.choice(COLORS)
for i in range(num_particles):
angle = (2 * math.pi / num_particles) * i + random.uniform(-0.2, 0.2)
speed = random.uniform(0.4, 1.6)
vx = math.cos(angle) * speed
vy = math.sin(angle) * speed * 0.6
color = self.color if i % 2 == 0 else second_color
lifetime = random.randint(12, 22)
self.particles.append(
Particle(self.x, self.y, vx, vy, color, char, lifetime)
)
def is_alive(self):
if not self.exploded:
return True
return len(self.particles) > 0
def render(fireworks, frame):
grid = [[" " for _ in range(WIDTH)] for _ in range(HEIGHT)]
color_grid = [["" for _ in range(WIDTH)] for _ in range(HEIGHT)]
# Draw ground
ground_msg = " ๐ ASCII FIREWORKS SHOW โ Press Ctrl+C to exit ๐ "
for i, ch in enumerate(ground_msg):
if i < WIDTH:
grid[HEIGHT - 1][i] = ch
color_grid[HEIGHT - 1][i] = "\033[93m"
for fw in fireworks:
if not fw.exploded:
# Draw trail
trail_chars = ["ยท", "ยท", ":", "|"]
for idx, (tx, ty) in enumerate(fw.trail):
if 0 <= ty < HEIGHT and 0 <= tx < WIDTH:
grid[ty][tx] = trail_chars[min(idx, len(trail_chars) - 1)]
color_grid[ty][tx] = fw.color
# Draw rocket
rx, ry = int(fw.x), int(fw.y)
if 0 <= ry < HEIGHT and 0 <= rx < WIDTH:
grid[ry][rx] = "^"
color_grid[ry][rx] = fw.color
else:
for p in fw.particles:
px, py = int(p.x), int(p.y)
if 0 <= py < HEIGHT and 0 <= px < WIDTH:
# Fade effect: use dimmer char near end of life
fade = p.age / p.lifetime
ch = p.char if fade < 0.6 else ("ยท" if fade < 0.85 else ".")
grid[py][px] = ch
color_grid[py][px] = p.color
# Build output string
lines = []
for row in range(HEIGHT):
line = ""
for col in range(WIDTH):
ch = grid[row][col]
color = color_grid[row][col]
if color:
line += f"{color}{ch}{RESET}"
else:
line += ch
lines.append(line)
# Twinkling stars in background
stars = ["ยท", ".", "*", " "]
random.seed(frame // 3) # Slow twinkle
star_positions = [(random.randint(0, WIDTH - 1), random.randint(0, HEIGHT - 3)) for _ in range(15)]
output = CLEAR
for row_idx, line in enumerate(lines):
output += line + "\n"
print(output, end="", flush=True)
def main():
fireworks = []
frame = 0
launch_countdown = 0
# Hide cursor
print("\033[?25l", end="")
try:
while True:
# Launch new fireworks periodically
if launch_countdown <= 0:
count = random.randint(1, 2)
for _ in range(count):
fireworks.append(Firework())
launch_countdown = random.randint(8, 20)
else:
launch_countdown -= 1
# Update
fireworks = [fw for fw in fireworks if fw.is_alive()]
for fw in fireworks:
fw.update()
# Render
render(fireworks, frame)
frame += 1
time.sleep(0.06)
except KeyboardInterrupt:
print("\033[?25h") # Restore cursor
print(CLEAR)
print("\033[93m๐ Thanks for watching! ๐\033[0m\n")
if __name__ == "__main__":
main()