Advent Calendar - December 4, 2024

Wednesday, Dec 4, 2024| Tags: Raku

Advent Calendar 2024

|   Day 3   |   Day 4   |   Day 5   |


The gift is presented by Arne Sommer. Today he is talking about his solution to The Weekly Challenge - 254. This is re-produced for Advent Calendar 2024 from the original post.



Reverse Power



Challenge #254.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.

File: three-power


#! /usr/bin/env raku

unit sub MAIN ($n is copy where $n ~~ UInt, :v($verbose));  # [1]

while $n > 3                                                # [2]
{
  print ": $n / 3 -> " if $verbose;
  $n /= 3;                                                  # [3]
  say $n if $verbose;

  last if $n != $n.Int;                                     # [4]
}

say $n == 0|3 ?? 'true' !! 'false';                         # [5]

[1] Note the is copy so that we can change the value later on (in [3]). Also note that we check the value against the Unsigned Int type UInt instead of enforcing the type on the variable, as the value in $n can become a non-integer (in [3]).

[2] As long as we have more 3s to extract (by factoring them out).

[3] Divide the value by three, and assign the value back. This may result in a non-integer.

[4] This check will bail out of the loop if we got a non-integer value. This will spare us for a lot of loop iterations in the worst case, at the cost of adding code (and time). Feel free to comment it out.

[5] Are we left with 3 (or the special case of 0, for the input value 0), if so we have succeeded and print «true». If not, print «false».

Running it:


$ ./three-power 27
true

$ ./three-power 0
true

$ ./three-power 6
false

Looking good.

With verbose mode:


$ ./three-power -v 27
: 27 / 3 -> 9
: 9 / 3 -> 3
true

$ ./three-power -v 0
true

$ ./three-power -v 6
: 6 / 3 -> 2
false

Let us try an arbitrary largish number. First with the check in [4] intact, and then without it:


$ ./three-power -v 999
: 999 / 3 -> 333
: 333 / 3 -> 111
: 111 / 3 -> 37
: 37 / 3 -> 12.333333
false

$ ./three-power -v 999
: 999 / 3 -> 333
: 333 / 3 -> 111
: 111 / 3 -> 37
: 37 / 3 -> 12.333333
: 12.333333 / 3 -> 4.111111
: 4.111111 / 3 -> 1.37037
false

Why restrict ourselves with the power of 3?

File: multi-power


#! /usr/bin/env raku

unit sub MAIN ($n is copy where $n ~~ UInt,
               UInt :p(:$power) where $power > 0 = 3,
               :v(:$verbose));

while $n > $power
{
  print ": $n / $power -> " if $verbose;
  $n /= $power;
  say $n if $verbose;
  last if $n != $n.Int;
}

say $n == 0|$power ?? 'true' !! 'false';

Specify the power as e.g. -p=2 or -power=2, if the default 3 does not suit you.


$ ./multi-power -power=2 512
true

$ ./multi-power -power=2 -v 512
: 512 / 2 -> 256
: 256 / 2 -> 128
: 128 / 2 -> 64
: 64 / 2 -> 32
: 32 / 2 -> 16
: 16 / 2 -> 8
: 8 / 2 -> 4
: 4 / 2 -> 2
true

Challenge #254.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.

File: reverse-vowels


#! /usr/bin/env raku

unit sub MAIN ($s, :v(:$verbose));                   # [1]

my @letters = $s.comb;                               # [2]
my @vowels  = @letters.grep: * ~~ /<[aeiouAEIOU]>/;  # [3]
my @reverse = @vowels.reverse;                       # [4]

if $verbose
{
  say ":Letters: { @letters.join(",") }";
  say ":Vowels: { @vowels.join(",") }";
  say ":Reverse: { @reverse.join(",") }";
}

my @output = @letters.map({ m:i/<[aeiou]>/ ?? @reverse.shift !! $_ }); # [5]

say @output.join;                                                      # [6]

[1] A string of arbitrary size (and content).

[2] Get the individual letters.

[3] Get the vowels. Note the «ignore case» :i modifier, instead of an explicit list of uppercase vowels in the regex.

[4] Reverse the list of vowels.

[5] Map each letter in the input (the list) to either itself (non-vowel) or the first remaing (unused) reversed list of vowels.

[6] Print the result as a single string.

Running it:


$ ./reverse-vowels Raku
Ruka

$ ./reverse-vowels Perl
Perl

$ ./reverse-vowels Julia
Jaliu

$ ./reverse-vowels Uiua
auiU

The last one is not as specified in the challenge, but let us have a go at verbose mode before looking into that.


$ ./reverse-vowels -v Raku
:Letters: R,a,k,u
:Vowels: a,u
:Reverse: u,a
Ruka

$ ./reverse-vowels -v Perl
:Letters: P,e,r,l
:Vowels: e
:Reverse: e
Perl

$ ./reverse-vowels -v Julia
:Letters: J,u,l,i,a
:Vowels: u,i,a
:Reverse: a,i,u
Jaliu

$ ./reverse-vowels -v Uiua
:Letters: U,i,u,a
:Vowels: U,i,u,a
:Reverse: a,u,i,U
auiU

Ok. Let us try a palindrome:


$ ./reverse-vowels "never odd or even"
never odd or even

$ ./reverse-vowels -v "never odd or even"
:Letters: n,e,v,e,r, ,o,d,d, ,o,r, ,e,v,e,n
:Vowels: e,e,o,o,e,e
:Reverse: e,e,o,o,e,e
never odd or even

$ ./reverse-vowels "NEVER ODD or even"
NeVeR oDD Or EvEn

$ ./reverse-vowels -v "NEVER ODD or even"
:Letters: N,E,V,E,R, ,O,D,D, ,o,r, ,e,v,e,n
:Vowels: E,E,O,o,e,e
:Reverse: e,e,o,O,E,E
NeVeR oDD Or EvEn

Then we can have a go at the case of the wrong case, so to speak…

File: reverse-vowels-case



#! /usr/bin/env raku

unit sub MAIN ($s, :v(:$verbose));

my @letters = $s.comb;
my @vowels  = @letters.grep: * ~~ /<[aeiouAEIOU]>/;
my @reverse = @vowels.reverse;

if $verbose
{
  say ":Letters: { @letters.join(",") }";
  say ":Vowels: { @vowels.join(",") }";
  say ":Reverse: { @reverse.join(",") }";
}

my @output = @letters.map({
           if    /<[aeiou]>/ { @reverse.shift.lc; } # [1]
           elsif /<[AEIOU]>/ { @reverse.shift.uc; } # [2]
           else             { $_;                }
             });

say @output.join;

[1] If the original vowel is lowercase, apply lc to force the replacement vowel to lowercase as well.

See docs.raku.org/routine/lc for more information about lc.

[2] If the original vowel is uppercase, apply uc to force the replacement vowel to uppercase as well.

See docs.raku.org/routine/uc for more information about uc.

And magically nothing seems to happen…


$ ./reverse-vowels-case "NEVER ODD or even"
NEVER ODD or even

Verbose mode will tell you otherwise:


$ ./reverse-vowels-case -v "NEVER ODD or even"
:Letters: N,E,V,E,R, ,O,D,D, ,o,r, ,e,v,e,n
:Vowels: E,E,O,o,e,e
:Reverse: e,e,o,O,E,E
NEVER ODD or even

Another one:


$ ./reverse-vowels-case -v "THIS IS not a test"
:Letters: T,H,I,S, ,I,S, ,n,o,t, ,a, ,t,e,s,t
:Vowels: I,I,o,a,e
:Reverse: e,a,o,I,I
THES AS not i tist

Ind that’s at. (Pun intended)



If you have any suggestion then please do share with us perlweeklychallenge@yahoo.com.

|   Advent Calendar 2024   |

SO WHAT DO YOU THINK ?

If you have any suggestions or ideas then please do share with us.

Contact with me