feat: finish chapter 3, program 1
This commit is contained in:
parent
8ee64c7e1e
commit
6fd1605429
2 changed files with 279 additions and 0 deletions
|
@ -21,3 +21,4 @@ c_2_lab_3 = executable('c_2_lab_3', 'src/chapter_2/lab_3/main.cpp', install: tru
|
||||||
c_2_program_1 = executable('c_2_program_1', 'src/chapter_2/program_1/main.cpp', install: true)
|
c_2_program_1 = executable('c_2_program_1', 'src/chapter_2/program_1/main.cpp', install: true)
|
||||||
|
|
||||||
c_3_lab_1 = executable('c_3_lab_1', 'src/chapter_3/lab_1/main.cpp', install: true)
|
c_3_lab_1 = executable('c_3_lab_1', 'src/chapter_3/lab_1/main.cpp', install: true)
|
||||||
|
c_3_program_1 = executable('c_3_program_1', 'src/chapter_3/program_1/main.cpp', install: true)
|
||||||
|
|
278
src/chapter_3/program_1/main.cpp
Normal file
278
src/chapter_3/program_1/main.cpp
Normal file
|
@ -0,0 +1,278 @@
|
||||||
|
#include <algorithm>
|
||||||
|
#include <array>
|
||||||
|
#include <iostream>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
class Date {
|
||||||
|
private:
|
||||||
|
unsigned day;
|
||||||
|
unsigned month;
|
||||||
|
string monthName;
|
||||||
|
unsigned year;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// creates the date January 1st, 2000.
|
||||||
|
Date();
|
||||||
|
|
||||||
|
/* parameterized constructor: month number, day, year
|
||||||
|
- e.g. (3, 1, 2010) will construct the date March 1st, 2010
|
||||||
|
|
||||||
|
If any of the arguments are invalid (e.g. 15 for month or 32 for day)
|
||||||
|
then the constructor will construct instead a valid Date as close
|
||||||
|
as possible to the arguments provided - e.g. in above example,
|
||||||
|
Date(15, 32, 2010), the Date would be corrected to Dec 31st, 2010.
|
||||||
|
In case of such invalid input, the constructor will issue a console error
|
||||||
|
message:
|
||||||
|
|
||||||
|
Invalid date values: Date corrected to 12/31/2010.
|
||||||
|
(with a newline at the end).
|
||||||
|
*/
|
||||||
|
Date(unsigned m, unsigned d, unsigned y);
|
||||||
|
|
||||||
|
/* parameterized constructor: month name, day, year
|
||||||
|
- e.g. (December, 15, 2012) will construct the date December 15th, 2012
|
||||||
|
|
||||||
|
If the constructor is unable to recognize the string argument as a valid
|
||||||
|
month name, then it will issue a console error message:
|
||||||
|
|
||||||
|
Invalid month name: the Date was set to 1/1/2000.
|
||||||
|
(with a newline at the end).
|
||||||
|
|
||||||
|
If the day argument is invalid for the given month (but the month name was
|
||||||
|
valid), then the constructor will handle this error in the same manner as
|
||||||
|
the other parameterized constructor.
|
||||||
|
|
||||||
|
This constructor will recognize both "december" and "December"
|
||||||
|
as month name.
|
||||||
|
*/
|
||||||
|
Date(const string &mn, unsigned d, unsigned y);
|
||||||
|
|
||||||
|
/* Outputs to the console (cout) a Date exactly in the format "3/15/2012".
|
||||||
|
Does not output a newline at the end.
|
||||||
|
*/
|
||||||
|
void printNumeric() const;
|
||||||
|
|
||||||
|
/* Outputs to the console (cout) a Date exactly in the format "March 15,
|
||||||
|
2012". The first letter of the month name is upper case, and the month name
|
||||||
|
is printed in full - January, not Jan, jan, or january. Does not output a
|
||||||
|
newline at the end.
|
||||||
|
*/
|
||||||
|
void printAlpha() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
/* Returns true if the year passed in is a leap year, otherwise returns false.
|
||||||
|
*/
|
||||||
|
bool isLeap(unsigned y) const;
|
||||||
|
|
||||||
|
/* Returns number of days allowed in a given month
|
||||||
|
- e.g. daysPerMonth(9, 2000) returns 30.
|
||||||
|
Calculates February's days for leap and non-leap years,
|
||||||
|
thus, the reason year is also a parameter.
|
||||||
|
*/
|
||||||
|
unsigned daysPerMonth(unsigned m, unsigned y) const;
|
||||||
|
|
||||||
|
/* Returns the name of a given month
|
||||||
|
- e.g. name(12) returns the string "December"
|
||||||
|
*/
|
||||||
|
string name(unsigned m) const;
|
||||||
|
|
||||||
|
/* Returns the number of a given named month
|
||||||
|
- e.g. number("March") returns 3
|
||||||
|
*/
|
||||||
|
unsigned number(const string &mn) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Implement the Date member functions here
|
||||||
|
Date::Date() {
|
||||||
|
this->day = 1;
|
||||||
|
this->month = 1;
|
||||||
|
this->year = 2000;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Date::isLeap(unsigned y) const {
|
||||||
|
return ((y % 4 == 0 && y % 100 != 0) || y % 400 == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned Date::daysPerMonth(unsigned m, unsigned y) const {
|
||||||
|
const unsigned int ODD_MONTHS[] = {1, 3, 5, 7, 8, 10, 12};
|
||||||
|
const unsigned int EVEN_MONTHS[] = {4, 6, 9, 11};
|
||||||
|
|
||||||
|
if (find(begin(ODD_MONTHS), end(ODD_MONTHS), m) != end(ODD_MONTHS)) {
|
||||||
|
return 31;
|
||||||
|
}
|
||||||
|
if (find(begin(EVEN_MONTHS), end(EVEN_MONTHS), m) != end(EVEN_MONTHS)) {
|
||||||
|
return 30;
|
||||||
|
}
|
||||||
|
|
||||||
|
// leap year
|
||||||
|
if (this->isLeap(y)) {
|
||||||
|
return 29;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 28;
|
||||||
|
};
|
||||||
|
|
||||||
|
string Date::name(unsigned m) const {
|
||||||
|
unordered_map<unsigned int, string> months;
|
||||||
|
|
||||||
|
months[1] = "January";
|
||||||
|
months[2] = "February";
|
||||||
|
months[3] = "March";
|
||||||
|
months[4] = "April";
|
||||||
|
months[5] = "May";
|
||||||
|
months[6] = "June";
|
||||||
|
months[7] = "July";
|
||||||
|
months[8] = "August";
|
||||||
|
months[9] = "September";
|
||||||
|
months[10] = "October";
|
||||||
|
months[11] = "November";
|
||||||
|
months[12] = "December";
|
||||||
|
|
||||||
|
try {
|
||||||
|
return (months.at(m));
|
||||||
|
} catch (std::out_of_range const &) {
|
||||||
|
return "NONE";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
unsigned Date::number(const string &mn) const {
|
||||||
|
string mnLowered = mn;
|
||||||
|
mnLowered.at(0) = tolower(mn.at(0));
|
||||||
|
|
||||||
|
unordered_map<string, unsigned int> months;
|
||||||
|
|
||||||
|
months["january"] = 1;
|
||||||
|
months["february"] = 2;
|
||||||
|
months["march"] = 3;
|
||||||
|
months["april"] = 4;
|
||||||
|
months["may"] = 5;
|
||||||
|
months["june"] = 6;
|
||||||
|
months["july"] = 7;
|
||||||
|
months["august"] = 8;
|
||||||
|
months["september"] = 9;
|
||||||
|
months["october"] = 10;
|
||||||
|
months["november"] = 11;
|
||||||
|
months["december"] = 12;
|
||||||
|
|
||||||
|
try {
|
||||||
|
return (months.at(mnLowered));
|
||||||
|
} catch (std::out_of_range const &) {
|
||||||
|
return 999;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Date::Date(unsigned m, unsigned d, unsigned y) {
|
||||||
|
this->day = d;
|
||||||
|
this->month = m;
|
||||||
|
this->year = y;
|
||||||
|
|
||||||
|
if (m < 1) {
|
||||||
|
this->month = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m > 12) {
|
||||||
|
this->month = 12;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (d < 1) {
|
||||||
|
this->day = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (d > this->daysPerMonth(this->month, y)) {
|
||||||
|
this->day = this->daysPerMonth(this->month, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->day != d || this->month != m || this->year != y) {
|
||||||
|
cout << "Invalid date values: Date corrected to " << this->month << "/"
|
||||||
|
<< this->day << "/" << this->year << "." << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Date::Date(const string &mn, unsigned d, unsigned y) {
|
||||||
|
Date date;
|
||||||
|
auto m = this->number(mn);
|
||||||
|
|
||||||
|
if (m != 999) {
|
||||||
|
date = Date(m, d, y);
|
||||||
|
this->day = date.day;
|
||||||
|
this->month = date.month;
|
||||||
|
this->year = date.year;
|
||||||
|
} else {
|
||||||
|
cout << "Invalid month name: the Date was set to 1/1/2000." << endl;
|
||||||
|
this->day = 1;
|
||||||
|
this->month = 1;
|
||||||
|
this->year = 2000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Date::printNumeric() const {
|
||||||
|
cout << this->month << "/" << this->day << "/" << this->year;
|
||||||
|
};
|
||||||
|
|
||||||
|
void Date::printAlpha() const {
|
||||||
|
cout << this->name(this->month) << " " << this->day << ", " << this->year;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Don't change the code below this line.
|
||||||
|
// You may comment them out if you want to build your own test harness
|
||||||
|
// while in develope mode, but you will need these to pass tets in submit mode.
|
||||||
|
|
||||||
|
Date getDate();
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
|
||||||
|
Date testDate;
|
||||||
|
testDate = getDate();
|
||||||
|
cout << endl;
|
||||||
|
cout << "Numeric: ";
|
||||||
|
testDate.printNumeric();
|
||||||
|
cout << endl;
|
||||||
|
cout << "Alpha: ";
|
||||||
|
testDate.printAlpha();
|
||||||
|
cout << endl;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Date getDate() {
|
||||||
|
int choice;
|
||||||
|
unsigned monthNumber, day, year;
|
||||||
|
string monthName;
|
||||||
|
|
||||||
|
cout << "Which Date constructor? (Enter 1, 2, or 3)" << endl
|
||||||
|
<< "1 - Month Number" << endl
|
||||||
|
<< "2 - Month Name" << endl
|
||||||
|
<< "3 - default" << endl;
|
||||||
|
cin >> choice;
|
||||||
|
cout << endl;
|
||||||
|
|
||||||
|
if (choice == 1) {
|
||||||
|
cout << "month number? ";
|
||||||
|
cin >> monthNumber;
|
||||||
|
cout << endl;
|
||||||
|
cout << "day? ";
|
||||||
|
cin >> day;
|
||||||
|
cout << endl;
|
||||||
|
cout << "year? ";
|
||||||
|
cin >> year;
|
||||||
|
cout << endl;
|
||||||
|
return Date(monthNumber, day, year);
|
||||||
|
} else if (choice == 2) {
|
||||||
|
cout << "month name? ";
|
||||||
|
cin >> monthName;
|
||||||
|
cout << endl;
|
||||||
|
cout << "day? ";
|
||||||
|
cin >> day;
|
||||||
|
cout << endl;
|
||||||
|
cout << "year? ";
|
||||||
|
cin >> year;
|
||||||
|
cout << endl;
|
||||||
|
return Date(monthName, day, year);
|
||||||
|
} else {
|
||||||
|
return Date();
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue