Perl Weekly Challenge 030: Sunday Christmas and Series with sum 12

Sunday Christmas

Write a script to list dates for Sunday Christmas between 2019 and 2100. For example, 25 Dec 2022 is Sunday.

I used the core module Time::Piece to check the dates.

It’s easy to create a string representing Christmas: just concatenate the year with '-12-25'. The module’s strptime method can be used to create an object if we provide a format of the input string, in this case it’s '%Y-%m-%d'. The object’s method day_of_week now tells us what day the object represents, 0 corresponds to Sunday, which is the day we’re interested in.

#!/usr/bin/perl
use warnings;
use strict;

use Time::Piece;

sub sunday_xmas {
    my ($year) = @_;
    return 0 == 'Time::Piece'
        ->strptime("$year-12-25", '%Y-%m-%d')
        ->day_of_week
}

To list the Sunday Christmas, let’s just iterate over all the years and use the function as a filter:

use feature qw{ say };

for my $year (2019 .. 2100) {
    say "25 Dec $year" if sunday_xmas($year);
}

I tested my solution against several Christmas dates—each of them represents a different week day.

use Test::More tests => 7;
ok   sunday_xmas(2022), 'Sunday 25 Dec 2022';
ok ! sunday_xmas(2021), 'Saturday 25 Dec 2021';
ok ! sunday_xmas(2020), 'Friday 25 Dec 2020';
ok ! sunday_xmas(2025), 'Thursday 25 Dec 2025';
ok ! sunday_xmas(2019), 'Wednesday 25 Dec 2019';
ok ! sunday_xmas(2029), 'Tuesday 25 Dec 2029';
ok ! sunday_xmas(2023), 'Monday 25 Dec 2023';

Series with sum 12

Write a script to print all possible series of 3 positive numbers, where in each series at least one of the number is even and sum of the three numbers is always 12. For example, 3,4,5.

There are several possible ways how to understand the challenge. Let’s choose one and interpret the “series” as a non-decreasing sequence of numbers with duplicates allowed.

Now we can just iterate over all the possible combinations and report the triples that sum to 12 and contain at least one even number:

#!/usr/bin/perl
use warnings;
use strict;
use feature qw{ say };

for my $i (1 .. 10) {
    for my $j ($i .. 10) {
        last if $i + $j > 11;

        for my $k ($j .. 10) {
            last if $i + $j + $k > 12;

            say "$i, $j, $k"
                if $i + $j + $k == 12
                && 0 == $i * $j * $k % 2
        }
    }
}

We can skip the second loop if $i + $j > 11, as the whole sum even for the smallest possible $k must be greater to 12 (as $k must be positive).

Also, the last condition can be simplified. If we remove the right hand side of the &&, the results don’t change. The reason is that the sum of three odd numbers is always odd, but 12 is even. Therefore, at least one of the numbers must be non-odd, i.e. even.

Leave a comment

About E. Choroba

user-pic I blog about Perl.