### Perl Weekly Challenge: Week 254

#### Challenge 1:

Three Power

You are given a positive integer, `\$n`.

Write a script to return true if the given integer is a power of three otherwise return false.

##### Example 1
``````Input: \$n = 27
Output: true

27 = 3 ^ 3
``````
##### Example 2
``````Input: \$n = 0
Output: true

0 = 0 ^ 3
``````
##### Example 3
``````Input: \$n = 6
Output: false
``````

The condition in the spec will be satisfied if the cube root of `\$n` is an integer. Which seems very easy to do.

``````say @*ARGS[0] ** (1/3) %% 1
``````

Raku has a `.sqrt()` method for square roots but not one specifically for cube roots. But raising a number to the power of one third is the same thing and we can do that with the exponention or `**` operator. `%%` is the integer modulus operator. `%% 1` will be true if the cube root is exactly divisible by one or in other words, an integer.

This works for the examples but there is a catch. If we try `\$n = 64` for example, we should get `True` because 64 is 4 to the power of 3 but we actually get `False`. Why? It is due to the way Raku (and it should be noted many other languages) represent numbers internally. `64 ** (1/3)` actually comes out as `3.9999999999999996`—not an integer. A way around this to not have our calculations be so precise. With `.round()`, the cube root is rounded off to the nearest thousandth.

``````say (@*ARGS[0] ** (1/3)).round(0.001) %% 1
``````

(Full code on Github.)

This will still fail for really big values of `\$n` I think but it works for a much larger range of values than before.

Perl has the same problem and we can use the same answer but there are added complications. One, we do not have `.round()` so we have to use a module. Math::Round has a function—and this trips me up every time—not `round()` but `nearest()` which does what we want. Two, there is no simple equivalent to `%% 1`. Another way to determine if a value is an integer is to compare it to the output of `sprintf("%d")`. If it is equal, the number is an integer.

``````\$r = nearest(0.001, shift() **(1/3)); say \$r == sprintf("%d", \$r) ? "true" : "false"
``````

(Full code on Github.)

#### Challenge 2:

Reverse Vowels

You are given a string, `\$s`.

Write a script to reverse all the vowels (`a`, `e`, `i`, `o`, `u`) in the given string.

##### Example 1
``````Input: \$s = "Raku"
Output: "Ruka"
``````
##### Example 2
``````Input: \$s = "Perl"
Output: "Perl"
``````
##### Example 3
``````Input: \$s = "Julia"
Output: "Jaliu"
``````
##### Example 4
``````Input: \$s = "Uiua"
Output: "Auiu"
``````

My initial idea for a solution involved a grand scheme of creating hashes of string positions and reordering the keys etc. but I thought about it and actually it is a lot more simple.

First we split the input string into a list of individual characters.

``````my @chars = \$s.comb;
``````

We also create another list which will be used as a LIFO (Last In First Out) stack.

``````my @vowels;
``````

We traverse the list of characterss and every time we find one which is a vowel, we add it to `@vowels`.

``````for @chars.keys -> \$c {
if @chars[\$c] ∈ <a A e E i I o O u U> {
@vowels.push(@chars[\$c]);
}
}
``````

Then we traverse `@chars` again. This time, when we see a vowel, we replace it with one `.pop()`ed off the end of `@vowels`.

``````for @chars.keys -> \$c {
if @chars[\$c] ∈ <a A e E i I o O u U> {
@chars[\$c] = @vowels.pop;
}
}
``````

Finally we join the characters back together into a string and print it out.

``````@chars.join.say;
``````

This mostly works except for i.e. example 4. The output is `auiU` but what we want is `Auiu`.

Luckily allowing for capitalization is an easy fix to our code. All we need to do is split up the second loop so...

``````for @chars.keys -> \$c {
``````

...if we come across an upper-case vowel...

``````    if @chars[\$c] ∈ <A E I O U> {
``````

...its' replacement is made upper-case with `.uc()` regardless of what it may have been stored as intitially.

``````        @chars[\$c] = @vowels.pop.uc;
}
``````

Or if we come across a lower-case vowel...

``````    elsif @chars[\$c] ∈ <a e i o u> {
``````

...its' replacement is made lower-case with `.lc()`.

``````        @chars[\$c] = @vowels.pop.lc;
}
}
``````

(Full code on Github.)

This is the Perl version, a straightforward translation from Raku except because we don't have a member-of operator like `∈` in Raku, we use a regular expression match instead.

``````my @chars = split //, \$s;
my @vowels;

for my \$c (keys @chars) {
if (\$chars[\$c] =~ /[aAeEiIoOuU]/) {
push @vowels, \$chars[\$c];
}
}

for my \$c (keys @chars) {
if (\$chars[\$c] =~ /[AEIOU]/) {
\$chars[\$c] = uc pop @vowels;
}
elsif (\$chars[\$c] =~ /[aeiou]/) {
\$chars[\$c] = lc pop @vowels;
}
}

say join q{}, @chars;
``````

(Full code on Github.)