Project Euler: Problem 17

https://projecteuler.net/problem=17

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.

First write a number_to_words(n) function that takes an integer n between 1 and 1000 inclusive and returns a list of words for the number as described above


In [10]:
def number_to_words(n):
    """Given a number n between 1-1000 inclusive return a list of words for the number."""
    # YOUR CODE HERE
    # English name of each digit/ place in dictionary
    one = {
            0: '',
            1: 'one',
            2: 'two',
            3: 'three',
            4: 'four',
            5: 'five',
            6: 'six',
            7: 'seven',
            8: 'eight',
            9: 'nine'
    }
            
    teen = { 
            10: 'ten',
            11: 'eleven',
            12: 'twelve',
            13: 'thirteen',
            14: 'fourteen',
            15: 'fifteen',
            16: 'sixteen',
            17: 'seventeen',
            18: 'eighteen',
            19: 'nineteen',
    }

    ten = {
            0: '',
            2: 'twenty',
            3: 'thirty',
            4: 'forty',
            5: 'fifty',
            6: 'sixty',
            7: 'seventy',
            8: 'eighty',
            9: 'ninety'
    }
    
    hundred = {
            1: 'onehundred', 
            2: 'twohundred',
            3: 'threehundred', 
            4: 'fourhundred',
            5: 'fivehundred', 
            6: 'sixhundred',
            7: 'sevenhundred', 
            8: 'eighthundred',
            9: 'ninehundred' 
    }
    
    hundredand = {
            1: 'onehundredand', 
            2: 'twohundredand',
            3: 'threehundredand', 
            4: 'fourhundredand',
            5: 'fivehundredand', 
            6: 'sixhundredand',
            7: 'sevenhundredand', 
            8: 'eighthundredand',
            9: 'ninehundredand' 
    }

    
    #return the name of 1-9 as a string
    if n in range (0, 10):
        return one[n]
    
    #return the name of 10-19 as a string
    elif n in range(10, 20):
        return teen[n]
    
    #return the name of 20-99 as a string
    elif n in range (20, 100):
        #turn number in to string
        a = str(n)
        #Call name of first digat from ten list
        b = int(a[0])
        #Call name of second digat from one list
        c = int(a[1])
        #return names as linked string
        return ten[b] + one[c]
    
    
    #return the name of 100-999 as a string
    elif n in range (99, 1000):
        #turn number into string
        a = str(n)
        #if last 2 digits are in teens
        if int(a[1]) == 1:
            #call name of first digit from hundred list
            b = int(a[0])
            #call name of last 2 digits from teen list 
            c = int(a[1:])
            #return number as linked string
            return hundredand[b] + teen[c]
        #If it ends in a double zero
        if int(a[1:]) == 0:
            b = int(a[0])
            return hundred[b]
        #If last 2 digits are not in teen or 00
        else:
            #call name of first digit from hundred list
            d = int(a[0])
            #Call name of second digat from ten list
            e = int(a[1])
            #Call name of second digat from one list
            f = int(a[2])
            return hundredand[d] + ten[e] + one[f]
    
    #retun onethousan if n = 1000
    elif n == 1000:
        return 'onethousand'
    
    #If anything that is not 1 - 1000 is enterd return fail as a string
    else:
        return 'fail'

Now write a set of assert tests for your number_to_words function that verifies that it is working as expected.


In [22]:
# YOUR CODE HERE
assert number_to_words(9) == 'nine'
assert number_to_words(16) == 'sixteen'
assert number_to_words(56) == 'fiftysix'
assert number_to_words(200) == 'twohundred'
assert number_to_words(315) == 'threehundredandfifteen'
assert number_to_words(638) == 'sixhundredandthirtyeight'
assert number_to_words(1000) == 'onethousand'

In [23]:
assert True # use this for grading the number_to_words tests.

Now define a count_letters(n) that returns the number of letters used to write out the words for all of the the numbers 1 to n inclusive.


In [24]:
def count_letters(n):
    """Count the number of letters used to write out the words for 1-n inclusive."""
    # YOUR CODE HERe
    #Return the length number_to_word as an integer
    return int(len(number_to_words(n)))

Now write a set of assert tests for your count_letters function that verifies that it is working as expected.


In [25]:
# YOUR CODE HERE
assert count_letters(9) == 4
assert count_letters(16) == 7
assert count_letters(56) == 8
assert count_letters(200) == 10
assert count_letters(315) == 22
assert count_letters(638) == 24
assert count_letters(1000) == 11

In [26]:
assert True # use this for gradig the count_letters test.

Finally used your count_letters function to solve the original question.


In [27]:
# YOUR CODE HERE
n = 0
i = 0
while n < 1000:
    n = n + 1
    i = i + count_letters(n)
print (i)


21124

In [17]:
assert True # use this for gradig the original sloution.