Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- rthdays.cpp
- In this project, you will develop a command-line application to calculate information regarding specific dates in the past and future.
- Problem Statement
- An old saying about the birthday of a child goes:
- Monday’s child is fair of face,
- Tuesday’s child is full of grace,
- Wednesday’s child is full of woe,
- Thursday’s child has far to go,
- Friday’s child is loving and giving,
- Saturday’s child works hard for a living,
- But the child who is born on a Sunday
- Is bonny, blithe, good and happy.
- Your program will find out what day any given birthday was on. To enable possible future expansions, you will also include a menu system for your program. It might be interesting to see if any of these traits fit yourself or any other member of your family.
- Solution Overview
- Write a program to determine the day of the week a person was born given their birthdate.
- Your program will provide a menu, implemented using a loop, to obtain user input and calculate birthdays.
- Even though we are going over what happens in int main() early in the specification, this does NOT mean you should begin your implementation with int main(). Actually, you should write main() last.
- Since you need to write 'main()' last, this means you can use it to test all of the individual functions you need to implement.
- To begin, your program will call printHeading(), which will print this heading:
- *******************************
- Birthday Calculator
- *******************************
- Next, your program will call getMenuChoice(), which will not only print the menu (there is a function that does this) but will be also be used to obtain user input for menu selection.
- The menu options are:
- Menu Options
- ------------
- 1) Determine day of birth
- 2) Determine birthdays for the next 10 years
- 3) Finished
- Choice -->
- Depending upon the value the user enters for "Choice", the program will either determine the day of your birthday or print your birthdays for the next 10 years.
- Your program shall continue to calculate birthdays and prompt the user for another choice until a user input of 'Finished' (user choice 3) is entered.
- When the user input indicates that they’ve had enough and want out of the Birthday Calculator, your program will call printCloser(), which will print this heading:
- ****************************************************
- Thanks for using the Birthday Calculator
- ****************************************************
- and the program naturally finishes.
- There are many functions that assist in making all of this happen. Below are details concerning the functions. The short version is available through the RME’s connected with each of the functions within birthdays.cpp.
- One of the first rules of programming is to make no assumptions about your program’s user. Often users provide incorrect input, either accidentally (through unfamiliarity with the program, or perhaps a typo) or maliciously (with the intent of causing your program to fail).
- Your program must therefore check the user’s input to make sure it is within the correct range and to make sure it did not make cin fail before using it for your calculations.
- printHeading()
- This function has been implemented for you.
- /**
- * Requires: nothing
- * Modifies: cout
- * Effects: prints out the initial heading for the program
- */
- void printHeading();
- This function will print the following prompts:
- *******************************
- Birthday Calculator
- *******************************
- printCloser()
- This function has been implemented for you.
- /**
- * Requires: nothing
- * Modifies: cout
- * Effects: prints out the final greeting for the program
- */
- void printCloser();
- This function will print the following prompts:
- ****************************************************
- Thanks for using the Birthday Calculator
- ****************************************************
- printMenu()
- This function has been implemented for you.
- /**
- * Requires: nothing
- * Modifies: cout
- * Effects: prints the menu
- */
- void printMenu();
- This function will print the following prompts:
- 1) Determine day of birth
- 2) Determine birthdays for the next 10 years
- 3) Finished
- Choice -->
- getMenuChoice()
- This function will handle everything for printing the menu and handling input from the user.
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- /**
- * Requires: nothing
- * Modifies: cout, cin
- * Effects: prints the menu
- * reads the input from the user
- * checks to make sure the input is within range for the menu
- * If not prints "Invalid menu choice"
- * continues to print the menu and read an input until a valid one is entered
- * returns the users choice of menu options
- */
- int getMenuChoice();
- This function will contain the following prompts, which print depending on program’s execution:
- Invalid menu choice
- This function will call the following function(s):
- printMenu()
- Remember, cleaning up for incorrect input is critical in getting a program to really run correctly.
- Wrong input. You also cannot depend upon users to get the input correct and within range. You also need to handle out of range input. If the user enters a menu option other than 1, 2, or 3, you need to
- print Invalid menu choice
- re-print the menu, and
- get another menu choice
- If the user enters something like 1 3, then read getMenuChoice should read 1 as the menu choice and leave 3 in the input stream. You shouldn’t have to do anything special for this if you read input the usual way.
- This needs to be repeated until a valid menu choice is entered
- Testing
- Testing is an art and not a science. It is absolutely a skill and can be developed.
- The basic idea of testing is you start small and build. Start with the obvious inputs needed then expand to the boundary conditions, and then expand further into the what else category.
- To test getMenuChoice(), you do NOT need any of the other functions implemented. And when you test it thoroughly now, then if something goes wrong with your code in the future you will know it is NOT this function. This method of testing will save you mega-time.
- To test getMenuChoice(), you need to check it against good input and bad input. Therefore, to test it, call it within int main() and make sure you get the output and action you expect.
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- void test_getMenuChoice();
- int main() {
- test_getMenuChoice();
- }
- void test_getMenuChoice() {
- cout << "testing good input" << endl;
- cout << getMenuChoice() << endl; // input 1
- cout << getMenuChoice() << endl; // input 2
- cout << getMenuChoice() << endl; // input 3
- cout << "testing bad input" << endl;
- cout << getMenuChoice() << endl;
- }
- For "good input", you may want to check 1, 2, and 3. Run your code. Make absolutely sure all works as it should.
- Now it is time to check for "bad input". You may want to check: 0, 5, -3. And if you want to be really sure it works, you will also want to check a non-numeric such as a, z, #, abc — the autograder will be checking .
- If a non-integer is entered, cin will go into a fail state. To handle, you will need to clear cin and then get rid of "the offending characters" by reading all left on that line of input into a string.
- You should only remove the rest of an input line when cin enters a fail state. If cin is not in a fail state, you should always leave any unread characters in the input stream.
- Now that we have laid out the testing approach for getMenuChoice(), take the concepts and apply them to all the other functions. You can do this. Just follow the same line of thinking.
- isLeapYear()
- The helper function isLeapYear() will check whether or not a particular year is a leap year.
- /**
- * Requires: year is a Gregorian year.
- * Modifies: Nothing.
- * Effects: Returns true if the year is a leap year,
- * otherwise returns false.
- */
- bool isLeapYear (int year);
- In the Gregorian calendar, every year evenly divisible by 4 is a leap year, with the exception of the following conditions:
- If the year can be evenly divided by 100, it is NOT a leap year, unless:
- The year is also evenly divisible by 400. Then it is a leap year.
- For example: 1768 is a leap year. 1800 is not a leap year. 2000 is a leap year.
- Testing
- Write your own function test_isLeapYear() and call it within int main()
- bool isLeapYear(int year) has a "Requires" clause of "year must be a Gregorian year"
- What this means is you can — and should — test:
- // because 2015 is a Gregorian year
- cout << isLeapYear(2015) << endl;
- However, the year 1750 is not a Gregorian year. The date must strictly after September 13, 1752 to be Gregorian. Therefore, even though it is “legal” within C++ to write
- // invalid test case
- cout << isLeapYear(1750) << endl;
- It violates the Requires clause and the programmer should not do this. It is the responsibility of the coder to not violate the Requires clauses.
- What dates will thoroughly test isLeapYear()?
- Hint: you will need four of them.
- isValidDate()
- In order to verify valid dates, you will need to implement the function isValidDate(). This function returns true if and only if (IFF) the provided month, day and year is a valid date.
- /**
- * Requires: month, day, year may represent a date.
- * Modifies: Nothing.
- * Effects: Returns true if the date is valid,
- * otherwise returns false.
- */
- bool isValidDate(int month, int day, int year);
- To know whether or not a date is valid, you will first need to check whether the given year is a leap year. Therefore, isLeapYear() needs to have been implemented. Also, this makes isLeapYear() a useful helper function.
- A helper function is a function written specifically to perform a task required by another function. In this case, isLeapYear() serves as a helper function to isValidDate().
- While checking for valid dates, you will also find it necessary to ensure that the dates your user enters fall within the limits of the Gregorian calendar, meaning that the date occurs after September 13, 1752.
- At this point in your work, you may find the following poetic mnemonic useful:
- Thirty days have September,
- April, June, and November.
- All the rest have 31,
- Except for February all alone,
- It has 28 each year,
- but 29 each leap year.
- Here are some examples of invalid user input to get you started.
- Not a valid month: 13/20/1980.
- Not a valid day: 1 / 32 / 1980.
- Not a valid day: 4 / 31 / 2015.
- Before 9/14/1752: 5 / 23 / 1300.
- In all of these cases, your program should return false;.
- All dates are entered MONTH / DAY / year and not DAY / MONTH / year.
- 9 / 12 / 2000 is the 12th of September and not the 9th of December.
- Testing
- To test isValidDate(), create your own function called test_isValidDate() you will need multiple different test sets.
- Values for valid and invalid months.
- Values for valid and invalid days.
- Days that are valid for Jan but not for Feb, etc.
- Days that are valid for March but not for April, etc.
- Values for valid and invalid Gregorian years.
- Values for February 29 if it is a leap year and if it isn’t a leap year.
- Then call your test_isValidDate() function within int main().
- determineDay()
- Now, you will implement determineDay() to compute the day of the week on which the date occurs. To do this, you will use Zeller’s Rule.
- /**
- * Requires: month, day, year to form a valid date.
- * i.e., the date passed to this function has already passed isValidDate()
- * Modifies: Nothing.
- * Effects: Returns the value that Zeller's formula calculates.
- */
- int determineDay(int month, int day, int year);
- Zeller’s Rule
- The following formula is named Zeller’s Rule after Christian Zeller, a German mathematician. Using the month, day and year of a date, it computes the day of the week on which that date occurred/will occur.
- f=(D+⌊13(M+1)5⌋+Y+⌊Y4⌋+⌊C4⌋+5×C)mod7
- M is the number of the month (adjusted, see below).
- D is the day.
- Y is the last two digits of the year number (possibly adjusted).
- C is the century, i.e. the first two digits of the year number (possibly adjusted).
- ⌊x⌋ means “the greatest integer that is smaller than or equal to x”, where ⌊3.14⌋ becomes 3 and ⌊4⌋ becomes 4. This is the floor function in C++ that is defined in the cmath library.
- For example,
- If the date is 5/3/2015 (May 3, 2015), then M is 5, D is 3, Y is 15, and C is 20.
- If the date is 1/3/2015 (January 3, 2015). then M is 13, D is 3, Y will be 14, and C is 20.
- Remember to adjust the date provided by the user accordingly before performing your calculations. Calendar Adjustments
- Zeller’s rule will return a number f between 0 and 6. This “zero-indexed” number will correlate to a day of the week in the following manner:
- f Day of the week
- 0
- Saturday
- 1
- Sunday
- 2
- Monday
- 3
- Tuesday
- 4
- Wednesday
- 5
- Thursday
- 6
- Friday
- Calendar Adjustments
- Zeller’s Rule uses a calendar year beginning in March. To account for this, we count March as month 3, and January and February as months 13 and 14 of the previous year. The table below marks conversions.
- Our calendar Zeller’s calendar
- 1/1/2015
- 13/1/2014
- 2/1/2015
- 14/1/2014
- 3/1/2015
- 3/1/2015
- 4/1/2015
- 4/1/2015
- 5/1/2015
- 5/1/2015
- 6/1/2015
- 6/1/2015
- 7/1/2015
- 7/1/2015
- 8/1/2015
- 8/1/2015
- 9/1/2015
- 9/1/2015
- 10/1/2015
- 10/1/2015
- 11/1/2015
- 11/1/2015
- 12/1/2015
- 12/1/2015
- Example Calculations
- A detailed example of Zeller’s Formula is included below.
- Date: January 29, 2064 (i.e., 1/29/2064)
- M=13 (remember Jan = 13, Feb = 14, March = 3, …)
- D=29
- Y=63 (by Zeller’s calendar, the year is actually 2063)
- C=20
- f=(D+⌊13(M+1)5⌋+Y+⌊Y4⌋+⌊C4⌋+5×C)mod7=(29+⌊13(13+1)5⌋+63+⌊634⌋+⌊204⌋+5×20)mod7=(29+⌊36.4⌋+63+⌊15.75⌋+⌊5⌋+100)mod7=(29+36+63+15+5+100)mod7=248mod7=3
- 3 corresponds to a Tuesday, so January 29, 2064 will be a Tuesday.
- printDayOfBirth()
- Make sure this function is declared and defined as printDayOfBirth and not printBirthday.
- You will implement printDayOfBirth(), which prints the day of the week using the number you just calculated.
- /**
- * Requires: day (0 represents Saturday, 1 Sunday, 2 Monday, 3 Tuesday, etc)
- * Modifies: cout
- * Effects: prints the day you were born on
- * Sunday, Monday, ..., Saturday
- */
- void printDayOfBirth(int day);
- This function will contain the following prompts, which print depending on program’s execution:
- Saturday
- Sunday
- Monday
- Tuesday
- Wednesday
- Thursday
- Friday
- day is the value calculated using Zeller’s rule. Use the table we provided above to determine the day of the week.
- For example, if day is 1, printDayOfBirth() will print
- Sunday
- determineDayOfBirth()
- This is the function that manages determining the day you were born on.
- /**
- * Requires: nothing
- * Modifies: cout, cin
- * Effects: Asks for the Month/day/year of their birth
- * If the date is valid, it will print the day
- * of the week you were born on
- * Otherwise, it will print "Invalid date" prompt
- */
- void determineDayOfBirth();
- This function will contain the following prompts, which print depending on program’s execution:
- Enter your date of birth
- format: month / day / year -->
- Invalid date
- You were born on a:
- Have a great birthday!!!
- This function will call the following function(s):
- isValidDate()
- determineDay()
- printDayOfBirth()
- This is the function that will:
- Input the date.
- Check to see if it is valid. If the date isn’t valid, it will print the error message Invalid date. If it is, it will
- print the day of the week you were born on.
- tell you to Have a great birthday!!!
- Dates may be entered with our without spaces around the /.
- 12/20/1980 is acceptable. 12 / 20 / 1980 is also acceptable.
- For purposes of this project, even if the user enters a birthday that has not yet taken place, your program shall still use the past tense You were born on a: .
- This function calls several of the other functions you have already written.
- Make sure you use the "prompts" exactly as listed in the description for this function.
- print10Years()
- For the base project the only thing this function needs to do is print
- Under Construction
- Only the S’more version needs to totally implement this function.
- Putting it Together
- Once you have written and tested each of the above functions, it is time to combine everything in main() and do further testing with your new debugging skills. Be sure that your program behaves as illustrated in the Sample Output. Also know that we’ve made our own implementation of the project available, see Staff’s Implementation for details.
- This function will call the following function(s):
- printHeading()
- getMenuChoice()
- determineDayOfBirth()
- print10Years()
- printCloser()
- Testing (diff)
- Remember, a computer does not interpret. If you misspell a word, you will fail all autograder test cases. If you omit punctuation, you will fail all autograder test cases. We strongly suggest you test your code. Use diff tools to compare the Sample Output against the output generated by your code using the same input. Some easy-to-use diff websites that we recommend are:
- diffchecker.com
- quickdiff.com
- diffnow.com
- For this project, we will not check differences in whitespace; "hello " and "hello" are considered to be equivalent. This will not be the case in future projects.
- Sample Output
- Here are a few examples of the way your program output should look, wherein red underlined text represents some user’s input.
- Sample run 1
- *******************************
- Birthday Calculator
- *******************************
- Menu Options
- ------------
- 1) Determine day of birth
- 2) Determine birthdays for the next 10 years
- 3) Finished
- Choice --> 1
- Enter your date of birth
- format: month / day / year --> 9/31/1980
- Invalid date
- Menu Options
- ------------
- 1) Determine day of birth
- 2) Determine birthdays for the next 10 years
- 3) Finished
- Choice --> 1
- Enter your date of birth
- format: month / day / year --> 1/25/1956
- You were born on a: Wednesday
- Have a great birthday!!!
- Menu Options
- ------------
- 1) Determine day of birth
- 2) Determine birthdays for the next 10 years
- 3) Finished
- Choice --> 3
- ****************************************************
- Thanks for using the Birthday Calculator
- ****************************************************
- Sample run 2
- *******************************
- Birthday Calculator
- *******************************
- Menu Options
- ------------
- 1) Determine day of birth
- 2) Determine birthdays for the next 10 years
- 3) Finished
- Choice --> 4
- Invalid menu choice
- Menu Options
- ------------
- 1) Determine day of birth
- 2) Determine birthdays for the next 10 years
- 3) Finished
- Choice --> 3
- ****************************************************
- Thanks for using the Birthday Calculator
- ****************************************************
- Sample run 3
- *******************************
- Birthday Calculator
- *******************************
- Menu Options
- ------------
- 1) Determine day of birth
- 2) Determine birthdays for the next 10 years
- 3) Finished
- Choice --> 1
- Enter your date of birth
- format: month / day / year --> 9/13/1752
- Invalid date
- Menu Options
- ------------
- 1) Determine day of birth
- 2) Determine birthdays for the next 10 years
- 3) Finished
- Choice --> 1
- Enter your date of birth
- format: month / day / year --> 19/13/1982
- Invalid date
- Menu Options
- ------------
- 1) Determine day of birth
- 2) Determine birthdays for the next 10 years
- 3) Finished
- Choice --> 1
- Enter your date of birth
- format: month / day / year --> 9/13/1982
- You were born on a: Monday
- Have a great birthday!!!
- Menu Options
- ------------
- 1) Determine day of birth
- 2) Determine birthdays for the next 10 years
- 3) Finished
- Choice --> 3
- ****************************************************
- Thanks for using the Birthday Calculator
- ****************************************************
- Staff’s Implementation
- If you’d like to play with the staff’s implementation of birthdays (to see the end result, to test your own solution, or just to procrastinate), know that you can download Mac and Windows versions from the Projects page of the course’s website.
- If you’d like to run the staff’s solution on a Windows PC, download the Windows executable from the course’s website and just double-click on it. If prompted, click Run to allow Windows to run the program.
- If you’d like to run the staff’s solution on a Mac, first download the Mac executable from the course’s website.
- Next, move it from your Downloads folder to your Desktop (or anywhere else you’d like).
- Open Terminal. This app allows you to interact with your computer via keyboard commands. If you’re not sure where to find Terminal, press Command-Space to open Spotlight and search for Terminal, or head to Applications > Utilities folder in Finder and you’ll find Terminal there.
- Once you’ve opened a Terminal window, type the following and hit Enter:
- cd ~/Desktop
- This will change your current directory to Desktop. Because the Desktop folder is in your home directory and because ~ is a way to reference the home directory, you can reference your Desktop with ~/Desktop. If you placed the executable file in a different directory, you’ll have to instead provide a path to that directory.
- Now you have to change permissions for birthdays in order allow your computer to run the executable. In Terminal, type the following and hit Enter:
- chmod u+x birthdays
- Now you can run our solution by simply executing
- ./birthdays
- If you’d like to run it again, just retype the above command.
- If you’d like to run our solution after you close the Terminal, you’ll have to first re-open it and again execute cd command from above. No need to execute chmod the second time.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement