my $dimension = $ARGV[0] || 10;
my ($count, %old, %mines);
my $fill_char = '.';
my @row = map {$fill_char} 1..$dimension;
my @matrix = map {[@row]} @row;
my @control = ([-1, -1], [-1, 0], [-1, 1],
[0, -1], [0, 1],
[1, -1], [1, 0], [1, 1] );
sub print_matrix {
my $i;
unshift @_, [map {$_} 1..$dimension];
for (@_) {
my @row = @$_;
unshift @row, $i++ || ' ';
for (@row) {
printf("%2s ", $_) ;
}
print $/;
}
}
sub initialize_fields {
my $i;
while ($i < $dimension) {
my ($x, $y) = map {int rand $dimension} 1..2;
my $mine = join ' ', $x, $y;
$mines{$mine}++ || $i++;
}
}
sub check_square {
die "BOOOOMMMM!!!\n" if is_bomb( @_ );
cq( @_ );
}
sub cq {
my ($x, $y) = @_;
return unless $matrix[$x][$y] eq $fill_char;
my $value = value( @_ );
$matrix[$x][$y] = $value;
unless ( $value ) {
for ( @control ) {
@_ = @$_;
my @nc = ($x + $_[0], $y + $_[1]);
next if out_of_range( @nc );
next if $matrix[ $nc[0] ][ $nc[1] ] ne $fill_char;
cq( @nc );
}
}
$count++;
}
sub value {
my ($x, $y) = @_;
my $value;
for ( @control ) {
@_ = @$_;
my @nc = ($x + $_[0], $y + $_[1]);
next if out_of_range( @nc );
$value += is_bomb( @nc );
}
return $value;
}
sub is_bomb {
my $mine = join ' ', @_;
return $mines{$mine} ? 1 : 0;
}
sub out_of_range {
return grep { $_ < 0 or $_ >= $dimension } @_;
}
initialize_fields;
while (1) {
print_matrix(@matrix);
print "YOU WON!!!\n" and exit if $count >= ($dimension ** 2 - $dim
+ension);
print "Insert (y, x) = ";
$_ = <STDIN>; print $/;
my ($command, $x, $y) = /^(x)?\s*(\d+)\D+(\d+)/i;
$x--; $y--;
print "x or y out of range!!!\n\n" and next if out_of_range($x, $y
+);
if ( $command ) {
if ( $matrix[$x][$y] eq 'X' ) {
my $mine = join ' ', $x, $y;
$matrix[$x][$y] = $old{$mine};
} else {
my $mine = join ' ', $x, $y;
$old{$mine} = $matrix[$x][$y];
$matrix[$x][$y] = 'X';
}
} else {
check_square($x, $y);
}
}
Update: fixed
exploitable bug.
Update (20020117): cuter command parsing.
$|=$_='1g2i1u1l2i4e2n0k',map{print"\7",chop;select$,,$,,$,,$_/7}m{..}g