This is my response to The Weekly Challenge #190.
A..Z
and
a..z
.
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
#! /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>
$s
.
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
").
#! /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.