/* __ __ __ __ __ ___
* \ \ / / \ \ / / __/
* \ \/ / /\ \ \/ / /
* \____/__/ \__\____/__/.ɪᴏ
* ᶜᵒᵖʸʳᶦᵍʰᵗ ᵇʸ ᵛᵃᵛʳ ⁻ ˡᶦᶜᵉⁿˢᵉᵈ ᵘⁿᵈᵉʳ ᵗʰᵉ ᵃᵖᵃᶜʰᵉ ˡᶦᶜᵉⁿˢᵉ ᵛᵉʳˢᶦᵒⁿ ᵗʷᵒ ᵈᵒᵗ ᶻᵉʳᵒ
*/
package io.vavr.collection.euler;
import io.vavr.Function2;
import io.vavr.Function3;
import io.vavr.collection.List;
import io.vavr.collection.Set;
import io.vavr.collection.Stream;
import io.vavr.control.Option;
final class Sieve {
private Sieve() {
}
private final static List<Function2<Integer, Integer, Option<Integer>>> RULES = List.of(
(x, y) -> Option.of((4 * x * x) + (y * y)).filter(n -> n % 12 == 1 || n % 12 == 5),
(x, y) -> Option.of((3 * x * x) + (y * y)).filter(n -> n % 12 == 7),
(x, y) -> Option.of((3 * x * x) - (y * y)).filter(n -> x > y && n % 12 == 11)
);
private final static List<Function3<Set<Integer>, Integer, Integer, Set<Integer>>> STEPS = List.of(
(sieve, limit, root) -> Stream.rangeClosed(1, root).crossProduct()
.foldLeft(sieve, (xs, xy) ->
RULES.foldLeft(xs, (ss, r) -> r.apply(xy._1, xy._2)
.filter(p -> p < limit)
.map(p -> ss.contains(p) ? ss.remove(p) : ss.add(p))
.getOrElse(ss)
)
),
(sieve, limit, root) -> Stream.rangeClosed(5, root)
.foldLeft(sieve, (xs, r) -> xs.contains(r)
? Stream.rangeBy(r * r, limit, r * r).foldLeft(xs, Set::remove)
: xs
)
);
static Set<Integer> fillSieve(int limit, Set<Integer> empty) {
return STEPS.foldLeft(empty.add(2).add(3), (s, step) ->
step.apply(s, limit, (int) Math.ceil(Math.sqrt(limit)))
);
}
}