#!/usr/bin/env python
#
# Snow Simulator -- Heavily modified version of the pygame 'stars.py' simple starfield example
# Glen Greer
# 2007

import math
import pygame
import pygame.locals
import random

# Constants
WINSIZE = [640, 480]
NUMFLAKES = 350
SNOW = (255, 255, 255)
BACKGROUND = (20, 20, 40, 255)
ICE = (127, 127, 255, 255)
STATIONARY = (250, 250, 250, 255)
RED = (255, 127, 127)
GREEN = (127, 255, 127)

def init_flake(i):
    return i, SNOW, (random.randrange(WINSIZE[0]), -2 * random.randrange(WINSIZE[1]))

def initialize_flakes():
    return [init_flake(i) for i in range(NUMFLAKES)]

def draw_flakes(surface, flakes, color):
    for i, type, pos in flakes:
        pos = (int(pos[0]), int(pos[1]))
        surface.set_at(pos, color)

def new_pos(surface, pos, dir, y_dir=1):
    new = [pos[0] + dir, pos[1] + y_dir]
    if (new[0] < 0):
        new[0] = WINSIZE[0] - 1
    elif (new[0] >= WINSIZE[0]):
        new[0] = 0
    if (0 <= new[1] < WINSIZE[1]):
        dest = surface.get_at(new)
    else:
        dest = BACKGROUND
    return tuple(new), dest

def move_flakes(surface, flakes):
    for i, type, pos in flakes:
        dir = 1 - (2 * random.randrange(2))
        new, dest = new_pos(surface, pos, dir)
        if (BACKGROUND == dest):
            if (ICE == type):
                up, updest = new_pos(surface, pos, 0, -1)
                if (BACKGROUND == updest):
                    flakes[i] = i, type, new
                else:
                    surface.set_at(pos, ICE)
                    flakes[i] = init_flake(i)
            else:
                flakes[i] = i, type, new
        else:
            type = ICE
            dir *= -1
            new, dest = new_pos(surface, pos, dir)
            if (BACKGROUND == dest):
                flakes[i] = i, type, new
            else:
                dir = 0
                new, dest = new_pos(surface, pos, dir)
                if (BACKGROUND == dest):
                    flakes[i] = i, type, new
                else:
                    surface.set_at(pos, STATIONARY)
                    flakes[i] = init_flake(i)

def main():
    pygame.init()
    random.seed()
    pygame.display.set_caption('Snow')
    screen = pygame.display.set_mode(WINSIZE)

    flakes = initialize_flakes()

    screen.fill(BACKGROUND)
    pygame.draw.line(screen, GREEN, (0, WINSIZE[1] - 1), (WINSIZE[0] - 1, WINSIZE[1] - 1))

    done = 0
    while not done:
        draw_flakes(screen, flakes, BACKGROUND)
        move_flakes(screen, flakes)
        draw_flakes(screen, flakes, SNOW)
        pygame.display.update()
        for e in pygame.event.get():
            if e.type == pygame.locals.QUIT or (e.type == pygame.locals.KEYUP and e.key == pygame.locals.K_ESCAPE):
                done = 1
                break
            elif e.type == pygame.locals.MOUSEBUTTONDOWN and e.button == 1:
                pygame.draw.circle(screen, RED, e.pos, 10)

if __name__ == '__main__':
    main()

