This is my response to The Weekly Challenge #395.
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.
#! /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:
#! /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
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
#! /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.