diff options
| author | Jörg Sommrey <28217714+jo-37@users.noreply.github.com> | 2021-11-12 16:05:01 +0100 |
|---|---|---|
| committer | Jörg Sommrey <28217714+jo-37@users.noreply.github.com> | 2021-11-12 16:05:01 +0100 |
| commit | dcf8d54ba8431df0b1f031c43d02dfa05cf998e5 (patch) | |
| tree | ecbca3d52e0ea7431240491d929f2e5d9b1c0f12 | |
| parent | 8efdb41631ac61515e268960162a0e8c4066d41c (diff) | |
| parent | 44f14b09f2e49649d8de2e213eaded0e6f4fc66b (diff) | |
| download | perlweeklychallenge-club-dcf8d54ba8431df0b1f031c43d02dfa05cf998e5.tar.gz perlweeklychallenge-club-dcf8d54ba8431df0b1f031c43d02dfa05cf998e5.tar.bz2 perlweeklychallenge-club-dcf8d54ba8431df0b1f031c43d02dfa05cf998e5.zip | |
Solutions to challenge 138
| -rwxr-xr-x | challenge-138/jo-37/perl/ch-1.pl | 91 | ||||
| -rwxr-xr-x | challenge-138/jo-37/perl/ch-2.pl | 87 |
2 files changed, 178 insertions, 0 deletions
diff --git a/challenge-138/jo-37/perl/ch-1.pl b/challenge-138/jo-37/perl/ch-1.pl new file mode 100755 index 0000000000..da396433b8 --- /dev/null +++ b/challenge-138/jo-37/perl/ch-1.pl @@ -0,0 +1,91 @@ +#!/usr/bin/perl -s + +use v5.16; +use Test2::V0; +use DateTime; +use experimental 'signatures'; +# For testing only: +use DateTime::Duration; + +our ($tests, $examples); + +run_tests() if $tests || $examples; # does not return + +die <<EOS unless @ARGV; +usage: $0 [-examples] [-tests] [Y] + +-examples + run the examples from the challenge + +-tests + run some tests + +Y + Count workday in year Y. + +EOS + + +### Input and Output + +# Count workdays between Jan 1 of the given year and the next. +say workdays_int(DateTime->new(year => $ARGV[0]), + DateTime->new(year => $ARGV[0] + 1)); + + +### Implementation + +# Find the number of workdays in the interval from $start to (not +# including) $end. Expecting DateTime arguments. +sub workdays_int ($start, $end) { + return 0 if $start >= $end; + my $days = $end->delta_days($start)->in_units('days'); + # Sat is 5, Sun is 6. + my $dow = $start->day_of_week_0; + + # Every full week has 5 workdays. From the remaining days count + # working days only. + 5 * int($days / 7) + grep abs($dow + $_ - 5.5) > 1, 0 .. $days % 7 - 1; +} + + +### Examples and tests + +sub run_tests { + SKIP: { + skip "examples" unless $examples; + + is workdays_int(DateTime->new(year => 2021), + DateTime->new(year => 2022)), 261, 'example 1'; + is workdays_int(DateTime->new(year => 2020), + DateTime->new(year => 2021)), 262, 'example 2'; + } + + SKIP: { + skip "tests" unless $tests; + + my $m = DateTime->new( + year => 2021, + month => 11, + day => 8); # Challenge 138 published on Mon + my $d = DateTime::Duration->new(days => 1); + is workdays_int($m, $m), 0, 'same day'; + is workdays_int($m, $m + 4*$d), 4, 'Mon to Fri'; + is workdays_int($m, $m + 5*$d), 5, 'Mon to Sat'; + is workdays_int($m, $m + 6*$d), 5, 'Mon to Sun'; + is workdays_int($m + 3*$d, $m + 17*$d), 10, 'two full weeks'; + is workdays_int($m + 3*$d, $m + 5*$d), 2, 'Thu to Sat'; + is workdays_int($m + 3*$d, $m + 6*$d), 2, 'Thu to Sun'; + is workdays_int($m + 3*$d, $m + 7*$d), 2, 'Thu to Mon'; + is workdays_int($m + 4*$d, $m + 5*$d), 1, 'Fri to Sat'; + is workdays_int($m + 4*$d, $m + 6*$d), 1, 'Fri to Sun'; + is workdays_int($m + 4*$d, $m + 7*$d), 1, 'Fri to Mon'; + is workdays_int($m + 5*$d, $m + 7*$d), 0, 'Sat to Mon'; + is workdays_int($m + 6*$d, $m + 7*$d), 0, 'Sun to Mon'; + is workdays_int($m + 6*$d, $m + 12*$d), 5, 'Sun to Sat'; + is workdays_int($m + $d, $m), 0, 'end before start'; + } + + done_testing; + exit; +} diff --git a/challenge-138/jo-37/perl/ch-2.pl b/challenge-138/jo-37/perl/ch-2.pl new file mode 100755 index 0000000000..bf1930ebec --- /dev/null +++ b/challenge-138/jo-37/perl/ch-2.pl @@ -0,0 +1,87 @@ +#!/usr/bin/perl -s + +use v5.16; +use Test2::V0; +use experimental 'signatures'; + +our ($tests, $examples); + +run_tests() if $tests || $examples; # does not return + +die <<EOS unless @ARGV; +usage: $0 [-examples] [-tests] [N] + +-examples + run the examples from the challenge + +-tests + run some tests + +N + Check if the square root of N is the sum of two or more splits of N + +EOS + + +### Input and Output + +say 0 + root_sum(shift); + + +### Implementation + +sub root_sum ($n) { + # Split N into at least two parts and compare the squared sum of the + # parts with N. + # There is no need to disallow leading zeros in any part (except the + # first), as these may be split-off as separate parts resulting in + # the same sum and a larger number of parts, e.g. + # 201: 2 + 01 or 2 + 0 + 1. + # The only exception are single digit numbers that cannot be split + # into two parts and therefore must not have leading zeros. + our $sum; + $n =~ m{ + ^ + (?=\d+$) # Numbers only. + (?!0+.$) # Forbid leading zeros for 1-digit numbers. + (?{local $sum = 0}) # Initialize and localize the part sum. + (?: + (.+) # capture one part + (?{local $sum = $sum + $^N}) # backtracking-safe part sum + ){2,} # two or more parts + $ + + # Check part sum for complete matches: + (?(?{$sum ** 2 != $n}) (*FAIL)) + }x; +} + + +### Examples and tests + +sub run_tests { + SKIP: { + skip "examples" unless $examples; + + is root_sum(81), T(), 'example 1'; + is root_sum(9801), T(), 'example 2'; + is root_sum(36), F(), 'example 3'; + } + + SKIP: { + skip "tests" unless $tests; + + is root_sum(1296), T(), 'without zeros'; + is root_sum(18), F(), 'not a square'; + is root_sum(0), F(), 'zero'; + is root_sum('00'), F(), 'double zero'; + is root_sum(1), F(), 'one'; + is root_sum('01'), F(), 'one with leading zero'; + is root_sum('001'), F(), 'one with leading zeros'; + is root_sum('081'), T(), 'leading zero'; + is root_sum(-abc), F(), 'non-numeric'; + } + + done_testing; + exit; +} |
