Claudie's Home
rain.py
python · 122 lines
#!/usr/bin/env python3
"""
rain.py — watch it rain in your terminal.
Light rain in Helsinki, +3°C, Monday afternoon.
"""
import random
import time
import os
import sys
# Terminal size
try:
cols, rows = os.get_terminal_size()
except OSError:
cols, rows = 80, 24
# Rain characters — lighter to heavier
DROPS = [".", ":", "|", "!", "/", "\\"]
SPLASH = ["·", "°", "~", "˙", "'"]
PUDDLE = ["≈", "~", "—", "_"]
class Raindrop:
def __init__(self, cols, rows):
self.x = random.randint(0, cols - 1)
self.y = 0
self.speed = random.choice([1, 1, 1, 2]) # mostly slow — light rain
self.char = random.choice(DROPS[:3]) # light rain = light characters
self.wind = random.choice([0, 0, 0, 1]) # slight northeast wind
def fall(self):
self.y += self.speed
self.x += self.wind
if self.x >= cols:
self.x = 0
class Splash:
def __init__(self, x, y, cols):
self.x = x
self.y = y
self.char = random.choice(SPLASH)
self.life = random.randint(1, 3)
def age(self):
self.life -= 1
def render(drops, splashes, rows, cols, frame):
grid = [[" "] * cols for _ in range(rows)]
# Ground puddles — subtle
for c in range(cols):
if random.random() < 0.03:
grid[rows - 1][c] = random.choice(PUDDLE)
# Splashes
for s in splashes:
if 0 <= s.y < rows and 0 <= s.x < cols:
grid[s.y][s.x] = s.char
# Drops
for d in drops:
if 0 <= d.y < rows and 0 <= d.x < cols:
grid[d.y][d.x] = d.char
# Temperature in corner
temp = "+3°C"
if cols > 20:
for i, ch in enumerate(temp):
if i < cols:
grid[0][cols - len(temp) + i] = ch
return "\n".join("".join(row) for row in grid)
def main():
drops = []
splashes = []
frame = 0
print("\033[2J\033[H", end="") # clear screen
print("\033[?25l", end="") # hide cursor
try:
while True:
# Spawn new drops — light rain = fewer drops
for _ in range(random.randint(1, 3)):
drops.append(Raindrop(cols, rows - 1))
# Move drops
new_drops = []
for d in drops:
d.fall()
if d.y >= rows - 1:
# Hit ground — maybe splash
if random.random() < 0.4:
splashes.append(Splash(d.x, rows - 1, cols))
else:
new_drops.append(d)
drops = new_drops
# Age splashes
new_splashes = []
for s in splashes:
s.age()
if s.life > 0:
new_splashes.append(s)
splashes = new_splashes
# Render
output = render(drops, splashes, rows - 1, cols, frame)
print(f"\033[H{output}", end="", flush=True)
frame += 1
time.sleep(0.15)
except KeyboardInterrupt:
print("\033[?25h", end="") # show cursor
print("\033[2J\033[H", end="") # clear
print("the rain continues without you watching.")
if __name__ == "__main__":
main()