#ProjectEuler/Python/Problem17.py #Matthew Ellison # Created: 02-04-19 #Modified: 07-24-21 #If all the numbers from 1 to 1000 (one thousand) inclusive were written out in words, how many letters would be used? #Unless otherwise listed, all of my non-standard imports can be gotten from my pyClasses repository at https://bitbucket.org/Mattrixwv/pyClasses """ Copyright (C) 2021 Matthew Ellison This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . """ from Problems.Problem import Problem import math class Problem17(Problem): __startNum = 1 #This is the smallest number to get the words of __stopNum = 1000 #This is the largest number to get the words of #Functions #Constructor def __init__(self) -> None: super().__init__("If all the numbers from 1 (one) to 1000 (one thousand) inclusive were written out in words, how many letters would be used?") self.letterCount = 0 #Operational functions #Solve the problem def solve(self) -> None: #If the problem has already been solved do nothing and end the function if(self.solved): return #Start the timer self.timer.start() #Start with 1 and increment for num in range(self.__startNum, self.__stopNum + 1): #Pass the number to a function that will create a string for the number currentNumString = self.getStringFromNum(num) #Pass the string to a function that will count the number of letters in a string, ignoring whitespace and punctuation and add the amount to the running tally self.letterCount += self.getNumberChars(currentNumString) #Stop the timer self.timer.stop() #Throw a flag to show the problem is solved self.solved = True #This function only works for numbers -1,000,000 < num < 1,000,000 def getStringFromNum(self, number: int) -> str: numberString = "" #Starting with the largest digit create a string based on the number passed in #Check for negative if(number < 0): numberString += "negative " #Check if the number is zero if(number == 0): numberString += "zero" #Start with the thousands place if((number / 1000) >= 1): numberString += self.getStringFromNum(math.floor(number / 1000)) numberString += " thousand" number -= (math.floor(number / 1000) * 1000) #Check for hundreds place if((number / 100) >= 1): numberString += self.getStringFromNum(math.floor(number / 100)) numberString += " hundred" number -= (math.floor(number / 100) * 100) #Insert an and if there is need if((numberString != "") and (number > 0)): numberString += " and " #Check for tens place if((number / 10) >= 2): #For the tens you need to do something special tensPlace = math.floor(number / 10) if(tensPlace == 9): numberString += "ninety" elif(tensPlace == 8): numberString += "eighty" elif(tensPlace == 7): numberString += "seventy" elif(tensPlace == 6): numberString += "sixty" elif(tensPlace == 5): numberString += "fifty" elif(tensPlace == 4): numberString += "forty" elif(tensPlace == 3): numberString += "thirty" elif(tensPlace == 2): numberString += "twenty" number -= (tensPlace * 10) #If there is something left in the number you will need a space to separate it if(number > 0): numberString += ' ' #Check for teens elif((number / 10) >= 1): onesPlace = (number % 10) if(onesPlace == 9): numberString += "nineteen" elif(onesPlace == 8): numberString += "eighteen" elif(onesPlace == 7): numberString += "seventeen" elif(onesPlace == 6): numberString += "sixteen" elif(onesPlace == 5): numberString += "fifteen" elif(onesPlace == 4): numberString += "fourteen" elif(onesPlace == 3): numberString += "thirteen" elif(onesPlace == 2): numberString += "twelve" elif(onesPlace == 1): numberString += "eleven" elif(onesPlace == 0): numberString += "ten" #If this if was hit number was used up number = 0 #Check for ones place if(number >= 1): if(number == 9): numberString += "nine" elif(number == 8): numberString += "eight" elif(number == 7): numberString += "seven" elif(number == 6): numberString += "six" elif(number == 5): numberString += "five" elif(number == 4): numberString += "four" elif(number == 3): numberString += "three" elif(number == 2): numberString += "two" elif(number == 1): numberString += "one" #If this if was hit number was used up number = 0 #Return the string return numberString #Get the number of alphabetic characters in the string passed in def getNumberChars(self, number: str) -> int: sumOfLetters = 0 #Start at location 0 and count the number of letters, ignoring punctuation and whitespace for location in range(0, len(number)): tempString = number[location] if(tempString.isalpha()): sumOfLetters += 1 #Return the number return sumOfLetters #Reset the problem so it can be run again def reset(self) -> None: super().reset() self.letterCount = 0 #Gets #Returns the result of solving the problem def getResult(self) -> str: self.solvedCheck("result") return f"The sum of all the letters in all the numbers {self.__startNum}-{self.__stopNum} is {self.letterCount}" #Returns the number of letters asked for def getLetterCount(self) -> int: self.solvedCheck("letter count") return self.letterCount """Results: The sum of all the letters in all the numbers 1-1000 is 21124 It took an average of 3.095 milliseconds to run this problem through 100 iterations """