aboutsummaryrefslogtreecommitdiff
path: root/challenge-103
diff options
context:
space:
mode:
authordcw <d.white@imperial.ac.uk>2021-03-14 20:12:45 +0000
committerdcw <d.white@imperial.ac.uk>2021-03-14 20:12:45 +0000
commitbf37fd3c005728937bf82b2bca35793ad6ddafdf (patch)
tree1c4030a87e9f51a96ea20ff2a2dd9342afde092b /challenge-103
parentd1438fe7cb03045f357c4e9ac389e16cea3c018c (diff)
downloadperlweeklychallenge-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/OptimizingTask150
-rw-r--r--challenge-103/duncan-c-white/README110
-rwxr-xr-xchallenge-103/duncan-c-white/perl/ch-1.pl67
-rwxr-xr-xchallenge-103/duncan-c-white/perl/ch-2.pl155
-rw-r--r--challenge-103/duncan-c-white/perl/filelist.csv7
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)"