use strict;
use warnings;
package Project::Euler::Problem::P002;
BEGIN {
$Project::Euler::Problem::P002::VERSION = '0.20';
}
use Modern::Perl;
use namespace::autoclean;
use Moose;
use Carp;
with 'Project::Euler::Problem::Base';
use Project::Euler::Lib::Types qw/ PosInt PosIntArray /;
use Project::Euler::Lib::Utils qw/ multiple_check fib_generator /;
use List::Util qw/ sum /;
#ABSTRACT: Solutions for problem 002 - Sum filtered fib numbers
has 'multi_nums' => (
is => 'rw',
isa => PosIntArray,
required => 1,
default => sub { return [2] },
);
around 'multi_nums' => sub {
my ($func, $self, $args) = @_;
if (ref $args) {
$self->$func( [sort {$a <=> $b} @$args] );
}
else {
$self->$func();
}
};
sub _build_problem_number {
# Must be an int > 0
return 2;
}
sub _build_problem_name {
# Must be a string whose length is between 10 and 80
return q{Sum filtered fib numbers};
}
sub _build_problem_date {
return q{19 October 2001};
}
sub _build_problem_desc {
return <<'__END_DESC';
Each new term in the Fibonacci sequence is generated by adding the previous two terms. By starting with 1 and 2, the first 10 terms will be:
1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...
Find the sum of all the even-valued terms in the sequence which do not exceed four million.
__END_DESC
}
sub _build_default_input {
return 4_000_000;
}
sub _build_default_answer {
return 4_613_732;
}
has '+has_input' => (default => 1);
sub _build_help_message {
return <<'__END_HELP';
You can change multi_nums to alter the way the program will function. If you
are providing custom_input, don't forget to specify the wanted_answer if you
know it!
__END_HELP
}
sub _check_input {
my ( $self, $input, ) = @_;
if ($input !~ /\D/ or $input < 1) {
croak sprintf(q{Your input, '%s', must be all digits and >= 1}, $input);
}
}
sub _solve_problem {
my ($self, $max) = @_;
# If the user didn't give us a max, then use the default_input
$max //= $self->default_input;
# Pull the multi_nums out of the object
my $multi_nums = $self->multi_nums;
# Initialize the sum and fib tracker
my $sum = 0;
my @fibs;
# Create a new Fibonacci generator
my $fib_gen = fib_generator;
# Now loop through the fib numbers until you find one greater than $max
while ((my $fib = $fib_gen->()) < $max) {
# If the found fib is a multiple of all the multi_nums,
# then add it to the sum and push it to the list of fibs
if (multiple_check($fib, $multi_nums)) {
$sum += $fib;
push @fibs, $fib;
}
}
# Save the list of fibs used in 'more info'
$self->_set_more_info(sprintf('The fibs were %s', join q{, }, @fibs));
return $sum;
}
__PACKAGE__->meta->make_immutable;
1; # End of Project::Euler::Problem::P002
__END__
=pod
=head1 NAME
Project::Euler::Problem::P002 - Solutions for problem 002 - Sum filtered fib numbers
=head1 VERSION
version 0.20
=head1 HOMEPAGE
L<< http://projecteuler.net/index.php?section=problems&id=2 >>
=head1 SYNOPSIS
use Project::Euler::Problem::P002;
my $p2 = Project::Euler::Problem::P002->new;
my $default_answer = $p2->solve;
=head1 DESCRIPTION
This module is used to solve problem #002
This is a simple problem which computes the fib numbers up to a certain maximum
and sums all of them that are even (or as implemented here, divisible by every
integer in multi_nums)
=head1 ATTRIBUTES
=head2 multi_nums
An array of positive numbers that are used to filter out the fib numbers
=over 4
=item Isa
PosIntArray
=item Default
C<[2]>
=back
=head1 SETUP
=head2 Problem Number
002
=head2 Problem Name
Sum filtered fib numbers
=head2 Problem Date
2001-10-19
=head2 Problem Desc
Each new term in the Fibonacci sequence is generated by adding the previous two
terms. By starting with 1 and 2, the first 10 terms will be:
1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...
Find the sum of all the even-valued terms in the sequence which do not exceed
four million.
=head2 Default Input
=over 4
=item Max number to go up to
C<4,000,000>
=back
=head2 Default Answer
4,613,732
=head2 Has Input?
Yes
=head2 Help Message
You can change C<< multi_nums >> to alter the way the program will function. If you
are providing custom_input, don't forget to specify the wanted_answer if you
know it!
=head1 INTERNAL FUNCTIONS
=head2 Validate Input
The restrictions on custom_input
A positive integer
=head2 Solving the problem
Generate all of the fib numbers up to $max, filtering them by the multi_nums
attribute, and find the sum
=head1 ACKNOWLEDGEMENTS
=over 4
=item *
L<< List::Util >>
=item *
L<< Project::Euler::Lib::Utils >>
=back
=head1 AUTHOR
Adam Lesperance
=head1 COPYRIGHT AND LICENSE
This software is copyright (c) 2010 by Adam Lesperance.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
=cut