package Enigmatic::Machine;
use DAKKAR::p 'class';
use Enigmatic::RotorBox;
use Enigmatic::ReflectorBox;
use Enigmatic::Plugboard;
use Enigmatic::CryptTrain;
use Enigmatic::Types qw(Letter RotorT ReflectorT PlugboardT);
use MooseX::Types::Moose qw(ArrayRef Str);
has train => (
isa => 'Enigmatic::CryptTrain',
is => 'ro',
);
has plugboard => (
isa => PlugboardT,
is => 'ro',
default => sub { Enigmatic::Plugboard->new },
coerce => 1,
);
around BUILDARGS => sub {
my $orig = shift;
my $class = shift;
my $args = $class->$orig(@_);
croak "no rotors specified" unless $args->{rotors};
croak "no reflector specified" unless $args->{reflector};
my $rotors = $args->{rotors}->map(\&to_RotorT);
my $reflector = to_ReflectorT($args->{reflector});
if ($args->{ring_settings}) {
$args->{ring_settings}->each(
sub {
my ($idx,$setting) = @_;
$rotors->[$idx]->ring_setting($setting);
});
}
$args->{train} = Enigmatic::CryptTrain->new({
rotors => $rotors,
reflector => $reflector,
( $args->{rotor_positions} ? ( positions => $args->{rotor_positions} ) : () ),
});
return $args;
};
sub map {
my $self = shift;
my ($letter) = pos_validated_list(
\@_,
{ isa => Letter },
);
$letter = $self->plugboard->map($letter);
$letter = $self->train->map($letter);
$letter = $self->plugboard->map($letter);
return $letter;
}
sub map_string {
my ($self,$string) = @_;
my @letters = $string->split(qr//)->grep(\&is_Letter)->flatten;
my @res;
for my $letter (@letters) {
push @res, $self->map($letter);
}
return wantarray ? @res : @res->join;
}