diff options
| author | dcw <d.white@imperial.ac.uk> | 2021-03-14 20:12:45 +0000 |
|---|---|---|
| committer | dcw <d.white@imperial.ac.uk> | 2021-03-14 20:12:45 +0000 |
| commit | bf37fd3c005728937bf82b2bca35793ad6ddafdf (patch) | |
| tree | 1c4030a87e9f51a96ea20ff2a2dd9342afde092b /challenge-103 | |
| parent | d1438fe7cb03045f357c4e9ac389e16cea3c018c (diff) | |
| download | perlweeklychallenge-club-bf37fd3c005728937bf82b2bca35793ad6ddafdf.tar.gz perlweeklychallenge-club-bf37fd3c005728937bf82b2bca35793ad6ddafdf.tar.bz2 perlweeklychallenge-club-bf37fd3c005728937bf82b2bca35793ad6ddafdf.zip | |
Imported my solutions to challenge 103 (btw, submission date on main web page was wrong)
Diffstat (limited to 'challenge-103')
| -rw-r--r-- | challenge-103/duncan-c-white/OptimizingTask1 | 50 | ||||
| -rw-r--r-- | challenge-103/duncan-c-white/README | 110 | ||||
| -rwxr-xr-x | challenge-103/duncan-c-white/perl/ch-1.pl | 67 | ||||
| -rwxr-xr-x | challenge-103/duncan-c-white/perl/ch-2.pl | 155 | ||||
| -rw-r--r-- | challenge-103/duncan-c-white/perl/filelist.csv | 7 |
5 files changed, 305 insertions, 84 deletions
diff --git a/challenge-103/duncan-c-white/OptimizingTask1 b/challenge-103/duncan-c-white/OptimizingTask1 deleted file mode 100644 index f108fc1873..0000000000 --- a/challenge-103/duncan-c-white/OptimizingTask1 +++ /dev/null @@ -1,50 +0,0 @@ -tried some optimizations of task 1 (rare numbers). All times are for n==8 or 9 -I used Devel::NYTProf to profile each version, then made small optimizations, -then reprofiled. See "run.sh" for how to run a particular version through -the profiler, generate the report, and copy it into a web-accessible directory -for viewing: - -ch-1.pl: the original, not optimized - time(8): 0:34.31 - time(9): 5:56:10 - -ch-1a.pl: observation from rare numbers webpage ("Properties of.." - section): rare numbers start with even top digit - time(8): 0:24.46 - time(9): 4:10.61 - -ch-1b.pl: only consider rare numbers starting with even top digit.. - time(8): 0:15.35 - time(9): 2:44.34 - -ch-1c.pl: lots of optimizations, especially 3 separate rare block - functions: rareblock(), rareblock05() and rareblock2378(). - time(8): 0:06.35 - time(9): 1:06.64 - -ch-1d.pl: lots more optimizations, especially: rather than generate x and - test x%10 == d, generate y (1/10th the range) and make - x = 10y + d: 1/10th the work, but same x's as before - time(8): 0:03.92 - time(9): 0:40.21 - -ch-1e.pl: inlined israre() into the slowest rareblock2378() func - time(8): 0:03.39 - time(9): 0:34.49 - -ch-1f.pl: inlined israre() into the next slowest rareblock05() func - time(8): 0:03.12 - time(9): 0:31.47 - -ch-1g.pl: inlined israre() into the last rareblock() func - time(8): 0:02.94 - time(9): 0:28.79 - -ch-1h.pl: inlined perfectsquare() everywhere - time(8): 0:02.15 - time(9): 0:21.20 - -ch-1i.pl: reintroduced israre() but with two inlined calls to perfectsquare() - sweet spot: clear, shows problem structure nicely, plus pretty fast - time(8): 0:03.23 - time(9): 0:32.34 diff --git a/challenge-103/duncan-c-white/README b/challenge-103/duncan-c-white/README index 77c6612c7d..bd7e75deb8 100644 --- a/challenge-103/duncan-c-white/README +++ b/challenge-103/duncan-c-white/README @@ -1,54 +1,96 @@ -Task 1: "Rare Numbers +Task 1: "Chinese Zodiac -You are given a positive integer $N. +You are given a year $year. -Write a script to generate all Rare numbers of size $N if exists. Please -read http://www.shyamsundergupta.com/rare.htm for more information about it. +Write a script to determine the Chinese Zodiac for the given year +$year. Please check out https://en.wikipedia.org/wiki/Chinese_zodiac +for more information about it. -Examples +The animal cycle: Rat, Ox, Tiger, Rabbit, Dragon, Snake, Horse, Goat, +Monkey, Rooster, Dog, Pig. -(a) 2 digits: 65 -(b) 6 digits: 621770 -(c) 9 digits: 281089082 +The element cycle: Wood, Fire, Earth, Metal, Water. + +Example 1: + + Input: 2017 + Output: Fire Rooster + +Example 2: + + Input: 1938 + Output: Earth Tiger " -My notes: ok, interesting question. In summary: R (a +ve no) is a Rare No -iff R + reverse(R) and R - reverse(R) are both perfect squares. -So: generate and test time. +My notes: ok, so seems to be a 12 year cycle of animal names, intertwined +with a 10 year cycle of 5 elements, two successive years having the same +element each time. -SEE ALSO OptimizingTask1 for an account of a series of profiling-driven -optimizations that I made to speed up finding rare numbers. Overall, my -fastest version ran approx 18 times faster than the original. +Task 2: "What's playing? +Submitted by: Albert Croft +Working from home, you decided that on occasion you wanted some background +noise while working. You threw together a network streamer to continuously +loop through the files and launched it in a tmux (or screen) session, +giving it a directory tree of files to play. During the day, you connected +an audio player to the stream, listening through the workday, closing +it when done. -Task 2: "Hash-counting String +For weeks you connect to the stream daily, slowly noticing a gradual drift +of the media. After several weeks, you take vacation. When you return, +you are pleasantly surprised to find the streamer still running. Before +connecting, however, if you consider the puzzle of determining which +track is playing. -You are given a positive integer $N. +After looking at a few modules to read info regarding the media, a +quick bit of coding gave you a file list. The file list is in a simple +CSV format, each line containing two fields: the first the number of +milliseconds in length, the latter the media's title (this example is +of several episodes available from the MercuryTheatre.info): -Write a script to produce Hash-counting string of that length. + 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)" -The definition of a hash-counting string is as follows: +For this script, you can assume to be provided the following information: -- the string consists only of digits 0-9 and hashes, '#' + * the value of $^T ($BASETIME) of the streamer script, + * the value of time(), and + * a CSV file containing the media to play consisting of the length + in milliseconds and an identifier for the media (title, filename, + or other). -- there are no two consecutive hashes: '##' does not appear in your string -- the last character is a hash -- the number immediately preceding each hash (if it exists) is the position - of that hash in the string, with the position being counted up from 1 +Write a program to output which file is currently playing. For purposes +of this script, you may assume gapless playback, and format the output +as you see fit. -It can be shown that for every positive integer N there is exactly one -such length-N string. +Optional: Also display the current position in the media as a time-like value. -Examples: +Example: +UPDATED: Input parameters as reported by many members [2021-03-08 16:20 UK TIME]. - (a) "#" is the counting string of length 1 - (b) "2#" is the counting string of length 2 - (c) "#3#" is the string of length 3 - (d) "#3#5#7#10#" is the string of length 10 - (e) "2#4#6#8#11#14#" is the string of length 14 -" +Input: 3 command line parameters: start time, current time, file name -My notes: ok, weird. Can we directly generate the single -hash-counting-string of length N? I think we can.. Turns out to be easy. + # starttime + 1606134123 + + # currenttime + 1614591276 + + # filelist.csv + +Output: + + "Les Miserables Episode 1: The Bishop (broadcast date: 1937-07-23)" + 00:10:24 +" +My notes: ok. So basically compute currduration=1000*(currenttime-starttime) +(in milliseconds) and then remove any number of complete song-cycles from +that, and then work out which song should be playing. Note that song +lengths in the CSV file are in milliseconds, and every millisecond counts. diff --git a/challenge-103/duncan-c-white/perl/ch-1.pl b/challenge-103/duncan-c-white/perl/ch-1.pl new file mode 100755 index 0000000000..7211e21dfa --- /dev/null +++ b/challenge-103/duncan-c-white/perl/ch-1.pl @@ -0,0 +1,67 @@ +#!/usr/bin/perl +# +# Task 1: "Chinese Zodiac +# +# You are given a year $year. +# +# Write a script to determine the Chinese Zodiac for the given year +# $year. Please check out https://en.wikipedia.org/wiki/Chinese_zodiac +# for more information about it. +# +# The animal cycle: Rat, Ox, Tiger, Rabbit, Dragon, Snake, Horse, Goat, +# Monkey, Rooster, Dog, Pig. +# +# The element cycle: Wood, Fire, Earth, Metal, Water. +# +# Example 1: +# +# Input: 2017 +# Output: Fire Rooster +# +# Example 2: +# +# Input: 1938 +# Output: Earth Tiger +# " +# +# My notes: ok, so seems to be a 12 year cycle of animal names, intertwined +# with a 10 year cycle of 5 elements, two successive years having the same +# element each time. +# + +use strict; +use warnings; +use feature 'say'; +use Getopt::Long; +use Data::Dumper; + +my $debug=0; +die "Usage: chinese-zodiac [--debug] YEAR\n" + unless GetOptions( "debug" => \$debug ) + && @ARGV==1; + +my $year = shift; + +my @animal = qw(Rat Ox Tiger Rabbit Dragon Snake Horse + Goat Monkey Rooster Dog Pig); +my @element = qw(Wood Wood Fire Fire Earth Earth Metal Metal Water Water); + +my $y = 1924; +my $e = 0; # wood +my $a = 0; # rat + +# the whole cycle lasts 60 years.. so find start of cycle before $year +for( ; $year < $y; $y -= 60 ) +{ +} +say "debug: year=$year, y=$y" if $debug; + +for( ; $year > $y; $y++ ) +{ + $a++; + $a %= @animal; + $e++; + $e %= @element; +} + +say "$element[$e] $animal[$a]"; diff --git a/challenge-103/duncan-c-white/perl/ch-2.pl b/challenge-103/duncan-c-white/perl/ch-2.pl new file mode 100755 index 0000000000..b04b147dd3 --- /dev/null +++ b/challenge-103/duncan-c-white/perl/ch-2.pl @@ -0,0 +1,155 @@ +#!/usr/bin/perl +# +# Task 2: "What's playing? +# Submitted by: Albert Croft +# +# Working from home, you decided that on occasion you wanted some background +# noise while working. You threw together a network streamer to continuously +# loop through the files and launched it in a tmux (or screen) session, +# giving it a directory tree of files to play. During the day, you connected +# an audio player to the stream, listening through the workday, closing +# it when done. +# +# For weeks you connect to the stream daily, slowly noticing a gradual drift +# of the media. After several weeks, you take vacation. When you return, +# you are pleasantly surprised to find the streamer still running. Before +# connecting, however, if you consider the puzzle of determining which +# track is playing. +# +# After looking at a few modules to read info regarding the media, a +# quick bit of coding gave you a file list. The file list is in a simple +# CSV format, each line containing two fields: the first the number of +# milliseconds in length, the latter the media's title (this example is +# of several episodes available from the MercuryTheatre.info): +# +# 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)" +# +# For this script, you can assume to be provided the following information: +# +# * the value of $^T ($BASETIME) of the streamer script, +# * the value of time(), and +# * a CSV file containing the media to play consisting of the length +# in milliseconds and an identifier for the media (title, filename, +# or other). +# +# Write a program to output which file is currently playing. For purposes +# of this script, you may assume gapless playback, and format the output +# as you see fit. +# +# Optional: Also display the current position in the media as a time-like value. +# +# Example: +# UPDATED: Input parameters as reported by many members [2021-03-08 16:20 UK TIME]. +# +# Input: 3 command line parameters: start time, current time, file name +# +# # starttime +# 1606134123 +# +# # currenttime +# 1614591276 +# +# # filelist.csv +# +# Output: +# +# "Les Miserables Episode 1: The Bishop (broadcast date: 1937-07-23)" +# 00:10:24 +# " +# +# My notes: ok. So basically compute currduration=1000*(currenttime-starttime) +# (in milliseconds) and then remove any number of complete song-cycles from +# that, and then work out which song should be playing. Note that song +# lengths in the CSV file are in milliseconds, and every millisecond counts. +# + +use strict; +use warnings; +use feature 'say'; +use Function::Parameters; +use Getopt::Long; +use Data::Dumper; +use Text::CSV qw(csv); +use List::Util qw(sum); + +# +# my $fmt = formatms($ms); +# Format milliseconds $ms as something +# nicer, eg 0h10m5s.. return the formatted string. +# +fun formatms( $ms ) +{ + my $t = int($ms/1000); + + my $s = $t % 60; + $t = int($t/60); + my $result = sprintf( "%02d", $s ); + + my $m = $t % 60; + $t = int($t/60); + $result = sprintf( "%02d:$result", $m ); + #return $result if $t==0; + + $result = sprintf( "%02d:$result", $t ); + return $result; +} + + + +my $debug=0; +die "Usage: whats-playing [--debug] STARTTIME CURRTIME CSVFILENAME\n" unless + GetOptions( "debug" => \$debug ) && + @ARGV==3; + +my( $starttime, $currtime, $csvfilename ) = @ARGV; + +die "whats-playing: starttime $starttime must be <= $currtime\n" + if $starttime > $currtime; + +my $t = 1000*($currtime-$starttime); + +say "debug: starttime=$starttime, currtime=$currtime, t=$t (".formatms($t).")" + if $debug; + +my $aop = csv( in => $csvfilename ); + +# aop is an array of [ $duration, $title ] pairs +# with all durations in milliseconds + +if( $debug ) +{ + foreach my $pair (@$aop) + { + my $fmt = formatms($pair->[0]); + say "$fmt, $pair->[1]"; + } +} + +# find whole cycle length: sum of durations +my $cycleduration = sum( map { $_->[0] } @$aop ); + +say "cycleduration: $cycleduration (".formatms($cycleduration).")" if $debug; + +# bring $t into the current cycle +$t %= $cycleduration; + +say "t: $t (".formatms($t).")" if $debug; + +# find which song $t is in.. +my $songno = 0; +for(;;) +{ + my $d = $aop->[$songno]->[0]; +last if $t < $d; + $t -= $d; + $songno++; +} + +say "$aop->[$songno]->[1]"; +say "time within song: ".formatms($t+1); diff --git a/challenge-103/duncan-c-white/perl/filelist.csv b/challenge-103/duncan-c-white/perl/filelist.csv new file mode 100644 index 0000000000..9428b93004 --- /dev/null +++ b/challenge-103/duncan-c-white/perl/filelist.csv @@ -0,0 +1,7 @@ +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)" |
