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 - $dimension); print "Insert (y, x) = "; $_ = ; 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); } }