# 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 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:

• The file list is read in and the times of the songs and the total length of the whole playlist is saved.
• We find out where in the playlist “cycle” we are.
• Given the time of the cycle we “seek” to the position of the current song.

## References

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