### Perl Weekly Challenge: Week 107

#### Challenge 1:

**Self-Descriptive Numbers**

Write a script to display the first three self-descriptive numbers. As per wikipedia, the definition of

`Self-descriptive Number`

isIn mathematics, a self-descriptive number is an integer m that in a given base b is b digits long in which each digit d at position n (the most significant digit being at position 0 and the least significant at position b−1) counts how many instances of digit n are in m.

##### Example

```
1210 is a four-digit self-descriptive number:
position 0 has value 1 i.e. there is only one 0 in the number
position 1 has value 2 i.e. there are two 1 in the number
position 2 has value 1 i.e. there is only one 2 in the number
position 3 has value 0 i.e. there is no 3 in the number
```

##### Output

```
1210, 2020, 21200
```

Actually Mohammed made a mistake; this problem was already set once before in week 43 of the challenge so I thought I would be able to just reuse the solution I gave then. Unfortunately, it looks like I got it wrong that time so I had to do it again. I'll show you the Raku version first.

The basic idea is to do a search through all the numbers and select the first three which are self-descriptive.

```
sub MAIN() {
my @sdns;
for 4 .. 5 -> $base {
```

We can do a more efficient search by restricting it to base 4 and base 5 numbers. We know from the information provided on the wikipedia page mentioned in the spec that the first three self-descriptive numbers will be in either of those bases.

```
for 10 ** ($base - 2) ..^ 10 ** ($base - 1) -> $i {
```

Furthermore from the wikipedia page we also know that answers will have a length of `$base - 1`

base-10 digits so we can optimize yet further by restricting our search to those numbers.

```
my $n = $i.base($base);
```

However we want to actually look at base-4 or base-5 numbers not base-10 so we do a conversion here.

```
if is_sdn($n) {
@sdns.push($n);
}
if (@sdns.elems == 3) {
last;
}
```

If we have a valid self-descriptive number we add it to the list and once we have three in the list we stop...

```
}
}
@sdns.join(q{, }).say;
}
```

...and print the results.

This function determines if a number is self-descriptive.

```
sub is_sdn(Str $n) {
if !is_harshad($n) {
return False;
}
```

One more fact about self-descriptive numbers we can use to our advantage is that they are all Harshad numbers. So we can automatically discard any input which is not a Harshad number. The check looks like this:

```
sub is_harshad(Str $n) {
return $n % $n.comb.sum == 0;
}
```

Back to `is_sdn()`

. This code counts how many instances of each digit we have and if they are in the right positions,
We return true or false accordingly.

```
my @digits = $n.comb;
my %count;
for 0 ..^ @digits.elems -> $i {
%count{ @digits[$i] }++;
}
for 0 ..^ @digits.elems -> $i {
if %count{$i}:!exists {
next;
}
if %count{$i} != @digits[$i] {
return False;
}
}
return True;
}
```

As usual, Perl requires more code to add functionality which is built in to Raku. Here for example, is a function to convert into a particular base.

```
sub base {
my ($number, $base) = @_;
my @digits = (0 .. 9, 'A' .. 'Z');
my @result;
while ($number > ($base - 1)) {
my $digit = $number % $base;
push @result, $digits[$digit];
$number /= $base;
}
push @result, $digits[$number];
return join '', reverse @result;
}
```

This is our check for Harshad number status.

```
sub is_harshad {
my ($n) = @_;
my $total = 0;
my @digits = split //, $n;
for my $digit (@digits) {
$total += $digit;
}
return @digits == $total;
}
```

Armed with these helper functions, `is_sdn()`

is the same as in Raku.

```
sub is_sdn {
my ($n) = @_;
if (!is_harshad($n)) {
return undef;
}
my @digits = split //, $n;
my %count;
for my $i (0 .. scalar @digits - 1) {
$count{ $digits[$i] }++;
}
for my $i (0 .. scalar @digits - 1) {
if (!exists $count{$i}) {
next;
}
if ($count{$i} != $digits[$i]) {
return undef;
}
}
return 1;
}
```

The main algorithm is also the same as in Raku.

```
my @sdns;
for my $base (4 .. 5) {
for my $i (10 ** ($base - 2) .. 10 ** ($base - 1) - 1) {
my $n = base($i, $base);
if (is_sdn($n)) {
push @sdns, $n;
}
if (scalar @sdns == 3) {
last;
}
}
}
say join q{, }, @sdns;
```

#### Challenge 2:

**List Methods**

Write a script to list methods of a package/class.

##### Example

```
package Calc;
use strict;
use warnings;
sub new { bless {}, shift; }
sub add { }
sub mul { }
sub div { }
1;
```

##### Output

```
BEGIN
mul
div
new
add
```

The subroutines in a Perl5 package (or methods in a class. They are the same thing in Perl.) are listed in a symbol table
which is just a plain old hash. It can be accessed as the package name followed by `::`

. like this:

```
for my $key (sort keys %Calc::) {
say $key;
}
```

In Raku, there is a `.^methods()`

method every object has. It can be accessed like this:

```
for Calc.^methods -> $method {
say $method;
}
```