aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrobbie-hatley <Robbie.Hatley@gmail.com>2023-07-24 23:09:02 -0700
committerrobbie-hatley <Robbie.Hatley@gmail.com>2023-07-24 23:09:02 -0700
commit3ca3e81cc69d5d6421f91d1fad0fd7fb4eb3146d (patch)
tree9b142ee07591bd4e9dd207be07bf019fb50a4fb3
parente4bdf5dcb6e741f1fb8e1b145fd2111f05ed6445 (diff)
downloadperlweeklychallenge-club-3ca3e81cc69d5d6421f91d1fad0fd7fb4eb3146d.tar.gz
perlweeklychallenge-club-3ca3e81cc69d5d6421f91d1fad0fd7fb4eb3146d.tar.bz2
perlweeklychallenge-club-3ca3e81cc69d5d6421f91d1fad0fd7fb4eb3146d.zip
Robbie Hatley's solutions to The Weekly Challenge 227
-rw-r--r--challenge-227/robbie-hatley/blog.txt1
-rwxr-xr-xchallenge-227/robbie-hatley/perl/ch-1.pl145
-rwxr-xr-xchallenge-227/robbie-hatley/perl/ch-2.pl130
3 files changed, 276 insertions, 0 deletions
diff --git a/challenge-227/robbie-hatley/blog.txt b/challenge-227/robbie-hatley/blog.txt
new file mode 100644
index 0000000000..c84a8c4014
--- /dev/null
+++ b/challenge-227/robbie-hatley/blog.txt
@@ -0,0 +1 @@
+https://hatley-software.blogspot.com/2023/07/robbie-hatleys-solutions-to-weekly_24.html \ No newline at end of file
diff --git a/challenge-227/robbie-hatley/perl/ch-1.pl b/challenge-227/robbie-hatley/perl/ch-1.pl
new file mode 100755
index 0000000000..ba6b6c4d71
--- /dev/null
+++ b/challenge-227/robbie-hatley/perl/ch-1.pl
@@ -0,0 +1,145 @@
+#! /bin/perl -CSDA
+
+=pod
+
+--------------------------------------------------------------------------------------------------------------
+COLOPHON:
+This is a 110-character-wide Unicode UTF-8 Perl-source-code text file with hard Unix line breaks ("\x0A").
+¡Hablo Español! Говорю Русский. Björt skjöldur. ॐ नमो भगवते वासुदेवाय. 看的星星,知道你是爱。麦藁雪、富士川町、山梨県。
+
+--------------------------------------------------------------------------------------------------------------
+TITLE BLOCK:
+Solutions in Perl for The Weekly Challenge 227-1.
+Written by Robbie Hatley on Mon Jul 24, 2023.
+
+--------------------------------------------------------------------------------------------------------------
+PROBLEM DESCRIPTION:
+Task 1: Friday 13th
+Submitted by: Peter Campbell Smith
+You are given a year number in the range 1753 to 9999. Write a script to find out how many dates in the year
+are Friday 13th, assume that the current Gregorian calendar applies.
+
+Example: Input: $year = 2023 Output: 2
+Since there are only 2 Friday 13th in the given year 2023 i.e. 13th Jan and 13th Oct.
+
+--------------------------------------------------------------------------------------------------------------
+PROBLEM NOTES:
+Let's use the number 0-6 to stand for days-of-week from a Sunday through the next Saturday. Because we're
+only interested in years 1753+, lets use 13 December 1752 as "epoch". That was a Wednesday, so our starting
+offset is 3. Then make an array to hold elements indexed from 1753 through 9999 (representing the years),
+with element being a ref to an array of elements indexed 0 through 11 (representing the months), with each
+inner element being "starting offset plus days elapsed from epoch to the 13th of the current month".
+The starting offset 3 only has to be added once, to the entry for 13 January 1753; every subsequent month
+from February 1753 through December 9999 is just the number from the previous month plus the number of days
+in the previous month. Then to get the "Friday The 13th"s for each year, just take each month's number
+modulo 7; each 5 is a Friday The 13th.
+
+--------------------------------------------------------------------------------------------------------------
+IO NOTES:
+Input is via either built-in variables or via @ARGV. If using @ARGV, provide one argument which must be a
+double-quoted array positive integers in the range 1753-9999, in proper Perl syntax, like so:
+./ch-1.pl "(1794,1846,2017,8462)"
+
+Output is to STDOUT and will be each input year followed by the "Friday The 13th"s in that year.
+
+=cut
+
+# ------------------------------------------------------------------------------------------------------------
+# PRELIMINARIES:
+
+use v5.36;
+use strict;
+use warnings;
+use utf8;
+use Sys::Binmode;
+use Time::HiRes 'time';
+$"=', ';
+
+# ------------------------------------------------------------------------------------------------------------
+# SUBROUTINES:
+
+sub days_in_february ($year) {
+ if ( 0 == $year%100 ) {
+ return ( (0 == $year%400) ? 29 : 28 );
+ }
+ else {
+ return ( (0 == $year%4) ? 29 : 28 );
+ }
+}
+
+sub days_in_month ($year, $month) {
+ if ( 0 == $month ) { return 31; }
+ elsif ( 1 == $month ) { return days_in_february($year); }
+ elsif ( 2 == $month ) { return 31; }
+ elsif ( 3 == $month ) { return 30; }
+ elsif ( 4 == $month ) { return 31; }
+ elsif ( 5 == $month ) { return 30; }
+ elsif ( 6 == $month ) { return 31; }
+ elsif ( 7 == $month ) { return 31; }
+ elsif ( 8 == $month ) { return 30; }
+ elsif ( 9 == $month ) { return 31; }
+ elsif ( 10 == $month ) { return 30; }
+ elsif ( 11 == $month ) { return 31; }
+}
+
+sub year_is_valid ($year) {
+ return 0 if $year !~ m/^[1-9]\d\d\d$/;
+ return 0 if $year < 1753;
+ return 1;
+}
+
+# ------------------------------------------------------------------------------------------------------------
+# MAIN BODY OF PROGRAM:
+
+# Start timer:
+my $t0 = time;
+
+# Array of month names:
+my @month_names = qw( January February March April May June July August September October November December );
+
+# @t = Array of thirteenths:
+my @t;
+$t[1752]->[11] = 3; # Starting offset is 3 because 13 December 1752 was a Wednesday.
+for my $year (1753..9999) {
+ for my $month (0..11) {
+ if ( 0 == $month ) {
+ $t[$year]->[$month] = $t[$year-1]->[11] + 31;
+ }
+ else {
+ $t[$year]->[$month] = $t[$year]->[$month-1] + days_in_month($year,$month-1);
+ }
+ }
+}
+
+# Default inputs:
+my @years =
+(
+ 2022,
+ 2023,
+ 2024,
+);
+
+# Non-default inputs:
+@years = eval($ARGV[0]) if @ARGV;
+
+# Main loop:
+for my $year (@years) {
+ say '';
+ if ( ! year_is_valid($year) ) {
+ say "Year $year is invalid. Year must be in range 1753-9999.";
+ next;
+ }
+ say "Friday the 13ths in year $year:";
+ my $tcount = 0;
+ for my $month (0..11) {
+ if ( 5 == $t[$year]->[$month]%7 ) {
+ say "Friday 13 $month_names[$month], $year";
+ ++$tcount;
+ }
+ }
+ say "Total Friday The 13ths in $year = $tcount";
+}
+
+# Determine and print execution time:
+my $µs = 1000000 * (time - $t0);
+printf("\nExecution time was %.0fµs.\n", $µs);
diff --git a/challenge-227/robbie-hatley/perl/ch-2.pl b/challenge-227/robbie-hatley/perl/ch-2.pl
new file mode 100755
index 0000000000..7929f8d1a0
--- /dev/null
+++ b/challenge-227/robbie-hatley/perl/ch-2.pl
@@ -0,0 +1,130 @@
+#! /bin/perl -CSDA
+
+=pod
+
+--------------------------------------------------------------------------------------------------------------
+COLOPHON:
+This is a 110-character-wide Unicode UTF-8 Perl-source-code text file with hard Unix line breaks ("\x0A").
+¡Hablo Español! Говорю Русский. Björt skjöldur. ॐ नमो भगवते वासुदेवाय. 看的星星,知道你是爱。麦藁雪、富士川町、山梨県。
+
+--------------------------------------------------------------------------------------------------------------
+TITLE BLOCK:
+Solutions in Perl for The Weekly Challenge 227-2.
+Written by Robbie Hatley on Mon Jul 24, 2023.
+
+--------------------------------------------------------------------------------------------------------------
+PROBLEM DESCRIPTION:
+Task 2: Roman Maths
+Submitted by: Peter Campbell Smith
+Write a script to handle a 2-term arithmetic operation expressed in Roman numeral.
+Examples:
+IV + V => IX
+M - I => CMXCIX
+X / II => V
+XI * VI => LXVI
+VII ** III => CCCXLIII
+V - V => nulla (they knew about zero but didn't have a symbol)
+V / II => non potest (they didn't do fractions)
+MMM + M => non potest (they only went up to 3999)
+V - X => non potest (they didn't do negative numbers)
+
+--------------------------------------------------------------------------------------------------------------
+PROBLEM NOTES:
+I'm sooooo not going to make roman-to-arabic or arabic-to-roman converters. Let's see what CPAN has to offer.
+Ah, it has "Text::Roman". Fine I'll use that. The rest is just expression validity checking, operator parsing,
+Latin output phrasing ("nulla" or "non potest" where appropriate), and other such details.
+
+--------------------------------------------------------------------------------------------------------------
+IO NOTES:
+Input is via either built-in variables or via @ARGV. If using @ARGV, provide one argument which must be a
+double-quoted array of single-quoted roman-math expressions, with operators separated from operands with
+white space, in proper Perl syntax, like so:
+./ch-2.pl "('MCMLXIX - MCMLIV', 'XIV / VII')"
+
+Output is to STDOUT and will be each expression followed by its result.
+
+=cut
+
+# ------------------------------------------------------------------------------------------------------------
+# PRELIMINARIES:
+
+use v5.36;
+use strict;
+use warnings;
+use utf8;
+use Sys::Binmode;
+use Time::HiRes 'time';
+use Text::Roman ':all';
+$"=', ';
+
+# ------------------------------------------------------------------------------------------------------------
+# SUBROUTINES:
+
+# Does given string represent a valid operator?
+sub isopera ($o) {
+ return ( $o =~ m/(?:^\+$)|(?:^-$)|(?:^\*$)|(?:^\/$)|(?:^\*\*$)/ );
+}
+
+# Perform a calculation using Roman numerals:
+sub computare ($e) {
+ my @array = split /\s+/, $e;
+ return "INVALID EXPRESSION" if ( 3 != scalar @array );
+ my ($x, $o, $y) = @array;
+ return "INVALID EXPRESSION" if ( ! isroman($x) );
+ return "INVALID EXPRESSION" if ( ! isopera($o) );
+ return "INVALID EXPRESSION" if ( ! isroman($y) );
+ my $result = 0;
+ if ( '+' eq $o ) {
+ $result = roman2int($x) + roman2int($y);
+ }
+ elsif ( '-' eq $o ) {
+ $result = roman2int($x) - roman2int($y);
+ }
+ elsif ( '*' eq $o ) {
+ $result = roman2int($x) * roman2int($y);
+ }
+ elsif ( '/' eq $o ) {
+ $result = roman2int($x) / roman2int($y);
+ }
+ elsif ( '**' eq $o ) {
+ $result = roman2int($x) ** roman2int($y);
+ }
+ return 'nulla' if 0 == $result; # no symbol for 0
+ return 'non potest' if 0 != $result - int $result; # no fractions
+ return 'non potest' if $result > 3999; # no numbers > 3999
+ return 'non potest' if $result < 0; # no numbers < 0
+ return int2roman($result);
+}
+
+# ------------------------------------------------------------------------------------------------------------
+# MAIN BODY OF PROGRAM:
+
+# Start timer:
+my $t0 = time;
+
+# Default inputs:
+my @expressions =
+(
+ 'IV + V',
+ 'M - I',
+ 'X / II',
+ 'XI * VI',
+ 'VII ** III',
+ 'V - V',
+ 'V / II',
+ 'MMM + M',
+ 'V - X',
+);
+
+# Non-default inputs:
+@expressions = eval($ARGV[0]) if @ARGV;
+
+# Main loop:
+for my $expression (@expressions) {
+ say '';
+ say "$expression = ", computare($expression);
+}
+
+# Determine and print execution time:
+my $µs = 1000000 * (time - $t0);
+printf("\nExecution time was %.0fµs.\n", $µs);