/* __ __ __ __ __ ___
* \ \ / / \ \ / / __/
* \ \/ / /\ \ \/ / /
* \____/__/ \__\____/__/.ɪᴏ
* ᶜᵒᵖʸʳᶦᵍʰᵗ ᵇʸ ᵛᵃᵛʳ ⁻ ˡᶦᶜᵉⁿˢᵉᵈ ᵘⁿᵈᵉʳ ᵗʰᵉ ᵃᵖᵃᶜʰᵉ ˡᶦᶜᵉⁿˢᵉ ᵛᵉʳˢᶦᵒⁿ ᵗʷᵒ ᵈᵒᵗ ᶻᵉʳᵒ
*/
package io.vavr.collection.euler;
import io.vavr.Function1;
import io.vavr.collection.CharSeq;
import io.vavr.collection.Stream;
import io.vavr.collection.List;
import org.junit.Test;
import java.util.function.Predicate;
import static org.assertj.core.api.Assertions.assertThat;
/**
* <strong>Problem 35: Circular primes</strong>
* <p>The number, 197, is called a circular prime because all rotations of the digits: 197, 971, and 719, are themselves prime.</p>
* <p>There are thirteen such primes below 100: 2, 3, 5, 7, 11, 13, 17, 31, 37, 71, 73, 79, and 97.</p>
* <p>How many circular primes are there below one million?</p>
* See also <a href="https://projecteuler.net/problem=35">projecteuler.net problem 35</a>.
*/
public class Euler35Test {
@Test
public void shouldSolveProblem35() {
assertThat(rotations(197)).isEqualTo(List.of(197, 971, 719));
assertThat(circularPrimes(100)).isEqualTo(13);
assertThat(circularPrimes(1000000)).isEqualTo(55);
}
private static int circularPrimes(int n) {
final Predicate<Integer> memoizedIsPrime = Function1.of(Euler35Test::isPrime).memoized()::apply;
return Stream.rangeClosed(2, n)
.filter(memoizedIsPrime)
.map(Euler35Test::rotations)
.filter(list -> list.forAll(memoizedIsPrime))
.length();
}
private static boolean isPrime(int n) {
return n == 2 || n % 2 != 0 &&
Stream.rangeClosedBy(3, (int) Math.sqrt(n), 2)
.find(x -> n % x == 0)
.isEmpty();
}
private static List<Integer> rotations(int n) {
final CharSeq seq = CharSeq.of(String.valueOf(n));
return Stream.range(0, seq.length())
.map(i -> seq.drop(i).appendAll(seq.take(i)))
.map(s -> Integer.valueOf(s.toString()))
.toList();
}
}