diff options
| author | robbie-hatley <Robbie.Hatley@gmail.com> | 2023-07-24 23:09:02 -0700 |
|---|---|---|
| committer | robbie-hatley <Robbie.Hatley@gmail.com> | 2023-07-24 23:09:02 -0700 |
| commit | 3ca3e81cc69d5d6421f91d1fad0fd7fb4eb3146d (patch) | |
| tree | 9b142ee07591bd4e9dd207be07bf019fb50a4fb3 | |
| parent | e4bdf5dcb6e741f1fb8e1b145fd2111f05ed6445 (diff) | |
| download | perlweeklychallenge-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.txt | 1 | ||||
| -rwxr-xr-x | challenge-227/robbie-hatley/perl/ch-1.pl | 145 | ||||
| -rwxr-xr-x | challenge-227/robbie-hatley/perl/ch-2.pl | 130 |
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); |
