## Perl Weekly Challenge 69: Strobogrammatic Numbers and 0/1 Strings

These are some answers to the Week 69 of the Perl Weekly Challenge organized by Mohammad S. Anwar.

*Spoiler Alert:* This weekly challenge deadline is due in a couple of days (July 19, 2020). This blog post offers some solutions to this challenge, please don’t read on if you intend to complete the challenge on your own.

## Task 1: Strobogrammatic Numbers

*A strobogrammatic number is a number that looks the same when looked at upside down.*

*You are given two positive numbers $A and $B such that 1 <= $A <= $B <= 10^15.*

*Write a script to print all strobogrammatic numbers between the given two numbers.*

*Example*

```
Input: $A = 50, $B = 100
Output: 69, 88, 96
```

The first question is: can the digit 1 be part of a strobogrammatic number? Some people handwrite 1 as a simple vertical bar, and some printing fonts also. In most fonts, however, 1 is more complicated than a single vertical bar, including the font used by my text editor to display a 1. So I decided against including 1. This decision does not change the algorithm I’ll use, so it would be very easy to change that and add 1 to the authorized digits..

With this decision made, a strobogrammatic number can only be composed of digits 0, 6, 8, and 9. In addition, the string containing the reversed number must have 0s and 8s in the same position as the original string, and 6s must be replaced by 9s, and conversely.

### Strobogrammatic Numbers in Raku

We’ll use some form of brute force: we will loop over all numbers in the range passed to the program, filter out any number containing anything else than 0, 6, 8, and 9, and finally compare each remaining number with the number generated by `flip`

ping the input ans substituting 9 with 6 and vice-versa.

```
use v6;
sub MAIN (Int $i, Int $j where 1 <= $i <= $j <= 1e15) {
for $i..$j -> $k {
next if $k ~~ / <-[0689]> /;
say $k if $k eq $k.flip.map({TR/69/96/});
}
}
```

Let’s start by running the program with faulty arguments:

```
$ raku strobo.raku foo bar
Type check failed in binding to parameter '<anon>'; expected Any but got Mu (Mu)
in block <unit> at strobo.raku line 1
$ raku strobo.raku 0 5
Type check failed in binding to parameter '<anon>'; expected Any but got Mu (Mu)
in block <unit> at strobo.raku line 1
$ raku strobo.raku 10 1
Type check failed in binding to parameter '<anon>'; expected Any but got Mu (Mu)
in block <unit> at strobo.raku line
```

The error message could be clearer, but the program fails as expected because parameter values don’t match the `MAIN`

subroutine signature. Let’s now run it with correct arguments:

```
$ raku strobo.raku 1 1000
8
69
88
96
609
689
808
888
906
986
```

### Strobogrammatic Numbers in Perl

We’ll use the same algorithm as in Raku.

```
use strict;
use warnings;
use feature qw /say/;
for my $k ($ARGV[0]..$ARGV[1]) {
next unless $k =~ /^[0689]+$/;
my $i = reverse $k;
$i =~ tr/69/96/;
say $k if $i eq $k;
}
```

Note that input parameter validation (if needed) is very easy and is left as an exercise to the reader.

If we now run it with the same arguments as the last Raku program run, we (fortunately) get the same output:

```
$ perl strobo.pl 1 1000
8
69
88
96
609
689
808
888
906
986
```

## Task 2: 0/1 Strings

*A 0/1 string is a string in which every character is either 0 or 1.*

*Write a script to perform switch and reverse to generate S30 as described below:*

```
switch:
Every 0 becomes 1 and every 1 becomes 0. For example, “101” becomes “010”.
reverse:
The string is reversed. For example, "001” becomes “100”.
```

*Please follow the rule as below:*

```
S0 = “”
S1 = “0”
S2 = “001”
S3 = “0010011”
…
SN = SN-1 + “0” + switch(reverse(SN-1))
```

In the original version of the task, it was requested to generate `S1000`

, which is just impossible as the resulting number would have about `1E305`

(or 10 to the 305th power) digits, because of the geometric progression (exponential) explosion of the result. That number of digits is much much larger than the number of atoms in the entire universe, so there is just no way it will be stored in the memory of any computer. (Please note that we’re not talking here about the resulting number `S1000`

, but only about the number of digits of that number, i.e. something in the order of the decimal logarithm of `S1000`

.) And, even assuming it were possible to store the number in question, computing `S1000`

would also take much much much more than the current age of the universe, so all challengers would miss the next Sunday deadline by a very very very large margin.

In fact, even generating `S30`

turned out to be extremely long, way too long in fact. `S20`

contains already more than a million digits; running it is quite OK (it runs in about two seconds), but `S30`

would take days (I gave up and stopped the program when reaching `S26`

after about a day execution, so that `S30`

would probably take several weeks). So, for the examples below, I’ll use much smaller input values. Unless, of course, there is a better algorithm, but I fail to figure out one at this point (more on this later).

### 0/1 Strings in Raku

Rather than printing only the last result (`Sxx`

), I decided to print all intermediate results between `S3`

and `S8`

, since it makes it possible to check manually the results.

```
use v6;
sub switch (Str $num) {
[~] $num.comb.map({$_ eq "0" ?? 1 !! 0});
}
my $prev = '001';
for 3..8 -> $i {
$prev = $prev ~ "0" ~ switch $prev.flip;
say "$i $prev";
}
```

This produces the following output (reformatted to make it look nicer on this blog post):

```
3 0010011
4 001001100011011
5 0010011000110110001001110011011
6 001001100011011000100111001101100010011000110111001001110011011
7 0010011000110110001001110011011000100110001101110010011100110110
001001100011011000100111001101110010011000110111001001110011011
8 0010011000110110001001110011011000100110001101110010011100110110
0010011000110110001001110011011100100110001101110010011100110110
0010011000110110001001110011011000100110001101110010011100110111
001001100011011000100111001101110010011000110111001001110011011
```

We can improve performance using the `tr///`

operator in the `switch`

subroutine:

```
sub switch (Str $num is copy) {
$num ~~ tr/01/10/;
}
```

Anyway, with a program undergoing such a massive exponential explosion, such small optimizations are probably somewhat pointless.

### 0/1 Strings in Perl

For the Perl version, I decided to try to get rid of the `switch`

subroutine used in Raku and to use the `tr///r`

operator in a probably quite futile attempt to improve performance.

```
use strict;
use warnings;
use feature qw /say/;
my $prev = '001';
for my $i (3..8) {
$prev = $prev . "0" . reverse map { tr/01/10/r } $prev;;
say "$i $prev";
}
```

This produces the following output (reformatted to make it look nicer on this blog post):

```
3 0010011
4 001001100011011
5 0010011000110110001001110011011
6 001001100011011000100111001101100010011000110111001001110011011
7 0010011000110110001001110011011000100110001101110010011100110110
001001100011011000100111001101110010011000110111001001110011011
8 0010011000110110001001110011011000100110001101110010011100110110
0010011000110110001001110011011100100110001101110010011100110110
0010011000110110001001110011011000100110001101110010011100110111
001001100011011000100111001101110010011000110111001001110011011
```

### Additional Thoughts on 0/1 Strings

If you look carefully at the output, there appears to be repeated patterns. For example, the line for `S6`

is repeated as the first line of `S7`

and `S8`

(not surprisingly, as this is the way the number is constructed), except for the trailing 0, but also as the third line of `S8`

, which is somewhat unexpected. Similarly, the second line of `S7`

is the same as the second line of `S8`

(again, by construction) except for the trailing 0, and also the same as the last line of `S8`

, for reasons that are less obvious (and also as the sixth line of `S9`

, not shown above). There are several other repeated patterns (for example `S5`

is repeated at the beginning of all lines of `S6`

, `S7`

, and `S8`

. Also, the 31 last digits of S6 are repeated at the end of each of the subsequent lines (lines of `S7`

and `s8`

), except for the trailing digits. This may have to do with the fact that is you apply twice the switch and reverse operations on a sequence of digits, you get back the original sequence. I really don’t have time now to investigate further these patterns, but there might be a way to construct these `Sxx`

numbers that is faster than the recursive definition given in the task specification.

## Wrapping up

The next week Perl Weekly Challenge will start soon. If you want to participate in this challenge, please check https://perlweeklychallenge.org/ and make sure you answer the challenge before 23:59 BST (British summer time) on Sunday, July 26, 2020. And, please, also spread the word about the Perl Weekly Challenge if you can.

## Leave a comment