Perlで雪を降らす

ソース

#!perl
use strict;
use warnings;

use Encode ();
use Time::HiRes ();
use Term::ReadKey ();

local $| = 1;

my %snowflakes;
my ($columns, $rows) = get_terminal_size();

main();

sub clear_screen {
    my @cmd;
    if ($^O eq 'MSWin32') {
        @cmd = qw/cls/;
    } else {
        @cmd = qw/clear/;
    }

    system(@cmd) == 0 or die "Can't exec '@cmd'";
}

sub get_terminal_size {
    my ($width, $height) = Term::ReadKey::GetTerminalSize(*STDIN);
    return ($width, $height);
}

sub get_random_flake {
    return " *" if $^O eq 'MSWin32';

    my $flake_num = 0x2749 - 0x2740;
    my $flake = int(rand($flake_num)) + 0x2740;
    return Encode::encode('utf-8', chr($flake));
}

sub move_flake {
    my $col = shift;

    my $flake_info = $snowflakes{$col};

    if ($flake_info->[0] + 1 == $rows) {
        $snowflakes{$col} = [1, get_random_flake()];
    } else {
        printf "\033[%s;%sH  ", $flake_info->[0], $col;
        $flake_info->[0] += 1;
        printf "\033[%s;%sH%s", $flake_info->[0], $col, $flake_info->[1];
        printf "\033[1;1H";
    }
}

sub main {
    clear_screen();

    while (1) {
        my $col = int(rand($columns)) + 1;

        if (exists $snowflakes{$col}) {
            move_flake($col);
        } else {
            my $flake = get_random_flake();

            printf "\033[%s;%sH%s", 1, $col, $flake;
            $snowflakes{$col} = [1, $flake];
        }

        for my $flake (keys %snowflakes) {
            move_flake($flake);
        }

        Time::HiRes::sleep(0.1);
    }
}

面白いですね。こういう発想ができるセンスのいいプログラマ
なりたいものです。