/*     / \____  _    _  ____   ______  / \ ____  __    _______
 *    /  /    \/ \  / \/    \ /  /\__\/  //    \/  \  //  /\__\   JΛVΛSLΛNG
 *  _/  /  /\  \  \/  /  /\  \\__\\  \  //  /\  \ /\\/ \ /__\ \   Copyright 2014-2016 Javaslang, http://javaslang.io
 * /___/\_/  \_/\____/\_/  \_/\__\/__/\__\_/  \_//  \__/\_____/   Licensed under the Apache License, Version 2.0
 */
package javaslang.collection.euler;

import javaslang.collection.List;
import javaslang.collection.Stream;
import org.junit.Test;

import static org.assertj.core.api.Assertions.assertThat;

public class Euler45Test {

    /**
     * <strong>Problem 45 Triangular, pentagonal, and hexagonal</strong>
     *
     * <p>Triangle, pentagonal, and hexagonal numbers are generated by the following formulae:</p>
     * <p>Triangle      Tn=n(n+1)/2     1, 3,  6, 10, 15, ...</p>
     * <p>Pentagonal    Pn=n(3n−1)/2    1, 5, 12, 22, 35, ...</p>
     * <p>Hexagonal     Hn=n(2n−1)      1, 6, 15, 28, 45, ...</p>
     *
     * <p>
     * It can be verified that T285 = P165 = H143 = 40755.
     * Find the next triangle number that is also pentagonal and hexagonal.
     * </p>
     *
     * See also <a href="https://projecteuler.net/problem=45">projecteuler.net
     * problem 45</a>.
     */

    @Test
    public void shouldSolveProblem45() {
        assertThat(List.of(5, 12, 22, 35)).allMatch(Euler45Test::isPentagonal);
        assertThat(List.of(3, 11, 21, 36)).allMatch(i -> !isPentagonal(i));
        assertThat(HEXAGONAL.take(5)).containsExactly(6L, 15L, 28L, 45L, 66L);

        assertThat(HEXAGONAL
                .filter(Euler45Test::isPentagonal)
                .head())
                .isEqualTo(40755);

        assertThat(HEXAGONAL
                .filter(Euler45Test::isPentagonal)
                .tail()
                .head())
                .isEqualTo(1533776805L);
    }

    private static final Stream<Long> HEXAGONAL = Stream.from(2L).map(i -> i*(2*i -1));

    private static boolean isPentagonal(long i) {
        // If a number k is pentagonal then n(3n−1)/2 = k; for some integer n
        // by the quadratic formula (1+sqrt(1+4*3*2k))/6 = n
        long discriminant = 1+24*i;
        return isPerfectSquare(discriminant) && (1 + flooredRoot(discriminant)) % 6 == 0;
    }

    private static boolean isPerfectSquare(long i) {
        long sqrtFloor = flooredRoot(i);
        return sqrtFloor*sqrtFloor == i;
    }

    private static long flooredRoot(long i) {
        return (long)Math.sqrt(i+0.5);
    }
}

Add euler 45 solution