/* __ __ __ __ __ ___
* \ \ / / \ \ / / __/
* \ \/ / /\ \ \/ / /
* \____/__/ \__\____/__/.ɪᴏ
* ᶜᵒᵖʸʳᶦᵍʰᵗ ᵇʸ ᵛᵃᵛʳ ⁻ ˡᶦᶜᵉⁿˢᵉᵈ ᵘⁿᵈᵉʳ ᵗʰᵉ ᵃᵖᵃᶜʰᵉ ˡᶦᶜᵉⁿˢᵉ ᵛᵉʳˢᶦᵒⁿ ᵗʷᵒ ᵈᵒᵗ ᶻᵉʳᵒ
*/
package io.vavr.collection.euler;
import io.vavr.API;
import io.vavr.Tuple;
import io.vavr.collection.List;
import io.vavr.collection.Stream;
import org.junit.Test;
import static io.vavr.API.For;
import static org.assertj.core.api.Assertions.assertThat;
/**
* <strong>Problem 27: Quadratic primes</strong>
* <p>
* Euler discovered the remarkable quadratic formula:
* <p>
* n² + n + 41
* <p>
* It turns out that the formula will produce 40 primes for the consecutive
* values n = 0 to 39. However, when n = 40, 40^2 + 40 + 41 = 40(40 + 1) + 41 is
* divisible by 41, and certainly when n = 41, 41² + 41 + 41 is clearly
* divisible by 41.
* <p>
* The incredible formula n² − 79n + 1601 was discovered, which produces 80
* primes for the consecutive values n = 0 to 79. The product of the
* coefficients, −79 and 1601, is −126479.
* <p>
* Considering quadratics of the form:
* <p>
* n² + an + b, where |a| < 1000 and |b| < 1000 <p>
* where |n| is the modulus/absolute value of n e.g. |11| = 11 and |−4| = 4
* <p>
* Find the product of the coefficients, a and b, for the quadratic expression
* that produces the maximum number of primes for consecutive values of n,
* starting with n = 0.
* <p>
* See also
* <a href="https://projecteuler.net/problem=27">projecteuler.net problem 27
* </a>.
*/
public class Euler27Test {
@Test
public void shouldSolveProblem27() {
assertThat(numberOfConsecutivePrimesProducedByFormulaWithCoefficients(1, 41)).isEqualTo(40);
assertThat(numberOfConsecutivePrimesProducedByFormulaWithCoefficients(-79, 1601)).isEqualTo(80);
assertThat(productOfCoefficientsWithMostConsecutivePrimes(-999, 999)).isEqualTo(-59231);
}
private static int productOfCoefficientsWithMostConsecutivePrimes(int coefficientsLowerBound, int coefficientsUpperBound) {
final List<Integer> coefficients = List.rangeClosed(coefficientsLowerBound, coefficientsUpperBound);
return API.For(coefficients, coefficients).yield(Tuple::of)
.map(c -> Tuple.of(c._1, c._2, numberOfConsecutivePrimesProducedByFormulaWithCoefficients(c._1, c._2)))
.fold(Tuple.of(0, 0, -1), (n, m) -> n._3 >= m._3 ? n : m)
.apply((a, b, p) -> a * b);
}
private static int numberOfConsecutivePrimesProducedByFormulaWithCoefficients(int a, int b) {
return Stream.from(0L)
.map(n -> (long) Math.pow(n, 2) + a * n + b)
.takeWhile(Utils.MEMOIZED_IS_PRIME::apply)
.length();
}
}