This is my response to The Weekly Challenge #282.
$int
, having 3 or more digits
.
Good Integer
in the given integer or
-1
if none found.
Input: $int = 12344456
Output: "444"
Example 2:
Input: $int = 1233334
Output: -1
Example 3:
Input: $int = 10020003
Output: "000"
Off we go, without careful reading of the challenge...
File: good-integer-regexp
#! /usr/bin/env raku
unit sub MAIN (UInt $int where $int > 99); # [1]
say $int ~~ /(.) {} :my $c=$0; <?after $c ** 3> / # [2]
?? $0.Str x 3 # [2a]
!! -1; # [2b]
[1] An unsigned integer, with a value of 100 or above.
[2] This «three identical characters in a row» regexp
is reused (slightly modified) from my recent
The Nine Billion Names of God with Raku
article. We capture only one of them (the characters, with the parens),
so have to print three of that one with the string repetition operator
x
). Note the stringification courtesy of Str
, as working
with a match object does not really work out here [2a]. Or -1
on failure.
See docs.raku.org/routine/x for more information about x
.
Running it:
$ ./good-integer-regexp 12344456
444
$ ./good-integer-regexp 1233334
333
$ ./good-integer-regexp 10020003
000
Oops. The second one is wrong. The regexp matches three or more, and not exactly three as prescribed by the challenge.
A second try, and a considerable longer program to boot.
File: good-integer
#! /usr/bin/env raku
unit sub MAIN (UInt $int where $int > 99, :v(:$verbose));
my $matching := gather # [1]
{
my @digits = $int.comb; # [2]
my $current = @digits.shift; # [3]
my $count = 1; # [4]
while @digits # [5]
{
my $next = @digits.shift; # [6]
if $current eq $next # [7]
{
$count++; # [7a]
}
else # [8]
{
take $current x $count; # [8a]
$current = $next; # [8b]
$count = 1; # [8c]
}
}
take $current if $current; # [9]
}
for $matching -> $candidate # [10]
{
say ":Considering candidate '$candidate'" if $verbose;
if $candidate.chars == 3 # [11]
{
say $candidate; # [11a]
exit; # [11b]
}
}
say -1; # [12]
[1] Using gather
(here) and
take
(in [8a] and [9]) to set up a partial string feed
works pretty well.
[2] Turn the input into an array of individual digits.
[3] Get the first digit.
[4] The size of the partial string starts out at 1.
[5] As long as we have additional digits to process.
[6] Get the next one.
[7] Identical to the previous one? If so, count it.
[8] If not, return (with take
) the old value [8a],
save the new value [8b] and reset the counter [8c].
[9] Return the last value on loop termination. The test is actually not really needed.
[10] Iterate over the partial strings.
[11] Does it have the required length? If so, print it [11a] and exit [11b].
[12] We have failed to find a match if we reach this part. Say so.
Running it:
$ ./good-integer 12344456
444
$ ./good-integer 1233334
-1
$ ./good-integer 10020003
000
Looking good.
With verbose mode:
$ ./good-integer -v 12344456
:Considering candidate '1'
:Considering candidate '2'
:Considering candidate '3'
:Considering candidate '444'
444
$ ./good-integer -v 1233334
:Considering candidate '1'
:Considering candidate '2'
:Considering candidate '3333'
:Considering candidate '4'
-1
$ ./good-integer -v 10020003
:Considering candidate '1'
:Considering candidate '00'
:Considering candidate '2'
:Considering candidate '000'
000
One can argue that «000» is not an integer. It is easy to amend the program to support that notion, but I will refrain from doing so.
$str
, as typed by user.
shift
and caps lock
keys won’t
be counted.
Input: $str = 'pPeERrLl'
Ouput: 3
p -> P : 0 key change
P -> e : 1 key change
e -> E : 0 key change
E -> R : 1 key change
R -> r : 0 key change
r -> L : 1 key change
L -> l : 0 key change
Example 2:
Input: $str = 'rRr'
Ouput: 0
Example 3:
Input: $str = 'GoO'
Ouput: 1
File: changing-keys
#! /usr/bin/env raku
unit sub MAIN ($str where $str ~~ /^<[a..z A..Z]>+$/, # [1]
:v(:$verbose));
my @letters = $str.comb; # [2]
my $first = @letters.shift;
my $count = 0;
while @letters
{
my $second = @letters.shift;
my $change = $first.lc ne $second.lc; # [3]
say ": $first -> $second : { +$change } key change" if $verbose;
$count++ if $change; # [4]
$first = $second; # [5]
}
say $count; # [6]
[1] Ensure english letters only, lower- and uppercase.
[2] This and the loop is almost a copy of the one in the first half of the challenge.
[3] Compare the lowercase versions (lc
) of the
strings.
See docs.raku.org/routine/lc for more information about lc
.
[4] Increase the counter if the letters differ.
[5] Set up for the next iteration.
[6] Print the result.
Running it:
$ ./changing-keys pPeERrLl
3
$ ./changing-keys rRr
0
$ ./changing-keys GoO
1
Looking good.
With verbose mode:
$ ./changing-keys -v pPeERrLl
: p -> P : 0 key change
: P -> e : 1 key change
: e -> E : 0 key change
: E -> R : 1 key change
: R -> r : 0 key change
: r -> L : 1 key change
: L -> l : 0 key change
3
$ ./changing-keys -v rRr
: r -> R : 0 key change
: R -> r : 0 key change
0
$ ./changing-keys -v GoO
: G -> o : 1 key change
: o -> O : 0 key change
1
And that's it.