aboutsummaryrefslogtreecommitdiff
path: root/challenge-039
diff options
context:
space:
mode:
authordcw <d.white@imperial.ac.uk>2019-12-23 00:00:09 +0000
committerdcw <d.white@imperial.ac.uk>2019-12-23 00:00:09 +0000
commit625d6bf4334dea9edbc3ae0e4c71b5313c0e841e (patch)
treeb86de41ef7a8645f4f23b279ce73cd4c9cb446c5 /challenge-039
parent12ed341626fbd6dc58f959286555fc5026bea58d (diff)
downloadperlweeklychallenge-club-625d6bf4334dea9edbc3ae0e4c71b5313c0e841e.tar.gz
perlweeklychallenge-club-625d6bf4334dea9edbc3ae0e4c71b5313c0e841e.tar.bz2
perlweeklychallenge-club-625d6bf4334dea9edbc3ae0e4c71b5313c0e841e.zip
ran out of time to get a Postscript code generator working (to show RPN) so here's part 1 - the guestbook question - instead
Diffstat (limited to 'challenge-039')
-rw-r--r--challenge-039/duncan-c-white/README80
-rw-r--r--challenge-039/duncan-c-white/perl5/Tuple.pm85
-rwxr-xr-xchallenge-039/duncan-c-white/perl5/ch-1.pl151
-rw-r--r--challenge-039/duncan-c-white/perl5/guestbook9
-rw-r--r--challenge-039/duncan-c-white/perl5/guestbook24
5 files changed, 287 insertions, 42 deletions
diff --git a/challenge-039/duncan-c-white/README b/challenge-039/duncan-c-white/README
index bbaa601b99..8fe990172f 100644
--- a/challenge-039/duncan-c-white/README
+++ b/challenge-039/duncan-c-white/README
@@ -1,51 +1,47 @@
-Challenge 1: "Date Finder
-
-Create a script to accept a 7 digits number, where the first
-number can only be 1 or 2. The second and third digits can be
-anything 0-9. The fourth and fifth digits corresponds to the month
-i.e. 01,02,03....11,12. And the last 2 digits respresents the days in
-the month i.e. 01,02,03....29,30,31. Your script should validate if
-the given number is valid as per the rule and then convert into human
-readable format date.
-
-RULES
-
-1) If 1st digit is 1, then prepend 20 otherwise 19 to the 2nd and 3rd
- digits to make it 4-digits year.
-
-2) The 4th and 5th digits together should be a valid month.
-
-3) The 6th and 7th digits together should be a valid day for the above month.
-
-For example, the given number is 2230120, it should print 1923-01-20.
+Challenge 1: "A guest house had a policy that the light remain ON as
+long as the at least one guest is in the house. There is guest book
+which tracks all guest in/out time. Write a script to find out how long
+in minutes the light were ON.
+
+Guest Book
+
+1) Alex IN: 09:10 OUT: 09:45
+2) Arnold IN: 09:15 OUT: 09:33
+3) Bob IN: 09:22 OUT: 09:55
+4) Charlie IN: 09:25 OUT: 10:05
+5) Steve IN: 09:33 OUT: 10:01
+6) Roger IN: 09:44 OUT: 10:12
+7) David IN: 09:57 OUT: 10:23
+8) Neil IN: 10:01 OUT: 10:19
+9) Chris IN: 10:10 OUT: 11:00
"
-My notes: sounds rather straightforward, with or without date manipulation
-modules. Reuse the "number of days in the month" code.
+My notes: Nice question. Looks reasonably straightforward, especially if
+we may assume that the IN times are in time order (as they are in the example
+data above, and would naturally be in a physical guest book, where each person
+writes their name and "IN" time in the first free row.
-Challenge 2: "Word Game
+Probably need to store the "OUT times that haven't happened yet" as
+future-time diary events a la Discrete Event Simulation.. Core idea is:
+store a set of users IN at the current time, and modify the set as time
+passes. Think I have a Delta Time queue Perl module somewhere to reuse.
-Lets assume we have tiles as listed below, with an alphabet (A..Z)
-printed on them. Each tile has a value, e.g. A (1 point), B (4 points)
-etc. You are allowed to draw 7 tiles from the lot randomly. Then try
-to form a word using the 7 tiles with maximum points altogether. You
-don't have to use all the 7 tiles to make a word. You should try to
-use as many tiles as possible to get the maximum points.
-For example, A (x8) means there are 8 tiles with letter A.
+Challenge 2: "Write a script to demonstrate Reverse Polish
+notation(RPN). Checkout https://en.wikipedia.org/wiki/Reverse_Polish_notation
+for more information about RPN. (Contributed by Andrezgz) "
-1 point: A (x8), G (x3), I (x5), S (x7), U (x5), X (x2), Z (x5)
+My notes: That's pretty open ended - but on the other hand I know RPN
+very well over the years so that gives quite some scope to play:-)
+An RPN evaluator, or a coventional expression->RPN translator, would
+be obvious tools to build, the evaluator in particular is trivial to
+do and a great opportunity to use callback functions.
-2 points: E (x9), J (x3), L (x3), R (x3), V (x3), Y (x5)
-
-3 points: F (x3), D (x3), P (x5), W (x5)
-
-4 points: B (x5), N (x4)
-
-5 points: T (x5), O (x3), H (x3), M (x4), C (x4)
-
-10 points: K (x2), Q (x2)
-"
+BTW, almost any script in Postscript would demonstrate RPN as Postscript
+is totally RPN-based, so this may is a great opportunity to go for
+Postscript again:-)
-My notes: So not scrabble then:-)
+I spent quite a lot of time trying to build a tiny language and translate
+it to Perl and Postscript, in order to show RPN in the Postscript version,
+but I ran out of time; maybe another time..
diff --git a/challenge-039/duncan-c-white/perl5/Tuple.pm b/challenge-039/duncan-c-white/perl5/Tuple.pm
new file mode 100644
index 0000000000..0f151e03cb
--- /dev/null
+++ b/challenge-039/duncan-c-white/perl5/Tuple.pm
@@ -0,0 +1,85 @@
+package Tuple;
+
+# jan2017: added deepclone() method.
+
+use strict;
+use warnings;
+use Data::Dumper;
+
+#
+# usage: use Tuple; (mainly OO)
+# or: use Tuple qw(tuple); (convenience function too)
+
+use Exporter 'import';
+our @EXPORT_OK = qw(tuple);
+
+
+# exported convenience functions
+sub tuple (@) { return Tuple->new(@_); }
+
+
+#
+# my $trip = Tuple->new( @elements ):
+# Construct a new Tuple with the given values.
+#
+sub new ($@)
+{
+ my( $class, @elements ) = @_;
+ my $tuple = bless [@elements], $class;
+ return $tuple;
+}
+
+
+#
+# my @elements = $tuple->detuple:
+# Return the array of elements from the tuple.
+#
+sub detuple ($)
+{
+ my( $tuple ) = @_;
+ die "Tuple->detuple: bad tuple object",Dumper($tuple),"\n"
+ unless defined $tuple && ref($tuple) eq "Tuple";
+ return @$tuple;
+}
+
+#
+# $tuple->append( $v );
+# Append $v as an extra field in $tuple (so a 3-tuple becomes a 4-tuple)
+#
+sub append ($$)
+{
+ my( $self, $v ) = @_;
+ push @$self, $v;
+}
+
+
+
+use overload '""' => \&as_string;
+
+#
+# my $str = $tuple->as_string():
+# Produce a printable string form of the given tuple.
+#
+sub as_string ($)
+{
+ my( $tuple ) = @_;
+ my $str = join(',', @$tuple);
+ return "($str)";
+}
+
+
+#
+# my $newtuple = $tuple->deepclone;
+# deepclone the given tuple $tuple, calling each item's deepclone
+# method and building and returning a new identical tuple with
+# no shared items..
+# ONLY CALL THIS IF ALL ITEMS ON $tuple "can" deepclone!
+#
+sub deepclone ($)
+{
+ my( $self ) = @_;
+ return Tuple->new( map { $_->deepclone } @$self );
+}
+
+
+1;
diff --git a/challenge-039/duncan-c-white/perl5/ch-1.pl b/challenge-039/duncan-c-white/perl5/ch-1.pl
new file mode 100755
index 0000000000..db1c8e5fab
--- /dev/null
+++ b/challenge-039/duncan-c-white/perl5/ch-1.pl
@@ -0,0 +1,151 @@
+#!/usr/bin/perl
+#
+# Challenge 1: "A guest house had a policy that the light remain ON as
+# long as the at least one guest is in the house. There is guest book
+# which tracks all guest in/out time. Write a script to find out how long
+# in minutes the light were ON.
+#
+# Guest Book
+#
+# 1) Alex IN: 09:10 OUT: 09:45
+# 2) Arnold IN: 09:15 OUT: 09:33
+# 3) Bob IN: 09:22 OUT: 09:55
+# 4) Charlie IN: 09:25 OUT: 10:05
+# 5) Steve IN: 09:33 OUT: 10:01
+# 6) Roger IN: 09:44 OUT: 10:12
+# 7) David IN: 09:57 OUT: 10:23
+# 8) Neil IN: 10:01 OUT: 10:19
+# 9) Chris IN: 10:10 OUT: 11:00
+# "
+#
+# My notes: Nice question. Looks reasonably straightforward, especially if
+# we may assume that the IN times are in time order (as they are in the example
+# data above, and would naturally be in a physical guest book, where each person
+# writes their name and "IN" time in the first free row.
+#
+# Simpler version: When manually checking the answer, I realised that I didn't
+# need the "future-time diary events", the callbacks, the "set of users who
+# are in". I don't need to know WHO is IN @ time T only whether or not ANYONE
+# is. This simpler algorithm REQUIRES that the IN times are in time order.
+#
+
+use v5.10; # to get "say"
+use strict;
+use warnings;
+use Function::Parameters;
+use Data::Dumper;
+
+use lib qw(.);
+use Tuple qw(tuple);
+
+die "Usage: ch-1.pl GUEST_BOOK_FILENAME]\n" unless @ARGV==1;
+my $filename = shift;
+
+
+#
+# my $t = t2i( $time );
+# Convert $time, a 24-hour clock hh:mm string, into an integer $t,
+# specifically 60*hh + mm.
+#
+fun t2i( $time )
+{
+ $time =~ /^(\d+):(\d+)$/;
+ my( $h, $m ) = ( $1, $2 );
+ return 60*$h+$m;
+}
+
+
+#
+# my @data = parse_guestbook( $filename );
+# Given the $filename of the file containing the guest book data,
+# open and read the data from the guestbook file ($filename) (dying
+# if you can't open the guestbook), build and return @data, a list
+# of (person, timein, timeout) tuples.
+#
+fun parse_guestbook( $filename )
+{
+ open( my $fh, '<', $filename ) || die "can't open $filename\n";
+ my @result;
+ while( <$fh> )
+ {
+ chomp;
+ # format is: 1) Alex IN: 09:10 OUT: 09:45
+ /^\s*\d+\)\s+(\w+)\s+IN:\s+(\S+)\s+OUT:\s+(\S+)\s*$/ ||
+ die "bad format '$_' at line $. in $filename\n";
+ my( $name, $intime, $outtime ) = ( $1, $2, $3 );
+ push @result, tuple( $name, $intime, $outtime );
+ #say "name=$name, intime=$intime, outtime=$outtime";
+ }
+ close( $fh );
+ return @result;
+}
+
+
+my @data = parse_guestbook( $filename );
+#die Dumper \@data;
+
+# now, to calculate the number of minutes that the house light is ON
+# (which in time happens whenever the house is NON EMPTY), run through
+# the @data, maintaining the people set.
+
+my $totaltime = 0; # total time house is non empty (in minutes)
+my $lighton = 0; # is light on?
+my $lightonuntil = "00:00"; # if light is on, until when? (hh:mm format)
+
+foreach my $tuple (@data)
+{
+ my( $name, $intime, $outtime ) = $tuple->detuple;
+ my $it = t2i( $intime );
+ my $ot = t2i( $outtime );
+ my $delta = $ot - $it;
+ say "$name enters house at $intime, leaves at $outtime";
+
+ unless( $lighton )
+ {
+ $lightonuntil = $outtime;
+ $lighton = 1;
+ $totaltime += $delta;
+ say "Light on for $delta minutes ".
+ "(from $intime until $outtime), ".
+ "so totaltime $totaltime";
+ next;
+ }
+
+ # we already know the light is on until $lightonuntil
+ # now we now that name is IN from $intime to $outtime
+
+ # lou is lights on until (but in minutes since midnight)
+ my $lou = t2i($lightonuntil);
+
+ if( $it <= $lou )
+ {
+ # ok: light on ..lightonuntil and
+ # also on from intime(<=lightonuntil)..outtime:
+
+ # if outtime > lightonuntil then:
+ # extend light on from lightonuntil until new outtime,
+ if( $ot > $lou )
+ {
+ # now know light is on from $lou to $ot:
+ my $extraontime = $ot - $lou;
+ $totaltime += $extraontime;
+ my $from = $lightonuntil;
+ $lightonuntil = $outtime;
+ say "Light on for another $extraontime minutes ".
+ "(from $from until $outtime), ".
+ "totaltime now $totaltime";
+ }
+ } else
+ {
+ # (light on ..lightonuntil and on intime(>lightonuntil)..outtime:
+ # so light OFF from lightonuntil .. intime
+ # THEN ON from intime..outtime: that's $delta
+ $lightonuntil = $outtime;
+ $totaltime += $delta;
+ say "Light on for $delta minutes ".
+ "(from $intime until $outtime), ".
+ "totaltime now $totaltime";
+ }
+}
+
+say "\nLight was on for $totaltime minutes";
diff --git a/challenge-039/duncan-c-white/perl5/guestbook b/challenge-039/duncan-c-white/perl5/guestbook
new file mode 100644
index 0000000000..a2467461cd
--- /dev/null
+++ b/challenge-039/duncan-c-white/perl5/guestbook
@@ -0,0 +1,9 @@
+1) Alex IN: 09:10 OUT: 09:45
+2) Arnold IN: 09:15 OUT: 09:33
+3) Bob IN: 09:22 OUT: 09:55
+4) Charlie IN: 09:25 OUT: 10:05
+5) Steve IN: 09:33 OUT: 10:01
+6) Roger IN: 09:44 OUT: 10:12
+7) David IN: 09:57 OUT: 10:23
+8) Neil IN: 10:01 OUT: 10:19
+9) Chris IN: 10:10 OUT: 11:00
diff --git a/challenge-039/duncan-c-white/perl5/guestbook2 b/challenge-039/duncan-c-white/perl5/guestbook2
new file mode 100644
index 0000000000..1345ead1bd
--- /dev/null
+++ b/challenge-039/duncan-c-white/perl5/guestbook2
@@ -0,0 +1,4 @@
+1) Alex IN: 09:10 OUT: 09:45
+2) Arnold IN: 09:15 OUT: 09:33
+3) Bob IN: 09:22 OUT: 09:55
+4) Charlie IN: 10:00 OUT: 10:30