Perl Weekly Challenge 126: counting mines!

One way to let me improve my knowledge about Raku (aka Perl 6) is to implement programs in it. Unluckily, I don’t have any production code to implement in Raku yet (sob!). So, why not try solving the Perl Weekly Challenge tasks?

In the following, the assigned tasks for Challenge 110.

PWC 126 - Task 1

The first task was very simple, or at least I was quick at solving it: count all the numbers in the sequence from 1 to a given $N that do not include any 1 digit.
It is easy with grep:

sub MAIN( Int $N ) {
    ( 1 .. $N ).grep( * !~~ / 1 / ).elems.say;
}


The idea is to produce the sequence of numbers, then grep for searching for a regular expression that does not match any 1, then I count how many elements are in the array by means of elemns and print them out.

PWC 126 - Task 2

The second task was about rewriting the mine swiper game. The task was not hard, but I solved with a few nested loops.
First of all, let’s do a couple of utility functions:
  • is-mine accepts the array of input and the position (as row and column), and returns true if the position is a mine (i.e., an x);
  • compute-mines accepts the same input and tries to move on near positions to see how many mines there are.


sub is-mine( @input, $row, $column ) {
    return @input[ $row ][ $column ] ~~ 'x';
}


sub compute-mines( @input, $row, $column ) {
    my $counter = 0;

    # see where we can move
    my ( $can-left, $can-right, $can-up, $can-down ) =
         $column > 0, $column < @input[ 0 ].elems, $row > 0, $row < @input.elems;


    # left, if possible
    $counter++  if ( $can-left && is-mine( @input, $row, $column - 1 ) );
    # up if possible
    $counter++  if ( $can-up && is-mine( @input, $row - 1, $column ) );
    # down if possible
    $counter++  if ( $can-down && is-mine( @input, $row + 1 , $column ) );
    # right if possible
    $counter++  if ( $can-right && is-mine( @input, $row, $column + 1 ) );


    # left up
    $counter++  if ( $can-left && $can-up && is-mine( @input, $row - 1, $column - 1 ) );
    # right up
    $counter++  if ( $can-up &&  $can-right && is-mine( @input, $row - 1, $column + 1 ) );
    # left down
    $counter++  if ( $can-left && $can-down && is-mine( @input, $row + 1, $column - 1 ) );
    # right down
    $counter++  if ( $can-down && $can-right && is-mine( @input, $row + 1, $column + 1 ) );

    # left up if possible


    return $counter;
}



The most complex part is within the compute-mines: in short the function checks if it can move up, down, left and right and diagonal directions without going over the array boundaries. If the move can be done, and in that position there is a mine, the $counter variable is incrementd.
It is now turn to use the above functions in the main program:

sub MAIN() {
    my @input =
     qw/ x * * * x * x x x x /,
     qw/ * * * * * * * * * x /,
     qw/ * * * * x * x * x * /,
     qw/ * * * x x * * * * * /,
     qw/ x * * * x * * * * x /;

    my $rows = @input.elems;
    my $columns = @input[ 0 ].elems;


    

    my ( $current-row, $current-column ) = 0, 0;
    for 0 ..^ $rows -> $current-row {
        for 0 ..^ $columns -> $current-column {
            print is-mine( @input, $current-row, $current-column ) ?? 'x'
                      !! compute-mines( @input, $current-row, $current-column );
        }

        print "\n";
    }
}



As you can see, the @input array contains the mine field, and the first step is to compute the number of rows and columns, than to do a nested loop to print either the mine or the number computed by compute-mines.
The final result is something like the following:

% raku ch-2.p6
x101x2xxxx
110224355x
0013x3x2x2
111xx41222
x113x2001x

The article Perl Weekly Challenge 126: counting mines! has been posted by Luca Ferrari on August 16, 2021