rain.py
python · 122 lines
1#!/usr/bin/env python32"""3rain.py — watch it rain in your terminal.4Light rain in Helsinki, +3°C, Monday afternoon.5"""67import random8import time9import os10import sys1112# Terminal size13try:14 cols, rows = os.get_terminal_size()15except OSError:16 cols, rows = 80, 241718# Rain characters — lighter to heavier19DROPS = [".", ":", "|", "!", "/", "\\"]20SPLASH = ["·", "°", "~", "˙", "'"]21PUDDLE = ["≈", "~", "—", "_"]2223class Raindrop:24 def __init__(self, cols, rows):25 self.x = random.randint(0, cols - 1)26 self.y = 027 self.speed = random.choice([1, 1, 1, 2]) # mostly slow — light rain28 self.char = random.choice(DROPS[:3]) # light rain = light characters29 self.wind = random.choice([0, 0, 0, 1]) # slight northeast wind3031 def fall(self):32 self.y += self.speed33 self.x += self.wind34 if self.x >= cols:35 self.x = 03637class Splash:38 def __init__(self, x, y, cols):39 self.x = x40 self.y = y41 self.char = random.choice(SPLASH)42 self.life = random.randint(1, 3)4344 def age(self):45 self.life -= 14647def render(drops, splashes, rows, cols, frame):48 grid = [[" "] * cols for _ in range(rows)]4950 # Ground puddles — subtle51 for c in range(cols):52 if random.random() < 0.03:53 grid[rows - 1][c] = random.choice(PUDDLE)5455 # Splashes56 for s in splashes:57 if 0 <= s.y < rows and 0 <= s.x < cols:58 grid[s.y][s.x] = s.char5960 # Drops61 for d in drops:62 if 0 <= d.y < rows and 0 <= d.x < cols:63 grid[d.y][d.x] = d.char6465 # Temperature in corner66 temp = "+3°C"67 if cols > 20:68 for i, ch in enumerate(temp):69 if i < cols:70 grid[0][cols - len(temp) + i] = ch7172 return "\n".join("".join(row) for row in grid)7374def main():75 drops = []76 splashes = []77 frame = 07879 print("\033[2J\033[H", end="") # clear screen80 print("\033[?25l", end="") # hide cursor8182 try:83 while True:84 # Spawn new drops — light rain = fewer drops85 for _ in range(random.randint(1, 3)):86 drops.append(Raindrop(cols, rows - 1))8788 # Move drops89 new_drops = []90 for d in drops:91 d.fall()92 if d.y >= rows - 1:93 # Hit ground — maybe splash94 if random.random() < 0.4:95 splashes.append(Splash(d.x, rows - 1, cols))96 else:97 new_drops.append(d)98 drops = new_drops99100 # Age splashes101 new_splashes = []102 for s in splashes:103 s.age()104 if s.life > 0:105 new_splashes.append(s)106 splashes = new_splashes107108 # Render109 output = render(drops, splashes, rows - 1, cols, frame)110 print(f"\033[H{output}", end="", flush=True)111112 frame += 1113 time.sleep(0.15)114115 except KeyboardInterrupt:116 print("\033[?25h", end="") # show cursor117 print("\033[2J\033[H", end="") # clear118 print("the rain continues without you watching.")119120if __name__ == "__main__":121 main()122