### The Problem

Triangle, pentagonal, and hexagonal numbers are generated by the following formulae:

Triangle Tn=n(n+1)/2 1, 3, 6, 10, 15, ...

Pentagonal Pn=n(3n−1)/2 1, 5, 12, 22, 35, ...

Hexagonal Hn=n(2n−1) 1, 6, 15, 28, 45, ...

It can be verified that T285 = P165 = H143 = 40755.

Find the next triangle number that is also pentagonal and hexagonal.

### The Solution

Plan of attack:

• Starting from 286, generate a sequence of triangle numbers
• Test each one for pentagonality
• Test each one for hexagonality
• When we find one that is both pentagonal and hexagonal, we have our answer.

``````let firstT = 285L + 1L
let firstP = 165L + 1L
let firstH = 143L + 1L
``````

Based on the problem definition, we know that the first time T, P, and H line up is at `n` = 285, 165, and 143, respectively. So when we start generating sequences, we're going to start at one past those.

``````let t n = n * (n + 1L) / 2L
let p n = n * (3L * n - 1L) /2L
let h n = n * (2L * n - 1L)
``````

The above trio of functions generate the nth triangle, pentagonal, and hexagonal number.

Now, we need a quick way to test for pentagonal and hexagonal numbers. So we'll make maps containing 100000 of each class of numbers. 100000 is a number I just made up on the spot because it "seemed reasonable". We can adjust later if need be.

``````let makeMap f first =
let nums =
Seq.unfold (fun state -> Some(f state, state + 1L)) first
|> Seq.mapi (fun i x -> (x,i+1))
|> Seq.take 100000
|> List.ofSeq

let max = fst (nums |> List.last)
let map = Map.ofList nums
(max,map)

let pentagonalMax,pentagonalMap = makeMap p firstP
let hexagonalMax,hexagonalMap = makeMap h firstH
let maxToCheck = min pentagonalMax hexagonalMax

let isPentagonal n = Map.containsKey n pentagonalMap
let isHexagonal n = Map.containsKey n hexagonalMap
``````

The `makeMap` function takes a starting value and a sequence unfolding function. It generates the sequence and converts it into a map. It returns both the maximum value in the map and the map itself.

Using `makeMap` we generate pentagonal and hexagonal maps and their maximums. The value `maxToCheck` gets bound to the minimum of `pentagonalMax` and `hexagonalMax`. We'll stop generating triangle numbers when they get above this value.

Finally, we have a pair of functions, `isPentagonal` and `isHexagonal` that can check for pentagonality and hexagonality, respectively.

Now we need a bunch of triangle numbers to start testing:

``````let generateTriangle state =
let number = t state
if (number > maxToCheck) then
None
else
Some(number, state + 1L)

let triangleNumbers =  Seq.unfold generateTriangle firstT
``````

We use `Seq.unfold` to generate triangle numbers using the generator function `generateTriangle`. It stops generating when the number generated exceeds `maxToCheck`.

Now we can solve the problem:

``````triangleNumbers
|> Seq.filter (fun n -> isPentagonal n && isHexagonal n)