Algorithm-X-DLX
view release on metacpan or search on metacpan
examples/npieces/NPieces.pm view on Meta::CPAN
package NPieces;
use strict;
use warnings;
use Algorithm::X::DLX;
use Algorithm::X::ExactCoverProblem;
use Carp;
use constant { None => 0, Knight => 1, Queen => 2 };
sub new {
my ($class, %args) = @_;
my $self = bless {
width_ => $args{width} || 0,
height_ => $args{height} || 0,
knights_ => $args{knights} || 0,
queens_ => $args{queens} || 0,
problem_ => undef,
row_data_ => [],
iterator_ => undef
}, $class;
return $self->_initialize();
}
sub _initialize {
my ($self) = @_;
# Columns
# P*A: (x,y) attacked by piece i?
# P*A: placing piece i at (x,y) ok?
# P: piece i used?
#
# Total: (2A+1)P
# Secondary: 2AP
my $A = $self->{width_} * $self->{height_};
my $P = $self->{knights_} + $self->{queens_};
$self->{problem_} = Algorithm::X::ExactCoverProblem->new((2 * $A + 1) * $P, undef, 2 * $A * $P);
for (my $yx = 0; $yx < $A; $yx++) {
my $x = $yx % $self->{width_};
my $y = int($yx / $self->{width_});
for (my $p = 0; $p < $P; $p++) {
my $piece = ($p < $self->{knights_}) ? Knight : Queen;
push @{$self->{row_data_}}, { piece => $piece, x => $x, y => $y };
my @columns;
push @columns, map { col_attack($A, $p, $_) } @{$self->attacks($piece, $x, $y)};
push @columns, col_piece($P, $A, $p);
push @columns, col_put($P, $A, $p, $yx);
for (my $p2 = 0; $p2 < $P; $p2++) {
push @columns, col_attack($A, $p2, $yx) if ($p2 != $p);
}
if ($p > 0 && ($p - 1 < $self->{knights_}) == ($piece == Knight)) {
push @columns, map { col_put($P, $A, $p - 1, $_) } ($yx + 1 .. $A - 1);
}
@columns = sort { $a <=> $b } @columns;
$self->{problem_}->add_row(\@columns);
}
}
$self->{iterator_} = Algorithm::X::DLX->new($self->{problem_})->get_solver();
return $self;
}
sub size {
( run in 0.655 second using v1.01-cache-2.11-cpan-524268b4103 )