by Arne Sommer

# Decoded Capital with Raku

[210] Published 13. November 2022.

This is my response to The Weekly Challenge #190.

## Challenge #190.1: Capital Detection

You are given a string with alphabetic characters only: `A..Z` and `a..z`.

Write a script to find out if the usage of Capital is appropriate if it satisfies at least one of the following rules:
1. Only first letter is capital and all others are small
2. Every letter is small
3. Every letter is capital
Example 1: ```Input: \$s = 'Perl' Output: 1 ``` Example 2: ```Input: \$s = 'TPF' Output: 1 ``` Example 3: ```Input: \$s = 'PyThon' Output: 0 ``` Example 4: ```Input: \$s = 'raku' Output: 1 ```
File: capital-detection ```#! /usr/bin/env raku subset alpha where * ~~ /^<[a..z A..Z]>+\$/; # [1a] unit sub MAIN (alpha \$s); # [1] say \$s ~~ /^<[a..z]>+\$/ || \$s ~~ /^<[A..Z]>+\$/ || \$s ~~ /^<[A..Z]><[a..z]>+\$/ ?? 1 !! 0; # [2] ```

[1] Ensure that the input consists of legal characters only, with the use of a custom type set up with `subset`.

See docs.raku.org/language/typesystem#index-entry-subset-subset for more information about `subset`.

[2] Print «1» if the input satisfies one (or more) of the input rules, and «0» if not.

Running it:

```\$ ./capital-detection Perl 1 \$ ./capital-detection TPF 1 \$ ./capital-detection PyThon 0 \$ ./capital-detection raku 1 ```

Looking good.

Illegal input:

```\$ ./capital-detection Perl5 Usage: ./capital-detection <s> ```

## Challenge #190.2: Decoded List

You are given an encoded string consisting of a sequence of numeric characters: 0..9, `\$s`.

Write a script to find the all valid different decodings in sorted order.

Encoding is simply done by mapping A,B,C,D,… to 1,2,3,4,… etc.

Example 1: ```Input: \$s = 11 Output: AA, K 11 can be decoded as (1 1) or (11) i.e. AA or K ``` Example 2: ```Input: \$s = 1115 Output: AAAE, AAO, AKE, KAE, KO Possible decoded data are: (1 1 1 5) => (AAAE) (1 1 15) => (AAO) (1 11 5) => (AKE) (11 1 5) => (KAE) (11 15) => (KO) ``` Example 3: ```Input: \$s = 127 Output: ABG, LG Possible decoded data are: (1 2 7) => (ABG) (12 7) => (LG) ```

Let us start with an illustration:

We start with the Todo digits (in blue). Then we pick either one or two of them (in green; in the Done list ), with the remainder still in Todo. This is a recursive task, so we go on until we end up with the result when the Todo list is empty (and everything is green). I have outlined the result in yellow.

Note that none of the examples include the digit 0 (zero). We'll have to look out for it just in case, as it will not translate into a letter (as "`1`" => "`A`"). We'll also have to look out for values > 26 (as "`26`" => "`Z`").

File: decoded-list ```#! /usr/bin/env raku # unit sub MAIN (\$s where \$s ~~ /^<[1..9]> <[0..9]>*\$/, :v(:\$verbose)); # [1] unit sub MAIN (\$s where \$s ~~ /^<[0..9]>*\$/, :v(:\$verbose)); # [1a] my \$seq := gather { recurse( (), \$s.comb); }; # [2] say \$seq.join(", "); # [3] sub recurse(@done is copy, @todo is copy) # [4] { unless @todo.elems # [5] { my \$string = @done.map({ (\$_ + 'A'.ord - 1).chr }).join; # [5a] say ":Take: @done[] -> \$string" if \$verbose; take \$string; # [5b] return; # [5c] } my \$next = @todo.shift; # [6] my @done2 = @done.clone; # [7] my @todo2 = @todo.clone; # [7a] return if \$next == 0; # [8] say ":Loop: @done2[] + \$next" if \$verbose; @done.push: \$next; # [9] recurse(@done, @todo); # [10] if @todo.elems # [11] { \$next ~= @todo2.shift; # [12] return if \$next > 26; # [13] say ":Loop: @done2[] + \$next" if \$verbose; @done2.push: \$next; # [14] recurse(@done2, @todo2); # [15] } } ```

[1] Should we allow a leading zero in the input? I have chosen to do so, but we catch them later on (in [9]).

[2] Using `gather`/`take` to set up the sequence is ideal here, as we return values (with `take`) twice (potentially) in each iteration.

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

[3] Print the result.

[4] The recursive procedure. The first argument is the part of the input that we have parsed (so far), and the second is the remainder. Note the use of `is copy` so that we get writeable copies.

[5] No remainder? If so convert the numbers to characters and return (with `take`) them as a single string. The `return` is there to stop further code from beeing run, and finish the current recursive call.

[6] If we come here, we have more digits to do. Get the first one.

[7] Take a copy of the input (with `clone`), so that the second part (starting at [11]) starts with the same values as first part (here).

See docs.raku.org/routine/clone for more information about the `clone` method.

[8] The digit «0» (zero) by itself is illegal, so we can abort this recursive call. (This will also stop things like «01», which is fine.)

[9] Add the new (single digit) number to the done list.

[10] Recursively go on.

[11] Any more elements? (So that we can do two digits.)

[12] Get the next digit, and add it to the current one.

[13] Numbers higher than 25 do not work out.

[14] Add the new (two-digit) number to the done list.

[15] Recursively go on.

Running it:

```\$ ./decoded-list 11 AA, K \$ ./decoded-list 1115 AAAE, AAO, AKE, KAE, KO \$ ./decoded-list 127 ABG, LG ```

Looking good.

With verbose mode:

```\$ ./decoded-list -v 11 :Loop: + 1 :Loop: 1 + 1 :Take: 1 1 -> AA :Loop: + 11 :Take: 11 -> K AA, K \$ ./decoded-list -v 1115 :Loop: + 1 :Loop: 1 + 1 :Loop: 1 1 + 1 :Loop: 1 1 1 + 5 :Take: 1 1 1 5 -> AAAE :Loop: 1 1 + 15 :Take: 1 1 15 -> AAO :Loop: 1 + 11 :Loop: 1 11 + 5 :Take: 1 11 5 -> AKE :Loop: + 11 :Loop: 11 + 1 :Loop: 11 1 + 5 :Take: 11 1 5 -> KAE :Loop: 11 + 15 :Take: 11 15 -> KO AAAE, AAO, AKE, KAE, KO \$ ./decoded-list -v 127 :Loop: + 1 :Loop: 1 + 2 :Loop: 1 2 + 7 :Take: 1 2 7 -> ABG :Loop: + 12 :Loop: 12 + 7 :Take: 12 7 -> LG ABG, LG ```

And that's it.