diff --git a/ProblemSelection.ts b/ProblemSelection.ts index aacff0b..560f898 100644 --- a/ProblemSelection.ts +++ b/ProblemSelection.ts @@ -40,11 +40,12 @@ import { Problem13 } from "./Problems/Problem13"; import { Problem14 } from "./Problems/Problem14"; import { Problem15 } from "./Problems/Problem15"; import { Problem16 } from "./Problems/Problem16"; +import { Problem17 } from "./Problems/Problem17"; export class ProblemSelection{ //Holds the valid problem numbers - public static PROBLEM_NUMBERS: number[] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; + public static PROBLEM_NUMBERS: number[] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17]; //Returns the problem corresponding to the given problem number public static getProblem(problemNumber: number): Problem{ @@ -66,6 +67,7 @@ export class ProblemSelection{ case 14: problem = new Problem14(); break; case 15: problem = new Problem15(); break; case 16: problem = new Problem16(); break; + case 17: problem = new Problem17(); break; } return problem; } diff --git a/Problems/Problem17.ts b/Problems/Problem17.ts new file mode 100644 index 0000000..5f1bc37 --- /dev/null +++ b/Problems/Problem17.ts @@ -0,0 +1,205 @@ +//ProjectEulerTS/Problems/Problem17.ts +//Matthew Ellison +// Created: 03-29-21 +//Modified: 03-29-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 non-standard includes are my own creation and available from https://bibucket.org/Mattrixwv/typescriptClasses +/* + 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 . +*/ + + +import { Unsolved } from "../Unsolved"; +import { Problem } from "./Problem"; + + +export class Problem17 extends Problem{ + //Variables + //Static variables + private static START_NUM: number = 1; //This is the smallest number to get the words of + private static STOP_NUM: number = 1000; //This is the largest number to get the words of + //Instance variables + private letterCount: number; //This is the cumulative number of letters in the words of the numbers + + //Functions + //Constructor + public constructor(){ + super(`If all of teh numbers from ${Problem17.START_NUM} to ${Problem17.STOP_NUM} inclusive were written out in words, how many letters would be used?`); + this.letterCount = 0; + } + //Operational functions + //Solve the problem + public solve(): void{ + //If the problem has already been solved do nothing and end the function + if(this.solved){ + return; + } + + //Start the timer + this.timer.start(); + + //Start with 1 and increment + for(let num: number = Problem17.START_NUM;num <= Problem17.STOP_NUM;++num){ + //Pass the number to a function that will create a string for the number + let currentNumString: string = this.makeWordFromNum(num); + //Pass the string to the function that will count the number of letters in it, ignoring whitespace and punctuation and add that number to the running tally + this.letterCount += this.getNumberChars(currentNumString); + } + + //Stop the timer + this.timer.stop(); + + //Throw a flag to show the problem is solved + this.solved = true; + } + //Reset the problem so it can be run again + public reset(): void{ + super.reset(); + this.letterCount = 0; + } + //This function makes a word out of the number passed into it + private makeWordFromNum(orgNum: number): string{ + let num: number = orgNum; + let numberString: string = ""; + //Starting with the largest digit create a string based on the number passed in + //Check for negative + if(num < 0){ + numberString += "negative "; + } + + //Check if the number is zero + if(num == 0){ + numberString += "zero"; + } + + //Start with the thousands place + if((num / 1000) >= 1){ + numberString += this.makeWordFromNum(Math.floor(num / 1000)); + numberString += " thousand"; + num -= (Math.floor(num / 1000) * 1000); + } + + //Check the hundreds place + if((num / 100) >= 1){ + numberString += this.makeWordFromNum(Math.floor(num / 100)); + numberString += " hundred"; + num -= (Math.floor(num / 100) * 100); + } + + //Insert an and if there is need + if((numberString.trim().length > 0) && (num > 0)){ + numberString += " and "; + } + + //Check for tens place + if((num / 10) >= 2){ + //For the tens you need to do something special + let tensPlace: number = Math.floor(num / 10); + switch(tensPlace){ + case 9: numberString += "ninety"; break; + case 8: numberString += "eighty"; break; + case 7: numberString += "seventy"; break; + case 6: numberString += "sixty"; break; + case 5: numberString += "fifty"; break; + case 4: numberString += "forty"; break; + case 3: numberString += "thirty"; break; + case 2: numberString += "twenty"; break; + } + num -= (tensPlace * 10); + //If there is something left in the number you will need a dash to separate the tens and ones place + if(num > 0){ + numberString += "-"; + } + } + //Check for teens + else if((num / 10) >= 1){ + let onesPlace: number = (num % 10); + switch(onesPlace){ + case 9: numberString += "nineteen"; break; + case 8: numberString += "eighteen"; break; + case 7: numberString += "seventeen"; break; + case 6: numberString += "sixteen"; break; + case 5: numberString += "fifteen"; break; + case 4: numberString += "fourteen"; break; + case 3: numberString += "thirteen"; break; + case 2: numberString += "twelve"; break; + case 1: numberString += "eleven"; break; + case 0: numberString += "ten"; break; + } + //If this was hit the number was completed + num = 0; + } + + //Check for the ones place + if(num >= 1){ + switch(num){ + case 9: numberString += "nine"; break; + case 8: numberString += "eight"; break; + case 7: numberString += "seven"; break; + case 6: numberString += "six"; break; + case 5: numberString += "five"; break; + case 4: numberString += "four"; break; + case 3: numberString += "three"; break; + case 2: numberString += "two"; break; + case 1: numberString += "one"; break; + } + //If this was hit the number was completed + num = 0; + } + + //If the number is not 0 there was a problem + if(num != 0){ + throw new Unsolved("The number " + orgNum + " was not completely reduced!\nRemainder is " + num); + } + + //Return the string + return numberString; + } + //This counts the number of letters in the string that is passed in (ignoring numbers and puctuation) + private getNumberChars(num: string): number{ + let sumOfLetters: number = 0; + //Start at location 0 and count the number of letters, ignoring punctuation and whitespace + for(let location: number = 0;location < num.length;++location){ + let char = num.charAt(location).toLowerCase(); + if((char >= "a") && (char <= "z")){ + sumOfLetters += 1; + } + } + + //Returns the number of letters + return sumOfLetters; + } + //Gets + //Returns the result of solving the problem + public getResult(): string{ + if(!this.solved){ + throw new Unsolved(); + } + return `The sum of all the letters in all the numbers ${Problem17.START_NUM}-${Problem17.STOP_NUM} is ${this.letterCount}`; + } + //Returns the number of letters asked for + public getLetterCount(): number{ + if(!this.solved){ + throw new Unsolved(); + } + return this.letterCount; + } +} + +/* Results: +The sum of all the letters in all the numbers 1-1000 is 21124 +It took an average of 485.744 microseconds to run this problem through 100 iterations +*/