/* __ __ __ __ __ ___
* \ \ / / \ \ / / __/
* \ \/ / /\ \ \/ / /
* \____/__/ \__\____/__/.ɪᴏ
* ᶜᵒᵖʸʳᶦᵍʰᵗ ᵇʸ ᵛᵃᵛʳ ⁻ ˡᶦᶜᵉⁿˢᵉᵈ ᵘⁿᵈᵉʳ ᵗʰᵉ ᵃᵖᵃᶜʰᵉ ˡᶦᶜᵉⁿˢᵉ ᵛᵉʳˢᶦᵒⁿ ᵗʷᵒ ᵈᵒᵗ ᶻᵉʳᵒ
*/
package io.vavr.collection.euler;
import io.vavr.Tuple;
import io.vavr.collection.CharSeq;
import io.vavr.Tuple3;
import io.vavr.collection.List;
import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
public class Euler32Test {
/**
* <strong>Problem 23 Pandigital products</strong>
* <p>
* We shall say that an n-digit number is pandigital if it makes use of all
* the digits 1 to n exactly once; for example, the 5-digit number, 15234,
* is 1 through 5 pandigital.
* <p>
* The product 7254 is unusual, as the identity, 39 × 186 = 7254, containing
* multiplicand, multiplier, and product is 1 through 9 pandigital.
* <p>
* Find the sum of all products whose multiplicand/multiplier/product
* identity can be written as a 1 through 9 pandigital.
* <p>
* HINT: Some products can be obtained in more than one way so be sure to
* only include it once in your sum.
* <p>
* See also <a href="https://projecteuler.net/problem=32">projecteuler.net
* problem 32</a>.
*/
@Test
public void shouldSolveProblem32() {
assertThat(isPandigital(1, 5, "15234")).isTrue();
assertThat(isPandigital(1, 9, "39" + "186" + "7254")).isTrue();
assertThat(isPandigital(1, 5, "55555")).isFalse();
assertThat(isPandigital(1, 5, "12340")).isFalse();
assertThat(sumOfAllProductsPandigital1Through9()).isEqualTo(45228);
}
private static boolean isPandigital(int from, int to, String num) {
return num.length() == to - from + 1 && List.rangeClosed(from, to).forAll(i -> num.contains(Integer.toString(i)));
}
private static final CharSeq DIGITS_1_9 = CharSeq.of("123456789");
private static long sumOfAllProductsPandigital1Through9() {
return List.of(1, 2)
.flatMap(i -> DIGITS_1_9.crossProduct(i)
.flatMap(multiplicand -> DIGITS_1_9.removeAll(multiplicand).crossProduct(5 - i)
.map(multiplier -> Tuple.of(multiplicand.mkString(), multiplier.mkString()))
)
)
.map(t -> Tuple.of(t._1, t._2, Long.valueOf(t._1) * Long.valueOf(t._2)))
.filter(t -> isPandigital(1, 9, t._1 + t._2 + Long.toString(t._3)))
.map(Tuple3::_3)
.distinct()
.sum().longValue();
}
}