# 解 Perl Weekly Challenge 088 -- 陣列乘積與矩陣之螺旋

## TASK #1 › Array of Product

You are given an array of positive integers @N.

Write a script to return an array @M where \$M[i] is the product of all elements of @N except the index \$N[i].

Example 1:

Input:

``````@N = (5, 2, 1, 4, 3)
``````

Output:

``````@M = (24, 60, 120, 30, 40)
\$M[0] = 2 x 1 x 4 x 3 = 24
\$M[1] = 5 x 1 x 4 x 3 = 60
\$M[2] = 5 x 2 x 4 x 3 = 120
\$M[3] = 5 x 2 x 1 x 3 = 30
\$M[4] = 5 x 2 x 1 x 4 = 40
``````

Example 2:

Input:

``````@N = (2, 1, 4, 3)
``````

Output:

``````@M = (12, 24, 6, 8)
\$M[0] = 1 x 4 x 3 = 12
\$M[1] = 2 x 4 x 3 = 24
\$M[2] = 2 x 1 x 3 = 6
\$M[3] = 2 x 1 x 4 = 8
``````

``my \$p = [*] @N;``

``my @M = @N.map(-> \$n { \$p / \$n });``

``my \$q = [*] @N.grep(-> \$n { \$n != 0 });``

1. N 裡面沒有 0
2. N 裡面只有一個 0，其所在位置為 i
3. N 裡面有兩個以上的 0

``````sub array-of-product (@N) {
my \$zeros = @N.grep(-> \$n { \$n == 0 }).elems;

my \$q = [*] @N.grep(-> \$n { \$n != 0 });

my \$fun;

if \$zeros == 0 {
\$fun = -> \$n { \$q / \$n };
} elsif \$zeros == 1 {
\$fun = -> \$n { \$n == 0 ?? \$q !! 0 };
} else {
\$fun = -> \$n { 0 };
}

return @N.map(\$fun);
}``````

## TASK #2 › Spiral Matrix

You are given m x n matrix of positive integers.

Write a script to print spiral matrix as list.

Example 1:

Input:

``````[ 1, 2, 3 ]
[ 4, 5, 6 ]
[ 7, 8, 9 ]
``````

Ouput:

``````[ 1, 2, 3, 6, 9, 8, 7, 4, 5 ]
``````

Example 2:

Input:

``````[  1,  2,  3,  4 ]
[  5,  6,  7,  8 ]
[  9, 10, 11, 12 ]
[ 13, 14, 15, 16 ]
``````

Output:

``````[ 1, 2, 3, 4, 8, 12, 16, 15, 14, 13, 9, 5, 6, 7, 11, 10 ]
``````

``````
my \$width  := @M[0].elems;
my \$height := @M.elems;
my @directions := [
[ 1, 0],  # →
[ 0, 1],  # ↓
[-1, 0],  # ←
[ 0,-1],  # ↑
];

my @cursor = [0,0];
my \$curdir = 0;
my @boundary = [
-1,      # ↑
\$width,  # →
\$height, # ↓
-1,      # ←
];
``````

``````sub turn (\$curdir is rw, @boundary) of Nil  { # ⤵
@boundary[\$curdir] += (\$curdir == 0|3) ?? 1 !! -1;
\$curdir = (\$curdir + 1) % 4;
return;
}

sub next-step (@cursor) {
return @cursor >>+<< @directions[\$curdir];
}``````

`>>+<<` 這個超算符符號看來很炫炮，但其實就只是把左右兩串東西一對一地相加起來，再傳回一串新的東西。(`a[0] + b[0], a[1] + b[1], a[2] + b[2], ...`)

``````sub inside-boundary(@cursor, @boundary) of Bool {
return ((@boundary[3] < @cursor[0] < @boundary[1])
and (@boundary[0] < @cursor[1] < @boundary[2]));
}``````

``````sub spiral-matrix (@M) {
# Things don't change
my \$width  := @M[0].elems;
my \$height := @M.elems;
my @directions := [
[ 1, 0],  # →
[ 0, 1],  # ↓
[-1, 0],  # ←
[ 0,-1],  # ↑
];

# Things change.
my @cursor = [0,0];
my \$curdir = 0;

# The order of boundary is arranged in thee way to make it easier to implement turn().
my @boundary = [
-1,      # ↑
\$width,  # →
\$height, # ↓
-1,      # ←
];

my sub turn (\$curdir is rw, @boundary) of Nil  { # ⤵
@boundary[\$curdir] += (\$curdir == 0|3) ?? 1 !! -1;
\$curdir = (\$curdir + 1) % 4;
return;
}

my sub next-step (@cursor, \$curdir) {
@cursor >>+<< @directions[\$curdir];
}

my sub inside-boundary(@cursor, @boundary) of Bool {
return ((@boundary[3] < @cursor[0] < @boundary[1])
and (@boundary[0] < @cursor[1] < @boundary[2]));
}

return gather {
while inside-boundary(@cursor, @boundary) {
take @M[@cursor[1]][@cursor[0]];

my @next = next-step(@cursor, \$curdir);
unless inside-boundary(@next, @boundary) {
turn(\$curdir, @boundary);
@next = next-step(@cursor, \$curdir);
}

@cursor = @next;
}
};
}``````