### Project Euler - Problem 17

Problem

If the numbers 1 to 5 are written out in words: one, two, three, four, five, then there are 3 + 3 + 5 + 4 + 4 = 19 letters used in total.

If all the numbers from 1 to 1000 (one thousand) inclusive were written out in words, how many letters would be used?

NOTE: Do not count spaces or hyphens. For example, 342 (three hundred and forty-two) contains 23 letters and 115 (one hundred and fifteen) contains 20 letters. The use of "and" when writing out numbers is in compliance with British usage.

Solution

//this is a very ugly solution, which I will return to to properly factor to smaller recursive methods

let GetThousandsLetters num =
match num with
| 1 -> "one thousand"
| 2 -> "two thousand"
| 3 -> "three thousand"
| 4 -> "four thousand"
| 5 -> "five thousand"
| 6 -> "six thousand"
| 7 -> "seven thousand"
| 8 -> "eight thousand"
| 9 -> "nine thousand"

let GetHundredsLetters num =
match num with
| 1 -> "one hundred"
| 2 -> "two hundred"
| 3 -> "three hundred"
| 4 -> "four hundred"
| 5 -> "five hundred"
| 6 -> "six hundred"
| 7 -> "seven hundred"
| 8 -> "eight hundred"
| 9 -> "nine hundred"

let GetTeensLetters num =
match num with
| 1 -> "eleven"
| 2 -> "twelve"
| 3 -> "thirteen"
| 4 -> "fourteen"
| 5 -> "fifteen"
| 6 -> "sixteen"
| 7 -> "seventeen"
| 8 -> "eighteen"
| 9 -> "nineteen"

let GetTensLetters num =
match num with
| 1 -> "ten"
| 2 -> "twenty"
| 3 -> "thirty"
| 4 -> "forty"
| 5 -> "fifty"
| 6 -> "sixty"
| 7 -> "seventy"
| 8 -> "eighty"
| 9 -> "ninety"

let GetSecondDigitLetters num =
match num with
| 1 -> "ten"
| 2 -> "twenty"
| 3 -> "thirty"
| 4 -> "forty"
| 5 -> "fifty"
| 6 -> "sixty"
| 7 -> "seventy"
| 8 -> "eighty"
| 9 -> "ninety"

let GetFirstDigitLetters num =
match num with
| 1 -> "one"
| 2 -> "two"
| 3 -> "three"
| 4 -> "four"
| 5 -> "five"
| 6 -> "six"
| 7 -> "seven"
| 8 -> "eight"
| 9 -> "nine"

let GetNumber num =
let numAsString = num.ToString()
let numCharArray = numAsString.ToCharArray()
let numIntArray = numCharArray |> Array.map (fun x -> System.Int32.Parse(x.ToString()))
let ln = numIntArray.Length
if ln = 4 then

let fourth = GetThousandsLetters numIntArray.[ln-4]
fourth

elif ln = 3 then

let third = GetHundredsLetters numIntArray.[ln-3]

if numIntArray.[ln-2] = 0 then
if numIntArray.[ln-1] = 0 then
third
else
let first = GetFirstDigitLetters numIntArray.[ln-1]
third + " and " + first
elif numIntArray.[ln-2] = 1 then
if numIntArray.[ln-1] = 0 then
let second = GetTensLetters numIntArray.[ln-2]
third + " and " + second
else
let second = GetTeensLetters numIntArray.[ln-1]
third + " and " + second
else
if numIntArray.[ln-1] = 0 then
let second = GetTensLetters numIntArray.[ln-2]
third + " and " + second
else
let first = GetFirstDigitLetters numIntArray.[ln-1]
let second = GetSecondDigitLetters numIntArray.[ln-2]
third + " and " + second + "-" + first

elif ln = 2 then

if numAsString.EndsWith("0") then
let second = GetTensLetters numIntArray.[ln-2]
second
elif numIntArray.[ln-2] = 1 then
let second = GetTeensLetters numIntArray.[ln-1]
second
else
let first = GetFirstDigitLetters numIntArray.[ln-1]
let second = GetSecondDigitLetters numIntArray.[ln-2]
second + "-" + first

elif ln = 1 then

let first = GetFirstDigitLetters numIntArray.[ln-1]
first

else
//nothing
""

let testNumber =
let arrWords = [1..1000] |> List.map (fun x -> GetNumber x)
let arrWordsMinusSpaces = arrWords |> List.map (fun x -> x.Replace(" ", ""))
let arrWordsMinusHyphen = arrWordsMinusSpaces |> List.map (fun x -> x.Replace("-", ""))
let arrLengths = arrWordsMinusHyphen |> List.map (fun x-> x.Length)
List.sum arrLengths

let GetNumber num =
let numAsString = num.ToString()
let numCharArray = numAsString.ToCharArray()
let numIntArray = numCharArray |> Array.map (fun x -> System.Int32.Parse(x.ToString()))
let ln = numIntArray.Length
if ln = 4 then

let fourth = GetThousandsLetters numIntArray.[ln-4]
fourth

elif ln = 3 then

let third = GetHundredsLetters numIntArray.[ln-3]

if numIntArray.[ln-2] = 0 then
if numIntArray.[ln-1] = 0 then
third
else
let first = GetFirstDigitLetters numIntArray.[ln-1]
third + " and " + first
elif numIntArray.[ln-2] = 1 then
if numIntArray.[ln-1] = 0 then
let second = GetTensLetters numIntArray.[ln-2]
third + " and " + second
else
let second = GetTeensLetters numIntArray.[ln-1]
third + " and " + second
else
if numIntArray.[ln-1] = 0 then
let second = GetTensLetters numIntArray.[ln-2]
third + " and " + second
else
let first = GetFirstDigitLetters numIntArray.[ln-1]
let second = GetSecondDigitLetters numIntArray.[ln-2]
third + " and " + second + "-" + first

elif ln = 2 then

if numAsString.EndsWith("0") then
let second = GetTensLetters numIntArray.[ln-2]
second
elif numIntArray.[ln-2] = 1 then
let second = GetTeensLetters numIntArray.[ln-1]
second
else
let first = GetFirstDigitLetters numIntArray.[ln-1]
let second = GetSecondDigitLetters numIntArray.[ln-2]
second + "-" + first

elif ln = 1 then

let first = GetFirstDigitLetters numIntArray.[ln-1]
first

else
//nothing
""

let testNumber =
let arrWords = [1..1000] |> List.map (fun x -> GetNumber x)
let arrWordsMinusSpaces = arrWords |> List.map (fun x -> x.Replace(" ", ""))
let arrWordsMinusHyphen = arrWordsMinusSpaces |> List.map (fun x -> x.Replace("-", ""))
let arrLengths = arrWordsMinusHyphen |> List.map (fun x-> x.Length)
List.sum arrLengths