#!/usr/bin/env perl use strict; use warnings; use Time::HiRes qw(usleep); use utf8; use open qw(:std :utf8); use Term::ReadKey; # Define an expanded set of emojis my @emojis = ( '๐Ÿ˜Š', '๐Ÿ˜‚', '๐Ÿคฃ', '๐Ÿ˜', '๐Ÿฅฐ', '๐Ÿ˜˜', '๐Ÿ˜œ', '๐Ÿ˜Ž', '๐Ÿค”', '๐Ÿคฏ', '๐Ÿ‘', '๐Ÿ‘', '๐Ÿ™Œ', '๐ŸŽ‰', '๐ŸŽŠ', '๐ŸŽˆ', '๐ŸŽ', '๐Ÿ†', '๐Ÿฅ‡', '๐Ÿ…', 'โค๏ธ', '๐Ÿงก', '๐Ÿ’›', '๐Ÿ’š', '๐Ÿ’™', '๐Ÿ’œ', '๐Ÿ–ค', '๐Ÿค', '๐ŸคŽ', '๐Ÿ’”', '๐ŸŒŸ', 'โญ', 'โœจ', '๐Ÿ’ซ', '๐ŸŒˆ', 'โ˜€๏ธ', '๐ŸŒค๏ธ', 'โ›…', '๐ŸŒฅ๏ธ', 'โ˜๏ธ', '๐ŸŒŠ', '๐ŸŒด', '๐ŸŒต', '๐ŸŒท', '๐ŸŒน', '๐ŸŒบ', '๐ŸŒธ', '๐ŸŒผ', '๐Ÿ€', '๐Ÿ', '๐ŸŽ', '๐Ÿ', '๐ŸŠ', '๐Ÿ‹', '๐ŸŒ', '๐Ÿ‰', '๐Ÿ‡', '๐Ÿ“', '๐Ÿ’', '๐Ÿ‘', '๐Ÿ•', '๐Ÿ”', '๐ŸŸ', '๐ŸŒญ', '๐Ÿฟ', '๐Ÿง', '๐Ÿฉ', '๐Ÿฆ', '๐Ÿญ', '๐Ÿซ', '๐Ÿถ', '๐Ÿฑ', '๐Ÿญ', '๐Ÿน', '๐Ÿฐ', '๐ŸฆŠ', '๐Ÿป', '๐Ÿผ', '๐Ÿจ', '๐Ÿฏ', '๐Ÿš€', 'โœˆ๏ธ', '๐Ÿš—', '๐Ÿš•', '๐Ÿš™', '๐ŸšŒ', '๐ŸŽ๏ธ', '๐Ÿš“', '๐Ÿš’', '๐Ÿš‘' ); # Get terminal size my ($width, $height) = GetTerminalSize(); # Initialize emoji positions my @positions; for (1..25) { # Number of falling emojis push @positions, get_new_position(\@positions, 1); } # Hide cursor and enter alternate screen buffer print "\e[?25l"; print "\e[?1049h"; # Main loop while (1) { # Clear screen and move cursor to top-left print "\e[2J\e[H"; my $output = ''; for my $pos (@positions) { my ($x, $y, $emoji_index) = @$pos; $output .= "\e[${y};${x}H" . $emojis[$emoji_index]; $pos->[1]++; # Move emoji down if ($pos->[1] >= $height) { @$pos = @{get_new_position(\@positions, 0)}; } } print $output; usleep(50000); # Animation speed # Check for 'q' key to quit if (defined(my $key = ReadKey(-1))) { last if $key eq 'q'; } } # Show cursor and exit alternate screen buffer print "\e[?25h"; print "\e[?1049l"; # Restore normal terminal behavior ReadMode('normal'); sub get_new_position { my ($positions, $initial) = @_; my $min_distance = 3; # Minimum distance between emojis my $max_attempts = 100; # Maximum number of attempts to find a suitable position for (1..$max_attempts) { my $new_x = int(rand($width)); my $new_y = $initial ? int(rand($height)) : 0; # Random y for initial, 0 for resets my $new_emoji = int(rand(scalar @emojis)); my $is_far_enough = 1; for my $pos (@$positions) { my ($x, $y) = @$pos; if (abs($x - $new_x) < $min_distance && abs($y - $new_y) < $height / 4) { $is_far_enough = 0; last; } } if ($is_far_enough) { return [$new_x, $new_y, $new_emoji]; } } # If we couldn't find a suitable position after max attempts, just return a random one return [int(rand($width)), $initial ? int(rand($height)) : 0, int(rand(scalar @emojis))]; }