I\'ve been trying to solve Euler 17 and have been running into some trouble. The definition of that problem is:
If the numbers 1 to 5 are written out
Your code is riddled with errors:
This is wrong:
maps[60] = 6
Contribution to error: +100 (because it affects 60 to 69, 160 to 169, ..., 960 to 969).
Several teenagers are mistaken:
>>> teen(12)
7
>>> teen(13)
9
>>> teen(15)
8
>>> teen(18)
9
Contribution to error: +40 (because it affects 12, 13, ..., 112, 113, ..., 918)
And any number of the form x10:
>>> three_digit(110)
17
Contribution to error: 9 (because 110, 210, ... 910)
The number 20 is not counted (you consider i < 20
and i > 20
but not i == 20
).
Contribution to error: −6
The number 1000 is written "one thousand" in English but:
>>> thousand(1000)
8
Contribution to error: −3
You subtract 10 at the end in an attempt to compensate for one of these errors.
Contribution to error: −10
Total error: 100 + 40 + 9 − 6 − 3 − 10 = 130.
By trying to work directly with letter counts you made it really hard for you to check your own work. How many letters are there in "one hundred and ten" again? Is it 17, or is it 16? It would have been much easier for you to test your work if you had adopted a strategy like this:
unit_names = """zero one two three four five six seven eight nine ten
eleven twelve thirteen fourteen fifteen sixteen seventeen
eighteen nineteen""".split()
tens_names = """zero ten twenty thirty forty fifty sixty seventy eighty
ninety""".split()
def english(n):
"Return the English name for n, from 0 to 999999."
if n >= 1000:
thous = english(n // 1000) + " thousand"
n = n % 1000
if n == 0:
return thous
elif n < 100:
return thous + " and " + english(n)
else:
return thous + ", " + english(n)
elif n >= 100:
huns = unit_names[n // 100] + " hundred"
n = n % 100
if n == 0:
return huns
else:
return huns + " and " + english(n)
elif n >= 20:
tens = tens_names[n // 10]
n = n % 10
if n == 0:
return tens
else:
return tens + "-" + english(n)
else:
return unit_names[n]
def letter_count(s):
"Return the number of letters in the string s."
import re
return len(re.findall(r'[a-zA-Z]', s))
def euler17():
return sum(letter_count(english(i)) for i in range(1, 1001))
With this approach it's easier to check your result:
>>> english(967)
'nine hundred and sixty-seven'