RabbitFarm

2021-03-14

The Weekly Challenge 103: Astrology and Audio

The examples used here are from the weekly challenge problem statement and demonstrate the working solution.

Part 1

You are given a year $year. Write a script to determine the Chinese Zodiac for the given year $year.

Solution


use strict;
use warnings;
##
# You are given a year $year.
# Write a script to determine the Chinese Zodiac for the given year $year
##
use constant ELEMENTS => {1 => q/Wood/, 2 => q/Fire/, 3 => q/Earth/, 4 => q/Metal/, 0 => q/Water/};
use constant ANIMALS =>  {1 => q/Rat/, 2 => q/Ox/, 3 => q/Tiger/, 4 => q/Rabbit/, 5 => q/Dragon/, 6 => q/Snake/, 7 => q/Horse/, 8 => q/Goat/, 9 => q/Monkey/, 10 => q/Rooster/, 11 => q/Dog/, 0 => q/Pig/}; 

sub chinese_zodiac{
    my($year) = @_;
    return ELEMENTS->{$year % 5} . " " . ANIMALS->{($year + 9) % 12};    
} 

MAIN:{
    my($YEAR);
    $YEAR = 2017;
    print chinese_zodiac($YEAR) . "\n";
    $YEAR = 1938;
    print chinese_zodiac($YEAR) . "\n";
}  

Sample Run


$ perl perl/ch-1.pl
Fire Rooster
Earth Tiger

Notes

When I first saw the problem statement for this part of the challenge I took a look at the cited Wikipedia article, but it just seemed like a real slog of a read. So I decided to just work backwards from the examples given! Pretty much this seems to boil down to a straightforward modular arithmetic problem. The values are all known and so I hard code then with use constant and then use them directly.

Part 2

Write a program to output which file is currently playing.

Solution


use strict;
use warnings;

sub song_times{
    my($file_name) = @_; 
    my %song_times;
    my @song_order;
    my $length = 0; 
    my $index = 0;  
    if(!$file_name){
        while(){
            chomp; 
            my($time, $song) = split(/,/);       
            $length += $time; 
            $song_order[$index] =  $song; 
            $song_times{$song} =  $time; 
            $index++; 
        } 
    } 
    else{
        open(FILE, $file_name); 
        while(){
            chomp; 
            my($time, $song) = split(/,/);       
            $length += $time; 
            $song_order[$song] =  $index; 
            $song_times{$song} =  $time; 
            $index++; 
        } 
    } 
    return [\%song_times, \@song_order, $length];   
}

sub now_playing{
    my($start_time, $current_time, $file_name) = @_; 
    my($song_times, $song_order, $length_millis);
    $current_time = time() if !$current_time; 
    ($song_times, $song_order, $length_millis) = @{song_times()} if $file_name;   
    ($song_times, $song_order, $length_millis) = @{song_times($file_name)} if !$file_name;   
    my $time_playing = $current_time - $start_time;
    my $cycles = ($time_playing * 1000) / $length_millis;  
    my $current_cycle_millis = ($cycles - int($cycles)) * $length_millis;  
    my $seek_time = 0; 
    for my $song (@{$song_order}){
        $seek_time += $song_times->{$song};
        if($seek_time > $current_cycle_millis){
            my $position = ($song_times->{$song} - ($seek_time - $current_cycle_millis)) / 1000; 
            my $hours = int($position/3600);
            my $minutes = int(($position % 3600) / 60);
            my $seconds = int(($position % 3600) % 60);
            $position = sprintf("%02d", $hours) . ":" . sprintf("%02d", $minutes) . ":" . sprintf("%02d", $seconds);    
            return ($song, $position);  
        }   
    }  
}  

MAIN:{
    my($song, $position) =  now_playing(1606134123, 1614591276);   
    print "$song\n$position\n";  
}  

__DATA__
1709363,"Les Miserables Episode 1: The Bishop (broadcast date: 1937-07-23)"
1723781,"Les Miserables Episode 2: Javert (broadcast date: 1937-07-30)"
1723781,"Les Miserables Episode 3: The Trial (broadcast date: 1937-08-06)"
1678356,"Les Miserables Episode 4: Cosette (broadcast date: 1937-08-13)"
1646043,"Les Miserables Episode 5: The Grave (broadcast date: 1937-08-20)"
1714640,"Les Miserables Episode 6: The Barricade (broadcast date: 1937-08-27)"
1714640,"Les Miserables Episode 7: Conclusion (broadcast date: 1937-09-03)"

Sample Run


$ perl perl/ch-2.pl
"Les Miserables Episode 1: The Bishop (broadcast date: 1937-07-23)"
00:10:24

Notes

I have to say that I found this deceptively harder to implement than it first appears! I suppose that is always true when working with time.

In the spirit of good sportsmanship wrote the code to fit the specification given, but then allow for defaults, such as reading from <DATA> and using the value of time().

The way this works here is:

References

Challenge 103 Chinese Zodiac

posted at: 16:46 by: Adam Russell | path: /perl | permanent link to this entry