#| minesweeper game
sub MAIN(Str $input where *.IO.f = "input") {
my @rect = $input.IO.lines.map(*.words.cache);
die "Not rectangle" unless [==] @rect.map(*.elems);
my @grid;
for 0 .. @rect.end -> $r {
for 0 .. @rect[$r].end -> $c {
given @rect[$r][$c] {
when "x" { @grid[$r][$c] = @rect[$r][$c] }
when "*" {
@grid[$r][$c] = 0;
for neighbors(@rect, $r, $c).List -> $pos {
@grid[$r][$c]++ if @rect[$pos[0]][$pos[1]] eq "x";
}
}
}
}
}
.put for @grid;
}
#| neighbors returns the neighbors of given index. Neighbors are
#| cached in @neighbors array. This way we don't have to compute them
#| everytime neighbors subroutine is called for the same position.
sub neighbors(
@puzzle, Int $y, Int $x --> List
) is export {
# @directions is holding a list of directions we can move in. It's
# used later for neighbors subroutine.
# $y, $x
state List @directions = (( +1, +0 ), # bottom
( +1, +1 ), # bottom-right
( +1, -1 ), # bottom-left
( -1, +0 ), # top
( -1, +1 ), # top-right
( -1, -1 ), # top-left
( +0, +1 ), # right
( +0, -1 ), # left
);
# @neighbors holds the neighbors of given position.
state Array @neighbors;
if @puzzle[$y][$x] {
# Don't re-compute neighbors.
unless @neighbors[$y][$x] {
# Set it to an empty array because otherwise if it has no
# neighbors then it would've be recomputed everytime
# neighbors() was called.
@neighbors[$y][$x] = [];
my Int $pos-x;
my Int $pos-y;
# Starting from the intital position of $y, $x we move to
# each direction according to the values specified in
# @directions array. In this case we're just trying to
# move in 4 directions (top, bottom, left & right).
direction: for @directions -> $direction {
$pos-y = $y + $direction[0];
$pos-x = $x + $direction[1];
# If movement in this direction is out of puzzle grid
# boundary then move on to next direction.
next direction unless @puzzle[$pos-y][$pos-x];
# If neighbors exist in this direction then add them
# to @neighbors[$y][$x] array.
push @neighbors[$y][$x], [$pos-y, $pos-x];
}
}
} else {
# If it's out of boundary then return no neighbor.
@neighbors[$y][$x] = [];
}
return @neighbors[$y][$x];
}