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 [72]:
def ones(one,count):
    if one == 1 or one == 2 or one == 6:
        count += 3 
    if one == 4 or one == 5 or one == 9:
        count += 4   
    if one == 3 or one == 7 or one == 8:
        count += 5
        
    return count

def teens(teen,count):
    if teen == 10:
        count += 3
    if teen == 11 or teen == 12:
        count += 6
    if teen == 15 or teen == 16:
        count += 7
    if teen == 13 or teen == 14 or teen == 18 or teen == 19:
        count += 8
    if teen == 17:
        count += 9
        
    return count

def tens(ten,count):
    b = str(ten)
    
    if b[0] == '4' or b[0] == '5' or b[0] == '6':
        count += 5
        one = int(b[1])
        count = ones(one,count)
    if b[0] == '2' or b[0] == '3' or b[0] == '8' or b[0] == '9' and b[1]:
        count += 6
        one = int(b[1])
        count = ones(one,count)
        
    if b[0] == '7' and b[1]:
        count += 7
        one = int(b[1])
        count = ones(one,count)
        
    return count

def huns(hun,count):
    count += 7
    a = str(hun)
    b = int(a[0])
    count = ones(b,count)
    
    return count

def numberlettercounts(nummin,nummax):
    nums = []
    for i in range(nummin,nummax+1):
        nums.append(i)
    
    
    count = 0
    for num in nums:
        a = str(num)
        if len(a) == 1:
            count = ones(num,count)
        if len(a) == 2 and a[0] == '1':
            count = teens(num,count)
        if len(a) == 2 and a[0] != '1':
            count = tens(num,count)
        if len(a) == 3 and a[1] == '0' and a[2]=='0':
            count = huns(num,count)
        if len(a) == 3 and a[1] != '0' and a[2] == '0':
            count = huns(num,count)
            ten = int(a[1:3])
            if a[1] == '1':
                count = teens(ten,count)
                count += 3 #for 'and'
            if a[1] != '1':
                count = tens(ten,count)
                count += 3 #for 'and'
        if len(a) == 3 and a[1] != '0' and a[2] != '0':
            count = huns(num,count)
            ten = int(a[1:3])
            if a[1] == '1' :
                count = teens(ten,count)
                count += 3 #for 'and'
            if a[1] != '1' :
                count = tens(ten,count)
                count += 3 #for 'and'
        if len(a) == 3 and a[1] == '0' and a[2] != '0': 
            count = huns(num,count)
            count += 3 #for 'and'
            c = int(a[2])
            count = ones(c,count)
        if len(a) == 4:
            count += 11
    print (count)

In [75]:
numberlettercounts(1,1000)


21124

In [65]:
def number_to_words(n, join = True):
    units = ['','one','two','three','four','five','six','seven','eight','nine']
    teens = ['','eleven','twelve','thirteen','fourteen','fifteen','sixteen', \
             'seventeen','eighteen','nineteen']
    tens = ['','ten','twenty','thirty','forty','fifty','sixty','seventy', \
            'eighty','ninety']
    thousands = ['','thousand']
    words = []
    if n==0: words.append('zero')
    else:
        nStr = '%d'%n
        nStrLen = len(nStr)
        groups = (nStrLen+2)/3
        nStr = nStr.zfill(int(groups)*3)
        for i in range(0,int(groups)*3,3):
            x,y,z = int(nStr[i]),int(nStr[i+1]),int(nStr[i+2])
            g = int(groups)-(i/3+1)
            if x>=1:
                words.append(units[x])
                words.append('hundred')
            if y>1:
                words.append(tens[y])
                if z>=1: words.append(units[z])
            elif y==1:
                if z>=1: words.append(teens[z])
                else: words.append(tens[y])
            else:
                if z>=1: words.append(units[z])
                if (int(g)>=1) and ((int(x)+int(y)+int(z))>0): words.append(thousands[int(g)])
    if join: return ' '.join(words)
    return words

In [66]:
number_to_words(999)


Out[66]:
'nine hundred ninety nine'

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


In [71]:
number_to_words(999)
expected ='nine hundred ninety nine'
number_to_words(0)
expected2 ='zero'
number_to_words(1000)
expected3 ='one thousand'
number_to_words(5)
expected4 ='five'
assert (number_to_words(999) == expected)
assert (number_to_words(0) == expected2)
assert (number_to_words(1000) == expected3)
assert (number_to_words(5) == expected4)

In [68]:
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 [ ]:
def ones(one,count):
    if one == 1 or one == 2 or one == 6:
        count += 3 
    if one == 4 or one == 5 or one == 9:
        count += 4   
    if one == 3 or one == 7 or one == 8:
        count += 5
        
    return count

def teens(teen,count):
    if teen == 10:
        count += 3
    if teen == 11 or teen == 12:
        count += 6
    if teen == 15 or teen == 16:
        count += 7
    if teen == 13 or teen == 14 or teen == 18 or teen == 19:
        count += 8
    if teen == 17:
        count += 9
        
    return count

def tens(ten,count):
    b = str(ten)
    
    if b[0] == '4' or b[0] == '5' or b[0] == '6':
        count += 5
        one = int(b[1])
        count = ones(one,count)
    if b[0] == '2' or b[0] == '3' or b[0] == '8' or b[0] == '9' and b[1]:
        count += 6
        one = int(b[1])
        count = ones(one,count)
        
    if b[0] == '7' and b[1]:
        count += 7
        one = int(b[1])
        count = ones(one,count)
        
    return count

def huns(hun,count):
    count += 7
    a = str(hun)
    b = int(a[0])
    count = ones(b,count)
    
    return count

In [85]:
#def count_letters(n): <--I didn't use this...
def count_letters(nummin,nummax):
    nums = []
    for i in range(nummin,nummax+1):
        nums.append(i)
    
    
    count = 0
    for num in nums:
        a = str(num)
        if len(a) == 1:
            count = ones(num,count)
        if len(a) == 2 and a[0] == '1':
            count = teens(num,count)
        if len(a) == 2 and a[0] != '1':
            count = tens(num,count)
        if len(a) == 3 and a[1] == '0' and a[2]=='0':
            count = huns(num,count)
        if len(a) == 3 and a[1] != '0' and a[2] == '0':
            count = huns(num,count)
            ten = int(a[1:3])
            if a[1] == '1':
                count = teens(ten,count)
                count += 3 #for 'and'
            if a[1] != '1':
                count = tens(ten,count)
                count += 3 #for 'and'
        if len(a) == 3 and a[1] != '0' and a[2] != '0':
            count = huns(num,count)
            ten = int(a[1:3])
            if a[1] == '1' :
                count = teens(ten,count)
                count += 3 #for 'and'
            if a[1] != '1' :
                count = tens(ten,count)
                count += 3 #for 'and'
        if len(a) == 3 and a[1] == '0' and a[2] != '0': 
            count = huns(num,count)
            count += 3 #for 'and'
            c = int(a[2])
            count = ones(c,count)
        if len(a) == 4:
            count += 11
    return (count)

In [90]:
count_letters(0,342)


Out[90]:
6117

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


In [91]:
expected1=3
assert(count_letters(0,1) == expected1)

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

Finally used your count_letters function to solve the original question.


In [92]:
count_letters(1,1000)


Out[92]:
21124

In [ ]:
assert True # use this for gradig the answer to the original question.