RosettaCodeData/Task/Minesweeper-game/Perl/minesweeper-game.pl
Ingy döt Net 776bba907c Sync
2013-10-27 22:24:23 +00:00

166 lines
3.9 KiB
Perl

#!/usr/bin/perl
use warnings;
use strict;
{ package Local::Field;
use constant {
REAL => 0,
SHOW => 1,
COUNT => 2,
};
sub new {
my ($class, $width, $height, $percent) = @_;
my $field;
for my $x (1 .. $width) {
for my $y (1 .. $height) {
$field->[$x - 1][$y - 1][REAL] = ' ';
$field->[$x - 1][$y - 1][SHOW] = '.';
}
}
for (1 .. $percent / 100 * $width * $height) {
my ($x, $y) = map int rand $_, $width, $height;
redo if 'm' eq $field->[$x][$y][REAL];
$field->[$x][$y][REAL] = 'm';
for my $i ($x - 1 .. $x + 1) {
for my $j ($y - 1 .. $y + 1) {
$field->[$i][$j][COUNT]++
if $i >= 0 and $j >= 0
and $i <= $#$field and $j <= $#{ $field->[0] };
}
}
}
bless $field, $class;
}
sub show {
my ($self) = @_;
print "\n ";
printf '%2d ', $_ + 1 for 0 .. $#$self;
print "\n";
for my $row (0 .. $#{ $self->[0] }) {
printf '%2d ', 1 + $row;
for my $column (0 .. $#$self) {
print $self->[$column][$row][SHOW], ' ';
}
print "\n";
}
}
sub mark {
my ($self, $x, $y) = @_;
$_-- for $x, $y;
if ('.' eq $self->[$x][$y][SHOW]) {
$self->[$x][$y][SHOW] = '?';
} elsif ('?' eq $self->[$x][$y][SHOW]) {
$self->[$x][$y][SHOW] = '.';
}
}
sub end {
my $self = shift;
for my $y (0 .. $#{ $self->[0] }) {
for my $x (0 .. $#$self) {
$self->[$x][$y][SHOW] = '!' if '.' eq $self->[$x][$y][SHOW]
and 'm' eq $self->[$x][$y][REAL];
$self->[$x][$y][SHOW] = 'x' if '?' eq $self->[$x][$y][SHOW]
and 'm' ne $self->[$x][$y][REAL];
}
}
$self->show;
exit;
}
sub _declassify {
my ($self, $x, $y) = @_;
return if '.' ne $self->[$x][$y][SHOW];
if (' ' eq $self->[$x][$y][REAL] and '.' eq $self->[$x][$y][SHOW]) {
$self->[$x][$y][SHOW] = $self->[$x][$y][COUNT] || ' ';
}
return if ' ' ne $self->[$x][$y][SHOW];
for my $i ($x - 1 .. $x + 1) {
next if $i < 0 or $i > $#$self;
for my $j ($y - 1 .. $y + 1) {
next if $j < 0 or $j > $#{ $self->[0] };
no warnings 'recursion';
$self->_declassify($i, $j);
}
}
}
sub clear {
my ($self, $x, $y) = @_;
$_-- for $x, $y;
return unless '.' eq $self->[$x][$y][SHOW];
print "You lost.\n" and $self->end if 'm' eq $self->[$x][$y][REAL];
$self->_declassify($x, $y);
}
sub remain {
my $self = shift;
my $unclear = 0;
for my $column (@$self) {
for my $cell (@$column) {
$unclear++ if '.' eq $cell->[SHOW];
}
}
return $unclear;
}
}
sub help {
print << '__HELP__';
Commands:
h ... help
q ... quit
m X Y ... mark/unmark X Y
c X Y ... clear X Y
__HELP__
}
my ($width, $height, $percent) = @ARGV;
$width ||= 6;
$height ||= 4;
$percent ||= 15;
my $field = 'Local::Field'->new($width, $height, $percent);
my $help = 1;
while (1) {
$field->show;
help() if $help;
$help = 0;
my $remain = $field->remain;
last if 0 == $remain;
print "Cells remaining: $remain.\n";
my $command = <STDIN>;
exit if $command =~ /^q/i;
if ($command =~ /^m.*?([0-9]+).*?([0-9]+)/i) {
$field->mark($1, $2);
} elsif ($command =~ /^c.*?([0-9]+).*?([0-9]+)/i) {
$field->clear($1, $2);
} elsif ($command =~ /^h/i) {
$help = 1;
} else {
print "Huh?\n";
}
}
print "You won!\n";