# Perl Weekly Challenge 97

My solution to challenge two builds on last week’s challenge two, so I encourage you to go read last week’s post if you haven’t already!

## Task 1: Caesar Cipher

You are given string `$S`

containing alphabets `A..Z`

only and a number `$N`

.

Write a script to encrypt the given string `$S`

using a Caesar Cipher with left shift of size `$N`

.

### Example

```
Input: $S = "THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG", $N = 3
Output: "QEB NRFZH YOLTK CLU GRJMP LSBO QEB IXWV ALD"
Plain: ABCDEFGHIJKLMNOPQRSTUVWXYZ
Cipher: XYZABCDEFGHIJKLMNOPQRSTUVW
Plaintext: THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG
Ciphertext: QEB NRFZH YOLTK CLU GRJMP LSBO QEB IXWV ALD
```

### Solution

See below for explanation and any implementation-specific comments.

```
constant @alphabet = ('A'..'Z').List; # [1]
sub challenge(
Str $S where $S ~~ /^[<alpha>|<space>]+$/, # [2]
Int $N where $N >= 0
) {
$S.uc.trans(@alphabet => @alphabet.rotate(-$N)); # [3][4]
}
sub MAIN(Str $S, Int $N) {
say challenge($S, $N);
}
```

This program runs as such:

```
$ raku ch-1.raku 'THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG' 3
QEB NRFZH YOLTK CLU GRJMP LSBO QEB IXWV ALD
```

### Explanation

We use some cool built-in functionality to make this so simple. Here is the logic:

- Make sure the string is uppercase (
`.uc`

). They say we will always get uppercase, but might as well validate. - For each letter in the string, translate it to a different version of the alphabet that is rotated by
`$N`

spaces.

That’s it!

#### Specific comments

- Since the alphabet is always going to be constant we can instantiate it at the top level as a
`constant`

. Constants are evaluated at compile time, so this speeds up the program (even if just marginally). - You have likely seen me use this syntax before; these are called anonymous type constraints, and allow us to be a little more specific than just
`Str`

or`Int`

. In this case, we want a string that only contains letters and spaces, and an int that is greater than or equal to zero. `trans`

is a cool subroutine; it takes two lists (or strings) defining replacements to be made in the supplied string. Given the example above, it is the equivalent of something like`$S.subst('a', 'x').subst('b', 'y')...`

. The left argument, in our case, will always be the alphabet, and the right argument is the alphabet rotated by`$N`

spaces.`rotate`

takes a list and rotates it to the left. Since we need our letters shifted to the right, we use a negative number (`-$N`

).

## Task 2: Binary Substrings

You are given a binary string `$B`

and an integer `$S`

.

Write a script to split the binary string `$B`

of size `$S`

and then find the minimum number of flips required to make it all the same.

### Example 1

```
Input: $B = “101100101”, $S = 3
Output: 1
Binary Substrings:
"101": 0 flip
"100": 1 flip to make it "101"
"101": 0 flip
```

### Example 2

```
Input $B = “10110111”, $S = 4
Output: 2
Binary Substrings:
"1011": 0 flip
"0111": 2 flips to make it "1011"
```

### Solution

See below for explanation and any implementation-specific comments.

```
use Text::Levenshtein; # imports `distance`
sub challenge(
Str $B where $B ~~ /^[0|1]+$/,
Int $S where $S > 0
) {
my @segments = $B.comb.rotor($S, :partial).map(-> @chars { # [1]
my $segment = @chars.join;
$segment ~ '0' x ($S - $segment.chars) # [2][3]
});
distance(|@segments).sum; # [4]
}
multi sub MAIN(Str $B, Int $S) {
say challenge($B, $S);
}
```

This program runs as such:

```
$ raku ch-2.raku 101100101 3
1
```

### Explanation

The number of flips seems oddly similar to the edit distance from last week, no? I was able to reuse `Text::Levenshtein.distance`

from last week to find the “edit distance” between binary strings! We do a little work to split the string into `$S`

pieces (padding with zeros, if necessary), then leave all the heaving lifting to `distance`

.

#### Specific Comments

`rotor`

splits a list into pieces based on the argument (`$S`

in this case). We pass it the`:partial`

flag so that it keeps any pieces that are less than`$S`

in size (rather than throwing them away).`~`

is Raku’s string concatenation subroutine.`x`

is Raku’s string repetition operator. I couldn’t an`rpad`

method in Raku, so this is my workaround.`distance`

does not take a single list of arguments, it takes a variable amount of top-level arguments. To achieve that behavior, we use a slip (`|`

) to unpack the list we built.

## Final Thoughts

As I was writing this blog I realized it may have been better for me to left pad the binary strings in challenge two; `1001 != 100100`

but `1001 == 001001`

. Oh well, the question doesn’t talk about the “partial” case anyway!