This is my response to The Weekly Challenge #173.
$n
.
Esthetic Number
.
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
#! /usr/bin/env raku
unit sub MAIN (Int $n where $n > 0)); # [1]
say + is-esthetic($n); # [2]
sub is-esthetic ($number) # [2a]
{
my @digits = $n.comb; # [3]
my $current = @digits.shift; # [4]
while @digits.elems # [5]
{
return False
if all ($current != @digits[0] + 1), ($current != @digits[0] - 1); # [6]
$current = @digits.shift; # [7]
}
return True; # [8]
}
[1] Ensure a positive integer.
[2] Print «1» if the number is esthetic, and «0»
if not. I have delegated the computation to a procedure [2a] to make reuse easier. Note
the Numeric Coercion Prefix Operator +
used to get a numeric value
instead of the True
/False
returned by the procedure.
See
docs.raku.org/routine/+ for
more information about the Numeric Coercion Prefix Operator +
.
[3] Get the individual digits.
[4] Get the first digit.
[5] As long as there are more digits,
[6] The first !=
checks that the current digit is not one less
than the next one, and the second one that it is not one more than it. If both are true (set
up with an all
junction, we do not have an esthetic number (and returns
False
).
See
docs.raku.org/routine/all
for more information about the all
Junction.
[7] Move along, one more digit.
[8] We have reached the end, without failing. Then we have an esthetic number.
Running it:
$ ./esthetic-number 5456
1
$ ./esthetic-number 120
0
Looking good.
Note that one-digit numbers are considered esthetic by my implementation:
$ ./esthetic-number 1
1
Write a script to generate first 10 members
of Sylvester's
sequence
. For more informations, please refer to the
wikipedia page.
2
3
7
43
1807
3263443
10650056950807
113423713055421844361000443
12864938683278671740537145998360961546653259485195807
16550664732451996419846819544443918001751315270637749784185138876653\
5868639572406808911988131737645185443
This sequence popped up in part 7 of my Centenary Sequences with Raku article, published in November 2020, as sequence #085:
(my $sum = 2, { my $c = $sum +1; $sum *= $c; $c } ... Inf) # 085
It was presented without explanation, but I'll do it this time:
(my $sum = 2, { my $c = $sum +1; $sum *= $c; $c } ... Inf)
# 1 ######## # 2 ############################### # 3 ####
[1] This (everything before the comma) is the first value in the sequence. We declare a
variable $sum
which is local to the sequence. The result of the assignment
is the value itself, which then is the first value.
[2] We set up a local variable $c
, and use that one to change the global
(from the point of view of this block) $sum
. The generated value for the
sequence is the last one in the block - which is the single $c
.
[3] This tells Raku to use the block to the left [2] to genereate values ad infinitum.
I used it like this:
> say (my $sum = 2, { my $c = $sum +1; $sum *= $c; $c } ... Inf)[^8];
(2 3 7 43 1807 3263443 10650056950807 113423713055421844361000443)
Wrapping it up as a program is easy:
File: sylvesters-sequence
#! /usr/bin/env raku
unit sub MAIN (Int $count where $count > 0 = 10);
my $ss := (my $sum = 2, { my $c = $sum +1; $sum *= $c; $c } ... Inf);
say $ss[^$count].join("\n"); # [1]
[1] The join
adds a newline between each value, and the say
adds one after the last one - giving the output as specified by the challenge.
Running it:
$ ./sylvesters-sequence
2
3
7
43
1807
3263443
10650056950807
113423713055421844361000443
12864938683278671740537145998360961546653259485195807
16550664732451996419846819544443918001751315270637749784185138876653\
5868639572406808911988131737645185443
Looking good.
Curious about the eleventh value?
$ ./sylvesters-sequence 11
2
3
7
43
1807
3263443
10650056950807
113423713055421844361000443
12864938683278671740537145998360961546653259485195807
16550664732451996419846819544443918001751315270637749784185138876653\
5868639572406808911988131737645185443
27392450308603031423410234291674686281194364367580914627947367941608\
692026226993634332118404582438634929548737283992369758487974306317\
730580753883429460344956410077034761330476016739454649828385541500\
213920807
The number of digits in each value increases at an alarming rate, after the first three values. Here is a Sylvester length sequence, giving us the number of digits instead of the actual values:
File: sylvesters-length-sequence
#! /usr/bin/env raku
unit sub MAIN (Int $count where $count > 0 = 10);
my $ss := (my $sum = 2, { my $c = $sum +1; $sum *= $c; $c } ... Inf);
say $ss[^$count].map( *.chars ).join(", "); # [1]
[1] Note the map
we have inserted here, giving the number of characters (i.e.
digits), instead of the actual value. Doing this in the sequence would require a major
rewrite. (I have chosen to print a comma separated list this time, as the values are
much smaller.)
Running it:
$ ./sylvesters-length-sequence 12
1, 1, 1, 2, 4, 7, 14, 27, 53, 105, 209, 417
The pattern (from «4») seems to be «double the value and then subtract 1».
Generating some more values falsifies that assumption:
$ ./sylvesters-length-sequence 15
1, 1, 1, 2, 4, 7, 14, 27, 53, 105, 209, 417, 834, 1668, 3336
And that's it.