by Arne Sommer

# Swap Sequence with Raku and Perl

 Published 4. July 2021.

This is my response to the Perl Weekly Challenge #119.

## Challenge #119.1: Swap Nibbles

You are given a positive integer `\$N`.

Write a script to swap the two nibbles of the binary representation of the given number and print the decimal number of the new binary representation.

A nibble is a four-bit aggregation, or half an octet.

To keep the task simple, we only allow integer less than or equal to 255. Example 1: ```Input: \$N = 101 Output: 86 Binary representation of decimal 101 is 1100101 or as 2 nibbles (0110)(0101). The swapped nibbles would be (0101)(0110) same as decimal 86. Input: \$N = 18 Output: 33 Binary representation of decimal 18 is 10010 or as 2 nibbles (0001)(0010). The swapped nibbles would be (0010)(0001) same as decimal 33. ```

treating the values as strings, and applying substring selection is the most efficient way of doing this (from a programmer point of view).

File: swap-nibbles ```#! /usr/bin/env raku unit sub MAIN (Int \$N where \$N > 0 && \$N <= 255, :v(:\$verbose)); #  my \$binary = \$N.fmt('%08b'); #  my \$swapped = \$binary.substr(4) ~ \$binary.substr(0,4); #  if \$verbose { say ": Binary: \$binary"; say ": Swapped: \$swapped (binary)"; } say \$swapped.parse-base(2); #  ```

 Ensure a positive integer in the range 1 .. 255.

 Get the binary representation (with `fmt`) as an 8-bit number. Note the leading zero, which gives us a zero padded value of length 8; e.g. `00010010` for 18.

 Get the second half and the first half (both with `substr`), and glue them together (with the string concatenation operator `~`).

 Convert the number from binary (the «2» part) to decimal (or rather, whatever Raku uses internally).

See docs.raku.org/routine/fmt more information about `fmt`.

See docs.raku.org/routine/substr for more information about `substr`.

See docs.raku.org/routine/~ for more information about the string concatenation operator `substr`.

See docs.raku.org/routine/parse-base for more information about `parse-base`.

Running it:

```\$ ./swap-nibbles 101 86 \$ ./swap-nibbles 18 33 ```

Looking good.

With verbose mode:

```\$ ./swap-nibbles -v 101 : Binary: 01100101 : Swapped: 01010110 (binary) 86 \$ ./swap-nibbles -v 18 : Binary: 00010010 : Swapped: 00100001 (binary) 33 ```

We can make it shorter (practically a one liner), with `with`:

File: swap-nibbles-with ```#! /usr/bin/env raku unit sub MAIN (Int \$N where \$N > 0 && \$N <= 255); say (\$_.substr(4) ~ \$_.substr(0,4)).parse-base(2) with \$N.fmt('%08b'); #  ```

 The trick with `with` is that it sets the topic variable (i.e. `\$_`) to the given expression for the affixed block.

See docs.raku.org/language/control#index-entry-control_flow_with for more information about `with`.

Running it gives the same result as for the previous version (except that verbose mode has gone, as there are no intermediary variables to be verbose about):

```\$ ./swap-nibbles-with 101 86 \$ ./swap-nibbles-with 18 33 ```

### A Perl Version

This is straight forward translation of the Raku version.

File: swap-nibbles-perl ```#! /usr/bin/env perl use strict; use warnings; use feature 'say'; use Getopt::Long; my \$verbose = 0; GetOptions("verbose" => \\$verbose); my \$N = \$ARGV // ""; die "Please specify an integer in the range 1..255" if \$N !~ /^[1-9]\d*\$/ || \$N > 255; my \$binary = sprintf('%08b', \$N); my \$swapped = substr(\$binary, 4) . substr(\$binary, 0, 4); if (\$verbose) { say ": Binary: \$binary"; say ": Swapped: \$swapped (binary)"; } say oct("0b" . \$swapped); #  ```

 The «oct» call does support octal numbers, but can be used on binary values as well if prefixed with «0b».

Running it gives the same result as the Raku version:

```\$ ./swap-nibbles-perl 18 33 \$ ./swap-nibbles-perl 101 86 \$ ./swap-nibbles-perl -v 18 : Binary: 00010010 : Swapped: 00100001 (binary) 33 \$ ./swap-nibbles-perl -v 101 : Binary: 01100101 : Swapped: 01010110 (binary) 86 ```

### Bitwise Operations

We could have used bitwise operations here; something like this (in quasi code):

```((\$N bitwise-and 11110000) right-shift-4) bitwise-or ((\$N bitwise-and 00001111) left-shift-4) ```

The right and left shift operators have not been implemented yet in Raku.

But we can do this bit (pun intended) in Perl:

File: swap-nibbles-bitwise-perl ```#! /usr/bin/env perl use strict; use warnings; use feature 'say'; use Getopt::Long; my \$verbose = 0; GetOptions("verbose" => \\$verbose); my \$N = \$ARGV // ""; die "Please specify an integer in the range 1..255" if \$N !~ /^[1-9]\d*\$/ || \$N > 255; my \$swapped = ((\$N & 15) << 4) | ((\$N & 241) >> 4); if (\$verbose) { say ": Binary: ", sprintf('%08b', \$N); say ": Swapped: ", sprintf('%08b', \$swapped), " (binary)"; } say \$swapped; ```

Note that the bitwise operations operate on integers (or rather, whatever Perl uses internally), so that we do not have to mess about with numeric conversion. Except for the verbose output, as a nicety.

## Challenge #119.2: Sequence without 1-on-1

Write a script to generate sequence starting at 1. Consider the increasing sequence of integers which contain only 1’s, 2’s and 3’s, and do not have any doublets of 1’s like below. Please accept a positive integer `\$N` and print the `\$Nth` term in the generated sequence.

``` 1, 2, 3, 12, 13, 21, 22, 23, 31, 32, 33, 121, 122, 123, 131, … ``` Example: ```Input: \$N = 5 Output: 13 Input: \$N = 10 Output: 32 Input: \$N = 60 Output: 2223 ```

The number system is unlike anything seen in nature (so to speak), so manual addition (with carrying) is the thing. If the digit is «1» or «2», we add one. Else (it is «3»), we set the carrying flag (called «\$add») and the current digit to «1». The final rule about double 1s is handled separately, at the end.

File: seq-without-seq ```#! /usr/bin/env raku unit sub MAIN (Int \$N where \$N > 0, :v(:\$verbose)); my \$seq := gather #  { my \$current = 1; #  take 1; # [2a] loop #  { my \$new = ""; my \$add = True; for \$current.comb.reverse -> \$digit is copy { if \$add { if \$digit <= 2 { \$digit++; \$add = False; } else { \$digit = 1; } } \$new = \$digit ~ \$new; } \$new = "1\$new" if \$add; \$current = \$new; take \$current unless \$current ~~ /11/; #  } } say ": Sequence: ", \$seq[^\$N].join(', ') if \$verbose; say \$seq[\$N-1]; ```

 Using `gather`/`take` to collect the values (a sequence) looks like a good idea.

 The first value is «1». Return it (with `take`).

 For every value after the first one, start with the previous one (in «\$current») and add 1 to the rightmost digit (`\$current.comb.reverse`) and work to the left with carrying.

 Skip values with double 1s. (As in, do not return them.)

See my Raku Gather, I Take article or docs.raku.org/syntax/gather take for more information about `gather`/`take`.

Running it:

```\$ ./seq-without-seq 5 13 \$ ./seq-without-seq 10 32 \$ ./seq-without-seq 60 2223 ```

We got the same result as the page linked to in the challenge.

With verbose mode:

```\$ ./seq-without-seq -v 5 : Sequence: 1, 2, 3, 12, 13 13 \$ ./seq-without-seq -v 10 : Sequence: 1, 2, 3, 12, 13, 21, 22, 23, 31, 32 32 \$ ./seq-without-seq -v 60 : Sequence: 1, 2, 3, 12, 13, 21, 22, 23, 31, 32, 33, 121, 122, 123, 131, 132, 133, 212, 213, 221, 222, 223, 231, 232, 233, 312, 313, 321, 322, 323, 331, 332, 333, 1212, 1213, 1221, 1222, 1223, 1231, 1232, 1233, 1312, 1313, 1321, 1322, 1323, 1331, 1332, 1333, 2121, 2122, 2123, 2131, 2132, 2133, 2212, 2213, 2221, 2222, 2223 2223 ```

Here is a version with a conventional array instead of the `gather`/`take` Sequence. Also note the

File: seq-without-loop ```#! /usr/bin/env raku unit sub MAIN (Int \$N where \$N > 0, :v(:\$verbose)); my @seq = 1; my \$current = 1; while @seq.elems < \$N { my \$new = ""; my \$add = True; for \$current.comb.reverse -> \$digit is copy { if \$add { if \$digit <= 2 { \$digit++; \$add = False; } else { \$digit = 1; } } \$new = \$digit ~ \$new; } \$new = "1\$new" if \$add; \$current = \$new; @seq.push: \$current unless \$current.contains('11'); ## -> https://docs.raku.org/routine/contains } say ": Sequence: ", @seq[^\$N].join(', ') if \$verbose; say @seq[\$N-1]; ```

 Note the use of `contains` instead of the original Regex.

See docs.raku.org/routine/contains for more information about `contains`.

Running it gives the same result as above.

The challenge asked for a sequence, and we did provide that - as shown with verbose mode in the two programs above. But we do not actually need it. Here is a version that does not generate a sequence at all, just the current value (and an index counter).

File: seq-without-single ```#! /usr/bin/env raku unit sub MAIN (Int \$N where \$N > 0); my \$count = 1; my \$current = 1; while \$count < \$N { my @digits = \$current.comb.reverse; my \$new = ""; my \$add = True; for \$current.comb.reverse -> \$digit is copy { if \$add { if \$digit <= 2 { \$digit++; \$add = False; } else { \$digit = 1; } } \$new = \$digit ~ \$new; } \$new = "1\$new" if \$add; \$current = \$new; \$count++ unless \$current.contains('11'); } say \$current; ```

Note that verbose mode has gone, as we do not have a sequence laying about to be verbose about. (We could have printed the index and current value inside the loop, and feel free to do that.)

### Perl

This is a straight forward translation of the last Raku version.

File: seq-without-single-perl ```#! /usr/bin/env perl use strict; use warnings; use feature 'say'; my \$N = \$ARGV // ""; die "Please specify a positive integer" if \$N !~ /^[1-9]\d*\$/; my \$count = 1; my \$current = 1; while (\$count < \$N) { my @digits = split(//, reverse(\$current)); my \$new = ""; my \$add = 1; for my \$digit (split(//, reverse(\$current))) { if (\$add) { if (\$digit <= 2) { \$digit++; \$add = 0; } else { \$digit = 1; } } \$new = \$digit . \$new; } \$new = "1\$new" if \$add; \$current = \$new; \$count++ unless \$current =~ /11/; } say \$current; ```

Running it gives the same result as the Raku versions:

```\$ ./seq-without-single-perl 5 13 \$ ./seq-without-single-perl 10 32 \$ ./seq-without-single-perl 60 2223 ```

And that's it.