aboutsummaryrefslogtreecommitdiff
path: root/challenge-046
diff options
context:
space:
mode:
authordcw <d.white@imperial.ac.uk>2020-02-06 20:20:07 +0000
committerdcw <d.white@imperial.ac.uk>2020-02-06 20:20:07 +0000
commita32c231818e654edf91d31076bf6001725c219bc (patch)
tree6cfa4d5cf992626149e76d22add8021fedc7188d /challenge-046
parentee0d2ae41449f68b3ac874e526c6b140e7d3e909 (diff)
downloadperlweeklychallenge-club-a32c231818e654edf91d31076bf6001725c219bc.tar.gz
perlweeklychallenge-club-a32c231818e654edf91d31076bf6001725c219bc.tar.bz2
perlweeklychallenge-club-a32c231818e654edf91d31076bf6001725c219bc.zip
imported my solutions, including the second one in postscript to get on the guest page again:-)
Diffstat (limited to 'challenge-046')
-rw-r--r--challenge-046/duncan-c-white/README60
-rwxr-xr-xchallenge-046/duncan-c-white/perl/ch-1.pl79
-rwxr-xr-xchallenge-046/duncan-c-white/perl/ch-2.pl61
-rw-r--r--challenge-046/duncan-c-white/postscript/ch-2.ps192
4 files changed, 371 insertions, 21 deletions
diff --git a/challenge-046/duncan-c-white/README b/challenge-046/duncan-c-white/README
index e8d0698436..8a4cac1fc2 100644
--- a/challenge-046/duncan-c-white/README
+++ b/challenge-046/duncan-c-white/README
@@ -1,34 +1,52 @@
-Task 1: "Square Secret Code:
+Task 1: "Cryptic Message:
-The square secret code mechanism first removes any space from the original
-message. Then it lays down the message in a row of 8 columns. The coded
-message is then obtained by reading down the columns going left to right.
+The communication system of an office is broken and messages received
+are not completely reliable. To send the message Hello 6 times, it ended
+up sending these following:
-For example, the message is "The quick brown fox jumps over the lazy dog".
+H x l 4 !
+c e - l o
+z e 6 l g
+H W l v R
+q 9 m # o
-Then the message would be laid out as below:
+Similarly another day we received a message repeatedly like below:
-thequick
-brownfox
-jumpsove
-rthelazy
-dog
+P + 2 l ! a t o
+1 e 8 0 R $ 4 u
+5 - r ] + a > /
+P x w l b 3 k \
+2 e 3 5 R 8 y u
+< ! r ^ ( ) k 0
-The code message would be as below:
+Write a script to decrypt the above repeated message (one message repeated
+6 times).
-tbjrd hruto eomhg qwpe unsl ifoa covz kxey
-
-Write a script that accepts a message from command line and prints the
-equivalent coded message.
+HINT: Look for characters repeated in a particular position in all six
+messages received.
"
-My notes: sounds trivial, let's write the decoder as well.
+My notes: ah, so pick maxfreq letter in each column?
-Task #2: "Source Dumper:
+Task #2: "Is the room open?
-Write a script that dumps its own source code. For example, say, the script name is ch-2.pl then the following command should returns nothing.
+There are 500 rooms in a hotel with 500 employees having keys to all the
+rooms. The first employee opened main entrance door of all the rooms. The
+second employee then closed the doors of room numbers 2,4,6,8,10 and
+so on to 500. The third employee then closed the door if it was opened
+or opened the door if it was closed of rooms 3,6,9,12,15 and so on to
+500. Similarly the fourth employee did the same as the third but only
+room numbers 4,8,12,16 and so on to 500. This goes on until all employees
+has had a turn.
-$ perl ch-2.pl | diff - ch-2.pl
+Write a script to find out all the rooms still open at the end.
"
-My notes: trivial if we're allowed to use $0.
+My notes: sounds pretty easy, two nested for loops, but one of those questions
+where I can't predict in advance what the answer will be.
+
+But having written the naive roomopen[r] based solution, I find that the
+answer is: the open rooms are all the room numbers that are exact squares!
+I'm not sure why, but I then implemented that more directly, with no
+arrays. I then translated that into Postscript too, see the postscript
+directory:-)
diff --git a/challenge-046/duncan-c-white/perl/ch-1.pl b/challenge-046/duncan-c-white/perl/ch-1.pl
new file mode 100755
index 0000000000..7939f8c141
--- /dev/null
+++ b/challenge-046/duncan-c-white/perl/ch-1.pl
@@ -0,0 +1,79 @@
+#!/usr/bin/perl
+#
+#
+# Task 1: "Cryptic Message:
+#
+# The communication system of an office is broken and messages received
+# are not completely reliable. If we sent the message Hello 6 times, it
+# might end up sending these following corrupt messsages:
+#
+# H x l 4 !
+# c e - l o
+# z e 6 l g
+# H W l v R
+# q 9 m # o
+#
+# Similarly another day we received a message repeatedly like below:
+#
+# P + 2 l ! a t o
+# 1 e 8 0 R $ 4 u
+# 5 - r ] + a > /
+# P x w l b 3 k \
+# 2 e 3 5 R 8 y u
+# < ! r ^ ( ) k 0
+#
+# Write a script to decrypt the above repeated message (one message repeated
+# 6 times).
+#
+# HINT: Look for characters repeated in a particular position in all six
+# messages received.
+# "
+#
+# My notes: ah, so pick maxfreq letter in each column?
+# invoke as:
+# ./ch-1.pl 'Hxl4!' 'ce-lo' 'ze6lg' 'HWlvR' 'q9m#o'
+# result: Hello
+#
+# ./ch-1.pl 'P+2l\!ato' '1e80R$4u' '5-r]+a>/' \
+# 'Pxwlb3k\' '2e35R8yu' '<\!r^()k0'
+# result: PerlRaku
+#
+
+use feature 'say';
+use strict;
+use warnings;
+use Data::Dumper;
+
+die "Usage: mergemsg M1 M2 M3....\n" unless @ARGV>1;
+
+my @freq; # array of bags
+
+foreach my $msg (@ARGV)
+{
+ my @letter = split( //, $msg );
+ foreach my $i (0..$#letter)
+ {
+ $freq[$i] //= {};
+ $freq[$i]{$letter[$i]}++;
+ }
+}
+
+#die Dumper \@freq;
+
+my $result = "";
+foreach my $i (0..$#freq)
+{
+ my $max = -1;
+ my $let = '';
+ my $href = $freq[$i];
+ while( my($l,$f) = each %$href )
+ {
+ if( $f > $max )
+ {
+ $max = $f;
+ $let = $l;
+ }
+ }
+ $result .= $let;
+}
+say $result;
diff --git a/challenge-046/duncan-c-white/perl/ch-2.pl b/challenge-046/duncan-c-white/perl/ch-2.pl
new file mode 100755
index 0000000000..d6320f2a4e
--- /dev/null
+++ b/challenge-046/duncan-c-white/perl/ch-2.pl
@@ -0,0 +1,61 @@
+#!/usr/bin/perl
+#
+# Task #2: "Is the room open?
+#
+# There are 500 rooms in a hotel with 500 employees having keys to all the
+# rooms. The first employee opened main entrance door of all the rooms. The
+# second employee then closed the doors of room numbers 2,4,6,8,10 and
+# so on to 500. The third employee then closed the door if it was opened
+# or opened the door if it was closed of rooms 3,6,9,12,15 and so on to
+# 500. Similarly the fourth employee did the same as the third but only
+# room numbers 4,8,12,16 and so on to 500. This goes on until all employees
+# has had a turn.
+#
+# Write a script to find out all the rooms still open at the end.
+# "
+#
+# My notes: sounds pretty easy, two nested for loops, but it's one of those
+# questions where I can't predict what the answer will be.
+# Wow! the answer is: all the squares! Let's find out why..
+#
+
+use feature 'say';
+use strict;
+use warnings;
+
+die "Usage: ch-2.pl [Nrooms]\n" if @ARGV>1;
+my $n = shift // 500;
+
+# all rooms open initially [we don't use element 0]
+my @roomopen = ( 0, (1) x $n );
+
+say "naive answer:";
+foreach my $empl (2..$n)
+{
+ for( my $room=$empl; $room<=$n; $room+=$empl )
+ {
+ #say "debug: empl=$empl, room=$room, roomopen? $roomopen[$room]";
+ $roomopen[$room] = 1-$roomopen[$room];
+ }
+}
+
+my @open = grep { $roomopen[$_] } 0..$n;
+say join(',', @open);
+
+# ok, so a room no R is open at the end if the number of factors of R,
+# including 1 and R, is ODD:
+
+say "odd-factors answer:";
+my @sq;
+foreach my $r (1..$n)
+{
+ my $odd = 1;
+ foreach my $i (2..$r)
+ {
+ $odd = ! $odd if $r % $i == 0;
+ }
+ push @sq, $r if $odd;
+}
+say join(',', @sq);
+
+say "but why are the squares the only numbers with an odd number of factors?";
diff --git a/challenge-046/duncan-c-white/postscript/ch-2.ps b/challenge-046/duncan-c-white/postscript/ch-2.ps
new file mode 100644
index 0000000000..032bfd82d0
--- /dev/null
+++ b/challenge-046/duncan-c-white/postscript/ch-2.ps
@@ -0,0 +1,192 @@
+%!PS-Adobe-3.0
+%%Pages: 1
+%%EndComments
+%
+% Task #2: "Is the room open?
+%
+% There are 500 rooms in a hotel with 500 employees having keys to all the
+% rooms. The first employee opened main entrance door of all the rooms. The
+% second employee then closed the doors of room numbers 2,4,6,8,10 and
+% so on to 500. The third employee then closed the door if it was opened
+% or opened the door if it was closed of rooms 3,6,9,12,15 and so on to
+% 500. Similarly the fourth employee did the same as the third but only
+% room numbers 4,8,12,16 and so on to 500. This goes on until all employees
+% has had a turn.
+%
+% Write a script to find out all the rooms still open at the end.
+% "
+%
+
+
+% Debugging....
+
+% const debuglm: left margin of debug messages
+/debuglm 0.5 72 mul def
+
+% const debugtop: top of debug messages - 11 inches up.
+/debugtop 11 72 mul def
+
+% const debugdown: how far to go down each line
+/debugdown 20 def
+
+
+% debugorigin():
+% move to debugging origin
+/debugorigin
+{
+ debuglm debugtop moveto
+ (Debugging log:) show
+ newline
+} bind def
+
+
+% debugnv( name, value );
+% display name and value on a debug line.
+% keep this as it's so much simpler than debug() below
+% and also debug() has commented out invocations to
+% this throughout it:-)
+/debugnv
+{
+ % initially: stack top: value, name
+ 30 0 rmoveto
+ exch % stack top: name, value
+ show % show name, stack top: value
+ (: ) show
+ 80 string cvs show % show convert_to_string(value)
+ newline
+} bind def
+
+
+% debugsay( string, array_of_pairs );
+% display a single message, combining the initial string and then
+% every pair of items (variable,string) in <array> with no separators.
+% eg debugsay( (x:), [ x (, y:) y (, z:) z ()] ) produces
+% "x: value_of_x, y: value_of_y, z: value_of_z"
+/debugsay
+{
+ 6 dict begin % next N items defined are in a local dictionary
+ /array exch def % localize parameter name, removing it from stack
+ /initstr exch def % localize parameter name, removing it from stack
+ /len 0 def % local variable - length of array
+ /pos 0 def % local variable - position in array
+ /name () def % local variable - an array element
+ /value () def % local variable - next array element
+
+ 30 0 rmoveto
+
+ /len array length def
+
+ initstr 80 string cvs show
+
+ % for pos = 0 to $#array step 2
+ 0 2 len 1 sub
+ {
+ /pos exch def
+% (pos) pos debugnv
+
+ % $name = $array[$pos];
+ /name array pos get def
+% (name) name debugnv
+
+ % $value = $array[$pos+1];
+ /value array pos 1 add get def
+% (value) value debugnv
+
+ name 80 string cvs show
+ value 80 string cvs show
+ } for
+
+ newline
+
+ end % local dictionary destroyed here
+
+} def
+
+
+% newline();
+% go to left margin of next line for debug messages
+/newline
+{
+ currentpoint debugdown sub % decrement Y pos
+ exch pop % drop old X
+ debuglm exch % form (debuglm,Y) on stack
+ moveto % go there!
+} def
+
+
+% str = i2s(n):
+% convert n to a string
+/i2s
+{
+ 20 string cvs
+} def
+
+
+% result = append( string1, string2 )
+% Concatenates two strings together. Some languages
+% already know how to do stuff like this!!!
+/append
+{
+ % Initial stack: s1 s2 <-- top of stack
+ 2 copy % s1 s2 s1 s2
+ length % s1 s2 s1 len(s2)
+ exch % s1 s2 len(s2) s1
+ length add % s1 s2 len(s1)+len(s2)
+ string dup % s1 s2 r r
+ 4 2 roll % r r s1 s2
+ 2 index % r r s1 s2 r
+ 0 % r r s1 s2 r 0
+ 3 index % r r s1 s2 r 0 s1
+ putinterval % strcpy( r+0, s1 )
+ % r r s1 s2
+ exch % r r s2 s1
+ length % r r s2 len(s1)
+ exch % r r len(s1) s2
+ putinterval % strcpy( r+len(s1), s2 )
+ % return r
+} bind def
+
+
+%%Page: 1 1
+%%PageOrientation: Portrait
+
+/Helvetica-Bold findfont 13 scalefont setfont
+
+debugorigin
+
+% n = 500
+/n 500 def
+
+% say "answer:"
+(answer:) [] debugsay
+
+% for r = 1 to n
+1 1 n
+{
+ /r exch def
+
+ % odd=1
+ /odd 1 def
+
+ % for i = 2 to r
+ 2 1 r
+ {
+ /i exch def
+ % if r % i == 0?
+ r i mod 0 eq
+ {
+ % odd = 1-odd
+ /odd 1 odd sub def
+ } if
+ } for
+
+ % if odd
+ odd 1 eq
+ {
+ % say "$r"
+ () [r ()] debugsay
+ } if
+} for
+
+
+showpage