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

Popular posts from this blog

Digit cancelling fractions (Project Euler Problem 33)

Champernowne's Constant - Project Euler Problem 40

Coin Sums (Project Euler Problem 31)