aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMohammad S Anwar <Mohammad.Anwar@yahoo.com>2019-12-16 00:35:59 +0000
committerGitHub <noreply@github.com>2019-12-16 00:35:59 +0000
commit5ce75caf5ded27ab908b0c3209b9c972ed8a279c (patch)
tree36a86889b4553d8f743b9f91a5368fcbd7c9f81b
parent41db04c710820d98653eb179a2fef27066c9cafb (diff)
parent1d360299a966c180d39c21151e0a52a97f59c42f (diff)
downloadperlweeklychallenge-club-5ce75caf5ded27ab908b0c3209b9c972ed8a279c.tar.gz
perlweeklychallenge-club-5ce75caf5ded27ab908b0c3209b9c972ed8a279c.tar.bz2
perlweeklychallenge-club-5ce75caf5ded27ab908b0c3209b9c972ed8a279c.zip
Merge pull request #1041 from dcw803/master
imported my solutions for challenge 38
-rw-r--r--challenge-038/duncan-c-white/README82
-rwxr-xr-xchallenge-038/duncan-c-white/perl5/ch-1.pl79
-rwxr-xr-xchallenge-038/duncan-c-white/perl5/ch-2.pl188
3 files changed, 304 insertions, 45 deletions
diff --git a/challenge-038/duncan-c-white/README b/challenge-038/duncan-c-white/README
index c71e2a54c9..bbaa601b99 100644
--- a/challenge-038/duncan-c-white/README
+++ b/challenge-038/duncan-c-white/README
@@ -1,59 +1,51 @@
-Challenge 1: "Write a script to calculate the total number of weekdays (Mon-Fri) in each month of the year 2019.
-Jan: 23 days
-Feb: 20 days
-Mar: 21 days
-Apr: 22 days
-May: 23 days
-Jun: 20 days
-Jul: 23 days
-Aug: 22 days
-Sep: 21 days
-Oct: 23 days
-Nov: 21 days
-Dec: 22 days
+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.
"
My notes: sounds rather straightforward, with or without date manipulation
-modules. Might even have a crack at this in an unconventional language
-as well as Perl - how about Adobe Postscript?
+modules. Reuse the "number of days in the month" code.
-Afternotes: I did 3 versions of this:
-ch-1-Date-Manip.pl: first version uses Date::Manip's Date_DaysInMonth(m,y) and
- Date_DayOfWeek(m,d,y) functions.
+Challenge 2: "Word Game
-ch-1.pl: second version does it ourselves from scratch.
+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.
-ch-1-in-postscript.ps: translated ch-1.pl into Postscript. Yes, the language
- mostly used for printer page layout, can be used as a
- full-blown programming language. However, you have to
- include functions to append strings and produce a
- variety of debugging messages down the page, before
- you start on the actual program logic.
+For example, A (x8) means there are 8 tiles with letter A.
+1 point: A (x8), G (x3), I (x5), S (x7), U (x5), X (x2), Z (x5)
-Challenge 2: "Write a script to find out the DayLight gain/loss in
-the month of December 2019 as compared to November 2019 in the city of
-London. You can find out London sunrise and sunset data for November 2019 here:
-https://www.timeanddate.com/sun/uk/london?month=11&year=2019
+2 points: E (x9), J (x3), L (x3), R (x3), V (x3), Y (x5)
-and for December 2019 here:
-https://www.timeanddate.com/sun/uk/london?month=12&year=2019
-"
+3 points: F (x3), D (x3), P (x5), W (x5)
-My notes: most of this problem is fetching the web pages and parsing the
-information out of the first table in each page: that's a typical
-HTML::Parser state machine, easy enough. But once we have that information,
-eg. for each month a day->daylight duration mapping, what exactly does the
-question mean us to do?
+4 points: B (x5), N (x4)
-I think this problem means
+5 points: T (x5), O (x3), H (x3), M (x4), C (x4)
-"calculate the difference between the amount of daylight on 1st Nov and on
-30th Nov, do the same for December (1st and 31st), and find out which
-"within month daylight duration" is smaller."
+10 points: K (x2), Q (x2)
+"
-btw, if I'm right the smaller duration is obviously between 1st-31st Dec
-than between 1st-30th Nov, because in November the days are getting shorter
-throughout the whole month, whereas in December they get shorter from
-1st-21st Dec, and then get longer again!
+My notes: So not scrabble then:-)
diff --git a/challenge-038/duncan-c-white/perl5/ch-1.pl b/challenge-038/duncan-c-white/perl5/ch-1.pl
new file mode 100755
index 0000000000..4464df186d
--- /dev/null
+++ b/challenge-038/duncan-c-white/perl5/ch-1.pl
@@ -0,0 +1,79 @@
+#!/usr/bin/perl
+#
+# 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.
+# "
+#
+# My notes: sounds rather straightforward, with or without date manipulation
+# modules. Uses Date::Manip's Date_DaysInMonth(m,y) function.
+#
+
+use v5.10; # to get "say"
+use strict;
+use warnings;
+use Function::Parameters;
+use Date::Manip;
+
+
+die "Usage: ch-1.pl [CODED_DATE]\n" if @ARGV>1;
+my $date = shift // "2230120";
+
+
+#
+# my $isodate = validate( $date );
+# Validate the strangely coded date, return undef if it's
+# not valid, or an ISO format date string if it's valid.
+#
+fun validate( $date )
+{
+ # must be 7 digits number
+ return undef unless $date =~ /^(\d)(\d\d)(\d\d)(\d\d)$/;
+ my( $first, $y, $m, $d ) = ( $1, $2, $3, $4 );
+
+ # where the first number can only be 1 or 2.
+ return undef unless $first eq '1' || $first eq '2';
+
+ # The second and third digits can be anything 0-9.
+ # If 1st digit is 1, then prepend 20 otherwise 19 to the year
+ $y = ($first eq '1' ? 20 : 19).$y;
+
+ # The fourth and fifth digits corresponds to the month i.e. 01-12.
+ return undef unless $m >= 1 && $m <= 12;
+
+ my $ndays = Date_DaysInMonth( $m, $y );
+ say "debug: y=$y, m=$m, ndays=$ndays";
+
+ # The last 2 digits respresents the days in the month i.e. 01-31.
+ return undef unless $d >= 1 && $d <= $ndays;
+
+ # Valid: convert into human readable format date.
+ return "$y-$m-$d";
+}
+
+
+my $isodate = validate( $date );
+if( defined $isodate )
+{
+ say "$date: valid $isodate";
+} else
+{
+ say "$date: invalid";
+}
diff --git a/challenge-038/duncan-c-white/perl5/ch-2.pl b/challenge-038/duncan-c-white/perl5/ch-2.pl
new file mode 100755
index 0000000000..eae5076dd9
--- /dev/null
+++ b/challenge-038/duncan-c-white/perl5/ch-2.pl
@@ -0,0 +1,188 @@
+#!/usr/bin/perl
+#
+# Challenge 2: "Word Game
+#
+# 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.
+#
+# 1 point: A (x8), G (x3), I (x5), S (x7), U (x5), X (x2), Z (x5)
+# 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)
+# "
+#
+# My notes: Sounds rather like Scrabble without the board.
+#
+
+use v5.10; # to get "say"
+use strict;
+use warnings;
+use Function::Parameters;
+use Data::Dumper;
+
+my %tilebag = (
+ A => 8, G => 3, I => 5, S => 7,
+ U => 5, X => 2, Z => 5, E => 9,
+ J => 3, L => 3, R => 3, V => 3,
+ Y => 5, F => 3, D => 3, P => 5,
+ W => 5, B => 5, N => 4, T => 5,
+ O => 3, H => 3, M => 4, C => 4,
+ K => 2, Q => 2,
+);
+
+
+my $debug=0;
+
+#srand(1);
+
+# build alltiles, a weighted list of tiles to take at random
+my $alltiles= join( '', map { $_ x $tilebag{$_} } sort keys %tilebag );
+#print "alltiles $alltiles\n";
+
+
+my %value = (
+ # 1 point:
+ A => 1, G => 1, I => 1, S => 1, U => 1, X => 1, Z => 1,
+
+ # 2 points:
+ E => 2, J => 2, L => 2, R => 2, V => 2, Y => 2,
+
+ # 3 points:
+ F => 3, D => 3, P => 3, W => 3,
+
+ # 4 points:
+ B => 4, N => 4,
+
+ # 5 points:
+ T => 5, O => 5, H => 5, M => 5, C => 5,
+
+ # 10 points:
+ K => 10, Q => 10,
+);
+
+#die Dumper \%value;
+
+
+#
+# my $hand = randomtiles( $n );
+# Select $n random tiles from $alltiles. Return
+# an $n-letter sorted sequence of those random tiles.
+#
+fun randomtiles( $n )
+{
+ my $at = $alltiles;
+ my @result;
+ foreach my $i (1..$n)
+ {
+ my $pos = int(rand(length($at)));
+ push @result, substr( $at, $pos, 1 );
+ substr( $at, $pos, 1 ) = '';
+ }
+ return join( '', sort @result );
+}
+
+
+#
+# my @words = readdict( $filename );
+# Read the given wordlist $filename. Return the list of words.
+#
+fun readdict( $filename )
+{
+ open( my $fh, '<', $filename ) || die;
+ my @result;
+ while( <$fh> )
+ {
+ chomp;
+ next unless /^[A-Za-z]+$/;
+ $_ =~ tr/a-z/A-Z/;
+ push @result, $_;
+ }
+ close( $fh );
+ return @result;
+}
+
+
+#
+# my $score = score( $word );
+# Score the letters of $word using the %value. Return the score.
+#
+fun score( $word )
+{
+ my $score = 0;
+ foreach my $letter (split(//,$word))
+ {
+ $score += $value{$letter};
+ }
+ return $score;
+}
+
+
+my @words = grep { length($_)<8 } readdict( '/usr/share/dict/words' );
+my %isword = map { $_ => 1 } @words;
+#die Dumper \%isword;
+
+# find highest scoring word that is a sub-bag of $hand.
+my $highscore=0;
+my $highscore_word;
+
+
+#
+# findall( $prefix, $hand );
+# Find all sub-words of $hand (starting with $prefix)
+# that are dictionary words, score each one, and find
+# the highest scored word.
+#
+fun findall( $prefix, $hand )
+{
+ #say "debug: prefix=$prefix, hand=$hand";
+ my $l = length($hand);
+ foreach my $pos (0..$l-1)
+ {
+ my $letter = substr($hand,$pos,1);
+ my $w = $prefix.$letter;
+ if( $isword{$w} )
+ {
+ my $score = score( $w );
+ #say "debug: w=$w, score=$score";
+ if( $score > $highscore )
+ {
+ $highscore = $score;
+ $highscore_word = $w;
+ }
+ }
+ my $rest = $hand;
+ substr($rest,$pos,1) = '';
+ findall( $w, $rest );
+ }
+}
+
+
+die "Usage: ch-2.pl [NROUNDS]\n" if @ARGV>1;
+my $nrounds = shift // 1;
+
+my $overall_highscore=0;
+my $overall_highscore_word;
+my $overall_highscore_hand;
+foreach (1..$nrounds)
+{
+ $highscore=0;
+ my $hand = randomtiles( 7 );
+ #my $score = score( $hand );
+ findall( "", $hand );
+ say "hand:$hand, highscore:$highscore, word:$highscore_word" if $debug;
+ if( $highscore > $overall_highscore )
+ {
+ $overall_highscore = $highscore;
+ $overall_highscore_word = $highscore_word;
+ $overall_highscore_hand = $hand;
+ }
+}
+say "overall: hand:$overall_highscore_hand, highscore:$overall_highscore, word:$overall_highscore_word";