Prefixed Alien
with Raku

by Arne Sommer

Prefixed Alien with Raku

[326] Published 26. January 2025.

This is my response to The Weekly Challenge #305.

Challenge #305.1: Binary Prefix

You are given a binary array.

Write a script to return an array of booleans where the partial binary number up to that point is prime.

Example 1:
Input: @binary = (1, 0, 1)
Output: (false, true, true)

Sub-arrays (base-10):
(1): 1 - not prime
(1, 0): 2 - prime
(1, 0, 1): 5 - prime
Example 2:
Input: @binary = (1, 1, 0)
Output: (false, true, false)

Sub-arrays (base-10):
(1): 1 - not prime
(1, 1): 3 - prime
(1, 1, 0): 6 - not prime
Example 3:
Input: @binary = (1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0,
                  0, 0, 1)
Output: (false, true, true, false, false, true, false, false, false,
         false, false, false, false, false, false, false, false, false,
         false, true)
File: binary-prefix
#! /usr/bin/env raku

unit sub MAIN (*@binary where @binary.elems > 0 && all(@binary) eq any(0,1),
               :v(:$verbose));         # [1]

my $current = "";                      # [2]
my @result;                            # [3]

for @binary -> $digit                  # [4]
{
  $current ~= $digit;                  # [5]

  my $int   = $current.parse-base(2);  # [6]
  my $prime = $int.is-prime;           # [7]

  say ": Binary:$current Int:$int { $prime ?? "prime" !! "not prime" }"
    if $verbose;

  @result.push: $prime;                # [8]
}

say "({ @result.join(", ")  })";       # [9]

[1] At least one value, and they must be either 0 or 1.

[2] We are going to build the partial binary number here.

[3] The resulting array of Boolean values.

[4] Iterate over each binary digit.

[5] Add the digit to the partial binary number.

[6] Convert the binary string to a (decimal) number with parse-base.

See docs.raku.org/routine/parse-base for more information about parse-base.

[7] Is the current number a prime?

See docs.raku.org/routine/is-prime for more information about is-prime.

[8] Add the Boolean value to the result.

[9] Pretty print the result.

Running it:

$ ./binary-prefix 1 0 1
(False, True, True)

$ ./binary-prefix 1 1 0
(False, True, False)

$ ./binary-prefix -v 1 1 1 1 0 1 0 0 0 0 1 0 1 0 0 1 0 0 0 1
(False, True, True, False, False, True, False, False, False, False, False, \
 False, False, False, False, False, False, False, False, True)

Looking good.

With verbose mode:

$ ./binary-prefix -v 1 0 1
: Binary:1 Int:1 not prime
: Binary:10 Int:2 prime
: Binary:101 Int:5 prime
(False, True, True)

$ ./binary-prefix -v 1 1 0
: Binary:1 Int:1 not prime
: Binary:11 Int:3 prime
: Binary:110 Int:6 not prime
(False, True, False)

$ ./binary-prefix -v 1 1 1 1 0 1 0 0 0 0 1 0 1 0 0 1 0 0 0 1
: Binary:1 Int:1 not prime
: Binary:11 Int:3 prime
: Binary:111 Int:7 prime
: Binary:1111 Int:15 not prime
: Binary:11110 Int:30 not prime
: Binary:111101 Int:61 prime
: Binary:1111010 Int:122 not prime
: Binary:11110100 Int:244 not prime
: Binary:111101000 Int:488 not prime
: Binary:1111010000 Int:976 not prime
: Binary:11110100001 Int:1953 not prime
: Binary:111101000010 Int:3906 not prime
: Binary:1111010000101 Int:7813 not prime
: Binary:11110100001010 Int:15626 not prime
: Binary:111101000010100 Int:31252 not prime
: Binary:1111010000101001 Int:62505 not prime
: Binary:11110100001010010 Int:125010 not prime
: Binary:111101000010100100 Int:250020 not prime
: Binary:1111010000101001000 Int:500040 not prime
: Binary:11110100001010010001 Int:1000081 prime
(False, True, True, False, False, True, False, False, False, False, \
 False, False, False, False, False, False, False, False, False, True)

Challenge #305.2: Alien Dictionary

You are given a list of words and alien dictionary character order.

Write a script to sort lexicographically the given list of words based on the alien dictionary characters.

Example 1:
Input: @words = ("perl", "python", "raku")
       @alien = qw/h l a b y d e f g i r k m n o p q j s t u v w x c z/
Output: ("raku", "python", "perl")
Example 2:
Input: @words = ("the", "weekly", "challenge")
       @alien = qw/c o r l d a b t e f g h i j k m n p q s w u v x y z/
Output: ("challenge", "the", "weekly")
File: alien-dictionary
#! /usr/bin/env raku

unit sub MAIN (*@words where @words.elems > 1
                 && all(@words) ~~ /^<[a..z]>+$/,           # [1]
               :a(:$alien) where $alien.comb.sort.join eq
                  "abcdefghijklmnopqrstuvwxyz",             # [2]
               :v(:$verbose));

my @alien = $alien.comb;                                    # [3]
my @alpha = 'a' .. 'z';                                     # [4]
my %alien;                                                  # [5]
my %words;                                                  # [6]

for @alpha -> $char                                         # [7]
{
  %alien{$char} = @alien.shift;                             # [7a]
  say ": char $char -> %alien{$char}" if $verbose;
}

for @words -> $word                                         # [8]
{
  %words{$word} = alienate($word);                          # [8a]
  say ": word $word -> %words{$word}" if $verbose;
}

sub alien ($char)                                           # [9]
{
  return %alien{$char};                                     # [9a]
}

sub alienate ($string)                                      # [10]
{
  return $string.comb>>.&alien.join;                        # [10a]
}

my @sorted = @words.sort({ %words{$^a} cmp %words{$^b} });  # [11]

say "({ @sorted.map('"' ~ * ~ '"').join(", ") })";          # [12]

[1] At least two words, using one or more of the letters a..z only.

[2] The alien alphabet as a string (and a named argument). We ensure that it is complete (i.e. has all the letters a..z) by turning the string into a list of characters (with comb), sorting that list (with sort), joining the result together into a string again (with join), and finally ensuring that we get the whole alphabet.

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

[3] The alien letters as a list.

[4] The normal alphabet.

[5] The mapping between alien and normal letters will end up here.

[6] The mapping between alien and normal words will end up here.

[7] Iterate over the normal alphabet, and assign the corresponding alien letter [7a].

[8] Iterate over the normal words, and assign the corresponding alien word [8a] using the «alienate» procedure.

[9] Procedure returning the alien twin of the normal letter.

[10] Procedure returning the alien version of the normal word. Note the use of >>. to apply the method on each element in the array, and the use of the .& prefix to call a procedure as a method.

See docs.raku.org/language/operators#methodop_.& for more information about the special procedure invocation syntax .&.

[11] Sort the words, based on the alien versions.

[12] Pretty print the result.

Running it:

$ ./alien-dictionary -a=hlabydefgirkmnopqjstuvwxcz perl python raku
("raku", "python", "perl")

$ ./alien-dictionary -a=corldabtefghijkmnpqswuvxyz the weekly challenge
("challenge", "the", "weekly")

Looking good.

With verbose mode:

$ ./alien-dictionary -v -a=hlabydefgirkmnopqjstuvwxcz perl python raku
: char a -> h
: char b -> l
: char c -> a
: char d -> b
: char e -> y
: char f -> d
: char g -> e
: char h -> f
: char i -> g
: char j -> i
: char k -> r
: char l -> k
: char m -> m
: char n -> n
: char o -> o
: char p -> p
: char q -> q
: char r -> j
: char s -> s
: char t -> t
: char u -> u
: char v -> v
: char w -> w
: char x -> x
: char y -> c
: char z -> z
: word perl -> pyjk
: word python -> pctfon
: word raku -> jhru
("raku", "python", "perl")

$ ./alien-dictionary -v -a=corldabtefghijkmnpqswuvxyz the weekly challenge
: char a -> c
: char b -> o
: char c -> r
: char d -> l
: char e -> d
: char f -> a
: char g -> b
: char h -> t
: char i -> e
: char j -> f
: char k -> g
: char l -> h
: char m -> i
: char n -> j
: char o -> k
: char p -> m
: char q -> n
: char r -> p
: char s -> q
: char t -> s
: char u -> w
: char v -> u
: char w -> v
: char x -> x
: char y -> y
: char z -> z
: word the -> std
: word weekly -> vddghy
: word challenge -> rtchhdjbd
("challenge", "the", "weekly")

And that's it.