Peter’s blog ✴ Week 126 ✴ 16 August 2021

THE WEEKLY CHALLENGE
Count numbers and bombs

The Perl Camel

Task 2

Minesweeper game

You are given a rectangle with points marked with either x or *. Please consider the x as a land mine. Write a script to print a rectangle with numbers and x as in the Minesweeper game. A number in a square of the minesweeper game indicates the number of mines within the neighbouring squares (usually 8), also implies that there are no bombs on that square.

Examples


Example 1:
Input:
    x * * * x * x x x x
    * * * * * * * * * x
    * * * * x * x * x *
    * * * x x * * * * *
    x * * * x * * * * x
Output:
    x 1 0 1 x 2 x x x x
    1 1 0 2 2 4 3 5 5 x
    0 0 1 3 x 3 x 2 x 2
    1 1 1 x x 4 1 2 2 2
    x 1 1 3 x 2 0 0 1 x

Analysis

I did not submit a solution at the time, but have written this later.

The essence of my solution is:

  • Loop over all the cells
  • If this one is a bomb:
    • Loop over up to 8 neighbouring cells
    • Increase their bomb-near count by 1 unless they are also a bomb

That sounds easy, but it amounts to quite a few lines of code.

One arguable aspect is that I worked with the cells in a 1-dimensional array with index of $x + $y * $width. My reason for doing that is that passing multidimensional arrays as subroutine arguments is a bit messy in Perl, and the ($x, $y) <-> $j conversion is cheap.

I have, separately, coded Minesweeper as a game in Perl and Jscript: if you would like a copy drop me an email.

I am sorry that the 'Try it' feature is currently working very slowly or not at all owing to some issue with my web hosting provider.

Try it 

Try running the script with any input:



example: '* * x *','x * * *','* x * *'

Script


#!/usr/bin/perl

# Blog: http://ccgi.campbellsmiths.force9.co.uk/challenge

use v5.26;    # The Weekly Challenge - 2021-08-16
use utf8;     # Week 126 - task 2 - Minesweeper game
use warnings; # Peter Campbell Smith
binmode STDOUT, ':utf8';

minesweeper_game('x * * * x * x x x x',
                 '* * * * * * * * * x',
                 '* * * * x * x * x *',
                 '* * * x x * * * * *',
                 'x * * * x * * * * x');
                 
minesweeper_game('* * x * x', 
                 '* x * x *', 
                 '* * x x x', 
                 'x x * * *', 
                 'x * x x x', 
                 'x x x * x', 
                 '* x x x x');

sub minesweeper_game {
    
    my (@input, @cell, $height, $width, $g, $x, $y, $xx, $yy, $c, $j);
    
    # preliminaries - build $cell and change all * to 0
    $height = @_;
    for $y (@_) {
        $cell[$j ++] = $1 while $y =~ m|([^ ])|g;
    }
    $width = $j / $height;
    show_grid('Input:', $height, $width, \@cell);
    $cell[$_] = $cell[$_] eq '*' ? 0 : 'x' for 0 .. $height * $width - 1;
    
    # loop over all cells
    for $x (0 .. $width - 1) {
        for $y (0 .. $height - 1) {
            $j = $x + $y * $width;
            
            # skip unless this is a bomb
            next unless $cell[$j] eq 'x';
            
            # loop over neighbouring cells
            for ($xx = $x - 1; $xx <= $x + 1; $xx ++) {
                for ($yy = $y - 1; $yy <= $y + 1; $yy ++) {
                    
                    # check not this cell and not off grid
                    if ($xx != $x || $yy != $y) {
                        if ($xx >= 0 && $xx < $width && $yy >= 0 && $yy < $height) {
                            
                            # add to neighbouring bomb count
                            $j = $xx + $yy * $width;
                            $cell[$j] ++ unless $cell[$j] eq 'x';
                        }
                    }
                }
            }
        }
    }
    show_grid('Output:', $height, $width,  \@cell)
}

sub show_grid {
    
    my ($cell, $height, $width, $x, $y, $j, $title);
    
    # print grid nicely
    ($title, $height, $width, $cell) = @_;
    say $title;
    for $y (0 .. $height - 1) {
        for $x (0 .. $width - 1) {
            print $cell->[$x + $y * $width] . ' ';
        }
        say '';
    }
}

27 lines of code
Completed after the closing date and not submitted to GitHub

Output from script


Input:
x * * * x * x x x x
* * * * * * * * * x
* * * * x * x * x *
* * * x x * * * * *
x * * * x * * * * x
Output:
x 1 0 1 x 2 x x x x
1 1 0 2 2 4 3 5 5 x
0 0 1 3 x 3 x 2 x 2
1 1 1 x x 4 1 2 2 2
x 1 1 3 x 2 0 0 1 x

Input:
* * x * x
* x * x *
* * x x x
x x * * *
x * x x x
x x x * x
* x x x x
Output:
1 2 x 3 x
1 x 5 x 4
3 4 x x x
x x 5 6 4
x 7 x x x
x x x 8 x
3 x x x x


 

Any content of this website which has been created by Peter Campbell Smith is in the public domain