Perl Weekly Challenge: Week 173

Challenge 1:

Esthetic Number

You are given a positive integer, $n.

Write a script to find out if the given number is Esthetic Number.

An esthetic number is a positive integer where every adjacent digit differs from its neighbour by 1.

For example,

5456 is an esthetic number as |5 - 4| = |4 - 5| = |5 - 6| = 1
120 is not an esthetic numner as |1 - 2| != |2 - 0| != 1

I put the code to determine if a number is esthetic into its' own function.

sub isEsthetic (Int $n) {
    my @digits = $n.comb;

The first thing this function does is to split $n into its' component digits.

    for 0 ..^ @digits.elems - 1 -> $i {
        if (@digits[$i] - @digits[$i + 1]).abs != 1 {
            return False;
        }
    } 

    return True;
}

Then it takes the indices of the first upto the first before last digit and loops through them. For each consecutive pair, the difference is taken. If it is ever not exactly 1, False is returned. If that never happens, $n is esthetic so True is returned.

say "$n is ", isEsthetic($n) ?? q{} !! 'not ', 'an esthetic number';

(Full code on Github.)

Armed with this function, we can print out a message like this.

The Perl version of isEsthetic() is shown below:

sub isEsthetic {
    my ($n) = @_;
    my @digits = split //, $n;

    for my $i (0 .. scalar @digits - 2) {
        if (abs($digits[$i] - $digits[$i + 1]) != 1) {
            return undef;
        }
    } 

    return 1;
}

(Full code on Github.)

As Perl lacks True and False, we use 1 and undef instead.

Challenge 2:

Sylvester's Sequence

Write a script to generate first 10 members of Sylvester's sequence. For more informations, please refer to the wikipedia page.

Output

2
3
7
43
1807
3263443
10650056950807
113423713055421844361000443
12864938683278671740537145998360961546653259485195807
165506647324519964198468195444439180017513152706377497841851388766535868639572406808911988131737645185443

Initially, I had hoped to make this a one-liner in Raku but after a few failed attempts, I gave up. But even "the long way round" this script is pretty short.

my @sylvesters = (2, 3);

I started by creating a list to hold the results. It is seeded with the first 2 numbers in the sequence because we need 2 in order to compute the next value.

while @sylvesters.elems < 10 {
    @sylvesters.push(([*] @sylvesters) + 1);
}

We multiply the existing values in the sequence (using [*]) and add 1. This number is added on to the results. When we have 10 values, we stop...

for @sylvesters {
    .say;
}

(Full code on Github.)

...and print them out. Easy peasy!

The main stumbling block with the Perl translation is that we don't have [*] but I already had a product() function from previous challenges I could use as a replacement.

my @sylvesters = (2, 3);

while (scalar @sylvesters< 10) {
    push @sylvesters, product(\@sylvesters) + 1;
}

for (@sylvesters) {
    say;
}

(Full code on Github.)

Perl by default displays large numbers differently than Raku. The output from my script looked like this

2
3
7
43
1807
3263443
10650056950807
1.13423713055422e+26
1.28649386832787e+52
1.6550664732452e+104

But it is not hard to get Perl to expand large integers fully. Simply place use bigint; at the top of the script.