This is my response to The Weekly Challenge #312.
a
to z
arranged in a circle.
1 sec
. You can move pointer one character
clockwise or anti-clockwise.
Input: $str = "abc"
Output: 5
The pointer is at 'a' initially.
1 sec - type the letter 'a'
1 sec - move pointer clockwise to 'b'
1 sec - type the letter 'b'
1 sec - move pointer clockwise to 'c'
1 sec - type the letter 'c'
Example 2:
Input: $str = "bza"
Output: 7
The pointer is at 'a' initially.
1 sec - move pointer clockwise to 'b'
1 sec - type the letter 'b'
1 sec - move pointer anti-clockwise to 'a'
1 sec - move pointer anti-clockwise to 'z'
1 sec - type the letter 'z'
1 sec - move pointer clockwise to 'a'
1 sec - type the letter 'a'
Example 3:
Input: $str = "zjpc"
Output: 34
We can deduce from the examples that the moving of the pointer
one step in either direction also takes 1 sec
.
#! /usr/bin/env raku
unit sub MAIN (Str $str where $str ~~ /^<[a..z]>+$/, :v(:$verbose)); # [1]
my @chars = $str.comb; # [2]
my $prev = 'a'; # [3]
my $time = 0; # [4]
while @chars.elems # [5]
{
my $current = @chars.shift; # [6]
my $diff = abs( ord($prev) - ord($current) ); # [7]
if $diff > 13 # [8]
{
$diff = 26 - $diff; # [9]
say ": $diff sec - Move pointer anti-clockwise from '$prev' \
to '$current'." if $verbose;
}
elsif $diff && $verbose
{
say ": $diff sec - Move pointer clocwise from '$prev' to '$current'.";
}
say ": 1 sec - Type the letter '$current'." if $verbose;
$time += ( $diff + 1 ); # [10]
$prev = $current; # [11]
}
say $time; # [12]
[1] Ensure a string of lowercase lettes (a-z) only, with at least one
(the +
).
[2] Split the string into an array of characters with comb
.
See docs.raku.org/routine/comb for more information about comb
.
[3] The starting position of the pointer.
[4] The time usage, initially zero.
[5] As long as we have more characters to print,
[6] Get the next character.
[7] Get the number of steps, without the sign (if any). We do
this by getting the codepoint (or ascii position) of the two letters
(with ord
), and subtracting those values.
[8] If the difference is more than 13, we will move anti-clockwise.
[9] The number of letters on the wheel is 26, so subtracting the difference from this value gives the number of steps in the anti-clockwise direction.
[10] Add the number of steps (1 second each) and the printing (also 1 second).
[11] Prepare for the next iteration.
[12] Print the result.
Running it:
$ ./minimum-time abc
5
$ ./minimum-time bza
7
$ ./minimum-time zjpc
34
Looking good.
With verbose mode:
$ ./minimum-time -v abc
: 1 sec - Type the letter 'a'.
: 1 sec - Move pointer clocwise from 'a' to 'b'.
: 1 sec - Type the letter 'b'.
: 1 sec - Move pointer clocwise from 'b' to 'c'.
: 1 sec - Type the letter 'c'.
5
$ ./minimum-time -v bza
: 1 sec - Move pointer clocwise from 'a' to 'b'.
: 1 sec - Type the letter 'b'.
: 2 sec - Move pointer anti-clockwise from 'b' to 'z'.
: 1 sec - Type the letter 'z'.
: 1 sec - Move pointer anti-clockwise from 'z' to 'a'.
: 1 sec - Type the letter 'a'.
7
$ ./minimum-time -v zjpc
: 1 sec - Move pointer anti-clockwise from 'a' to 'z'.
: 1 sec - Type the letter 'z'.
: 10 sec - Move pointer anti-clockwise from 'z' to 'j'.
: 1 sec - Type the letter 'j'.
: 6 sec - Move pointer clocwise from 'j' to 'p'.
: 1 sec - Type the letter 'p'.
: 13 sec - Move pointer clocwise from 'p' to 'c'.
: 1 sec - Type the letter 'c'.
34
$n
balls of mixed colors: red, blue or green.
They are all distributed in 10 boxes labelled 0-9.
Input: $str = "G0B1R2R0B0"
Output: 1
The given string describes there are 5 balls as below:
Box 0: Green(G0), Red(R0), Blue(B0) => 3 balls
Box 1: Blue(B1) => 1 ball
Box 2: Red(R2) => 1 ball
Example 2:
Input: $str = "G1R3R6B3G6B1B6R1G3"
Output: 3
The given string describes there are 9 balls as below:
Box 1: Red(R1), Blue(B1), Green(G1) => 3 balls
Box 3: Red(R3), Blue(B3), Green(G3) => 3 balls
Box 6: Red(R6), Blue(B6), Green(G6) => 3 balls
Example 3:
Input: $str = "B3B2G1B3"
Output: 0
Box 1: Green(G1) => 1 ball
Box 2: Blue(B2) => 1 ball
Box 3: Blue(B3) => 2 balls
#! /usr/bin/env raku
subset RGB where /^(<[RGB]><[0..9]>)+$/; # [1]
unit sub MAIN (RGB $str is copy, :v(:$verbose)); # [1a]
my %boxes; # [2]
while $str.chars # [3]
{
my $ball = $str.substr(0,2); # [4]
my $colour = $str.substr(0,1); # [4a]
my $box = $str.substr(1,1); # [4b]
$str = $str.substr(2); # [5]
%boxes{$box}{$colour}++; # [6]
say ":Ball $ball (Colour $colour, Box $box)" if $verbose;
}
say %boxes>>.elems.grep( *.value == 3 ).elems; # [7]
[1] A custom type for the two-character box
specifications (with subset
), with at least one box. And
apply it to the input [1a].
See docs.raku.org/routine/subset for more information about subset
.
[2] We will build up the boxes here, as a two dimentional hash. The first level is the box id (number 0-9) and the second is the colour identifier.
[3] As long as we have more balls to process.
[4] Get the ball, the first two characters, with
substr
. This one is used by verbose mode only, so can be skipped.
Get the colour [4a] and the box number [4b].
See docs.raku.org/routine/substr for more information about substr
.
[5] Get rid of the first two characters, i.e. the ball that we have just processed.
[6] Add the new ball to the hash.
The %boxes
hash looks like this, for the first example:
[7] For each box (%boxes>>
) use elems
to get the number of
colours they contain. (Non-existing colours will not be present in the hash.)
Then use grep
to only keep the boxes with three elements (different
colours). And finally we count them with elems
and print the result.
There is more than one way to skin this cat (or hash). Here is a very convoluted one:
%boxes.map({ + %boxes{ .key }.elems == 3}).sum.say;
Running it:
$ ./balls-and-boxes G0B1R2R0B0
1
$ ./balls-and-boxes G1R3R6B3G6B1B6R1G3
3
$ ./balls-and-boxes B3B2G1B3
0
Looking good.
With verbose mode:
$ ./balls-and-boxes -v G0B1R2R0B0
:Ball G0 (Colour G, Box 0)
:Ball B1 (Colour B, Box 1)
:Ball R2 (Colour R, Box 2)
:Ball R0 (Colour R, Box 0)
:Ball B0 (Colour B, Box 0)
1
$ ./balls-and-boxes -v G1R3R6B3G6B1B6R1G3
:Ball G1 (Colour G, Box 1)
:Ball R3 (Colour R, Box 3)
:Ball R6 (Colour R, Box 6)
:Ball B3 (Colour B, Box 3)
:Ball G6 (Colour G, Box 6)
:Ball B1 (Colour B, Box 1)
:Ball B6 (Colour B, Box 6)
:Ball R1 (Colour R, Box 1)
:Ball G3 (Colour G, Box 3)
3
$ ./balls-and-boxes -v B3B2G1B3
:Ball B3 (Colour B, Box 3)
:Ball B2 (Colour B, Box 2)
:Ball G1 (Colour G, Box 1)
:Ball B3 (Colour B, Box 3)
0
And that's it.