Complex Squares
with Raku

by Arne Sommer

Complex Squares with Raku

[420] Published 18. October 2026.

This is my response to The Weekly Challenge #395.

#395.1 Complex Number You are given two complex numbers as string.

Write a script to return the multiplication of the given complex numbers.

Using the formula: (a + bi) x (c + di) = (ac - bd) + (ad + bc)i

Example 1:
Input: $num1 = "1+1i", $num2 = "1+1i"
Output: "0+2i"
Example 2:
Input: $num1 = "1+(-1)i", $num2 = "1+(-1)i"
Output: "0+(-2)i"
Example 3:
Input: $num1 = "0+3i", $num2 = "0+4i"
Output: "-12+0i"
Example 4:
Input: $num1 = "3+4i", $num2 = "3+(-4)i"
Output: "25+0i"
Example 5:
Input: $num1 = "50+(-20)i", $num2 = "-10+30i"
Output: "100+1700i"

Raku has a built in Complex data type (or class), so we can use that out of the box

See docs.raku.org/type/complex for more information about the complex type.

File: complex-number
#! /usr/bin/env raku

subset ComplexStr where * ~~ /^ \-? \d+ \+ \(? \-? \d+ \)? i $/;

unit sub MAIN (ComplexStr $num1, ComplexStr $num2,
               :v(:$verbose));

sub gen-complex(Str $s)
{
  $s ~~ /^ (\-?\d+) \+ \(? (\-?\d+) \)? i $/;
  Complex.new($0.Int, $1.Int);
}

my $complex1 = gen-complex($num1);
my $complex2 = gen-complex($num2);
my $product  = $complex1 * $complex2;

if $verbose
{
  say ": Real: { $complex1.re } * { $complex2.re } - \
    { $complex1.im } * { $complex2.im } = { $product.re }";

  say ": Imag: { $complex1.re } * { $complex2.im } + \
    { $complex1.im } * { $complex2.re } = { $product.im }";
}

say "{ $product.re }+{ $product.im < 0 ?? \
  "({ $product.im })" !! $product.im }i";

[3] A custom type with subset to validate the complex number strings - in [5].

See docs.raku.org/language/typesystem#subset for more information about subset.

[8] Helper procedure taking a complex number string and returning a Complex object.

See docs.raku.org/type/Complex for more information about the Complex type.

[14,15] Convert the Complex number strings to objects.

[16] Get the product, directly on the objects.

[27] Just printing the Complex object would work, but it would not include the fancy syntax for negative imaginary parts. The challenge wants 0+(-2)i in example 2, and printing the object would give 0-2i.

Running it:

$ ./complex-number "1+1i" "1+1i"
0+2i

$ ./complex-number "1+(-1)i" "1+(-1)i"
0+(-2)i

$ ./complex-number "0+3i" "0+4i"
-12+0i

$ ./complex-number "3+4i" "3+(-4)i"
25+0i

$ ./complex-number "50+(-20)i" "-10+30i"
100+1700i

Looking good.

With verbose mode:

$ ./complex-number -v "1+1i" "1+1i"
: Real: 1 * 1 - 1 * 1 = 0
: Imag: 1 * 1 + 1 * 1 = 2
0+2i

$ ./complex-number -v "1+(-1)i" "1+(-1)i"
: Real: 1 * 1 - -1 * -1 = 0
: Imag: 1 * -1 + -1 * 1 = -2
0+(-2)i

$ ./complex-number -v "0+3i" "0+4i"
: Real: 0 * 0 - 3 * 4 = -12
: Imag: 0 * 4 + 3 * 0 = 0
-12+0i

$ ./complex-number -v "3+4i" "3+(-4)i"
: Real: 3 * 3 - 4 * -4 = 25
: Imag: 3 * -4 + 4 * 3 = 0
25+0i

$ ./complex-number -v "50+(-20)i" "-10+30i"
: Real: 50 * -10 - -20 * 30 = 100
: Imag: 50 * 30 + -20 * -10 = 1700
100+1700i

Here is a version where we do the multiplications ourselves, insted of using Complex objects:

File: complex-number-manual
#! /usr/bin/env raku

subset Complex where * ~~ /^ \-? \d+ \+ \(? \-? \d+ \)? i $/;

unit sub MAIN (Complex $num1, Complex $num2, :v(:$verbose));

sub parse-complex(Str $s)
{
  $s ~~ /^ (\-?\d+) \+ \(? (\-?\d+) \)? i $/;
  ($0.Int, $1.Int);
}

my ($a, $b) = parse-complex($num1);
my ($c, $d) = parse-complex($num2);

my $real    = $a * $c - $b * $d;
my $imag    = $a * $d + $b * $c;

if $verbose
{
  say ": Real: $a * $c - $b * $d = $real";
  say ": Imag: $a * $d + $b * $c = $imag";
}

say "$real+{ $imag < 0 ?? "($imag)" !! $imag }i";

[10] Return the two values, instead of a (single) object.

[16+17] Manually compute the multiplication.

Running this version gives the same result. Here is an example:

$ ./complex-number-manual -v "50+(-20)i" "-10+30i"
: Real: 50 * -10 - -20 * 30 = 100
: Imag: 50 * 30 + -20 * -10 = 1700
100+1700i

#395.2 Word Squares You are given a list of equal lengths words.

Write a script to arrange a set of words into a grid that reading across any row gives the exact same word as reading down its corresponding column.

Example 1:
Input: @words = ("MA", "AM", "MY", "ME")
Output: ("MA", "AM")

    M A
    A M
Example 2:
Input: @words = ("SUN", "USE", "NET", "SEE", "TEN")
Output: ("SUN", "USE", "NET")

    S U N
    U S E
    N E T
Example 3:
Input: @words = ("BOAT", "TEAL", "AREA", "TSAR", "OGRE")
Output: ("BOAT", "OGRE", "AREA", "TEAL")

    B O A T
    O G R E
    A R E A
    T E A L
Example 4:
Input: @words = ("CARD", "AREA", "REAR", "DART")
Output: ("CARD", "AREA", "REAR", "DART")

    C A R D
    A R E A
    R E A R
    D A R T
Example 5:
Input: @words = ("HEART", "TREND", "EMBER", "RESIN", "ABUSE")
Output: ("HEART", "EMBER", "ABUSE", "RESIN", "TREND")

    H E A R T
    E M B E R
    A B U S E
    R E S I N
    T R E N D
File: word-squares
#! /usr/bin/env raku

unit sub MAIN (*@words where @words.elems > 0
                  && all(@words) ~~ /^ <[a..zA..Z]>+ $/
                  && ( [==] @words>>.chars ),
                :v(:$verbose));

my $n = @words[0].chars;

my @rows;

sub solve(Int $i)
{
  return True if $i == $n;

  my $prefix = @rows.map(*.substr($i, 1)).join;

  for @words -> $w
  {
    next if $w ∈ @rows;
    next unless $w.starts-with($prefix);

    @rows.push: $w;

    return True if solve($i + 1);
 
    @rows.pop;
  }

  return False;
}

my @result = solve(0);

if $verbose
{
  for @result -> $w
  {
    say ": " ~ $w.comb.join(" ");
  }
}

say "({ @result.map( '"' ~ * ~ '"' ).join(", ") })";

[3] At least one word,

[4] • containing English letters only,

[5] • and they must have the same length.

[8] Get the size of the matrix.

[10] The rows will be placed here (and rolled back if a dead end).

[12] Recursive procedure used to find the .

[14] We are finished if we have filled all the rows; return them.

[16] Get the prefix for the new row; from the columns of the rows we already have.

[18] Iterate over all the words.

[20] Skip words already used (i.e. already in @words).

[21] Skip words that do not start with the prefix.

[23] We can add the word to the result, so we do.

[25] Report success if the recursion ended with success.

[27] Not a success if we get here. Remove the last word and go on trying.

[30] Failure to return success (in [14] or [25]) means failure.

[33] Off we go, recursively.

[43] Pretty print the result.

Running it:

$ ./word-squares MA AM MY ME
("MA", "AM")

$ ./word-squares SUN USE NET SEE TEN
("SUN", "USE", "NET")

$ ./word-squares BOAT TEAL AREA TSAR OGRE
("BOAT", "OGRE", "AREA", "TEAL")

$ ./word-squares CARD AREA REAR DART
("CARD", "AREA", "REAR", "DART")

$ ./word-squares HEART TREND EMBER RESIN ABUSE
("HEART", "EMBER", "ABUSE", "RESIN", "TREND")

Looking good.

With verbose mode:

$ ./word-squares -v MA AM MY ME
: M A
: A M
("MA", "AM")

$ ./word-squares -v SUN USE NET SEE TEN
: S U N
: U S E
: N E T
("SUN", "USE", "NET")

$ ./word-squares -v BOAT TEAL AREA TSAR OGRE
: B O A T
: O G R E
: A R E A
: T E A L
("BOAT", "OGRE", "AREA", "TEAL")
$ ./word-squares -v CARD AREA REAR DART
: C A R D
: A R E A
: R E A R
: D A R T
("CARD", "AREA", "REAR", "DART")

$ ./word-squares -v HEART TREND EMBER RESIN ABUSE
: H E A R T
: E M B E R
: A B U S E
: R E S I N
: T R E N D
("HEART", "EMBER", "ABUSE", "RESIN", "TREND")

And that's it.