diff --git a/01 Training road maps/05_ICPC_Training-The_Contest-1-Concerns.pdf b/01 Training road maps/05_ICPC_Training-The_Contest-1-Concerns.pdf new file mode 100644 index 0000000..c8362e1 Binary files /dev/null and b/01 Training road maps/05_ICPC_Training-The_Contest-1-Concerns.pdf differ diff --git a/01 Training road maps/06_ICPC_Training-The_Contest-2-Strategies.pdf b/01 Training road maps/06_ICPC_Training-The_Contest-2-Strategies.pdf new file mode 100644 index 0000000..3f7e2b2 Binary files /dev/null and b/01 Training road maps/06_ICPC_Training-The_Contest-2-Strategies.pdf differ diff --git a/01 Training road maps/07_ICPC_Training-The_Contest-3-Trends.pdf b/01 Training road maps/07_ICPC_Training-The_Contest-3-Trends.pdf new file mode 100644 index 0000000..0ee4154 Binary files /dev/null and b/01 Training road maps/07_ICPC_Training-The_Contest-3-Trends.pdf differ diff --git a/01 Training road maps/ICPC_Community-Building_and_Training.pdf b/01 Training road maps/ICPC_Community-Building_and_Training.pdf new file mode 100644 index 0000000..e4272f5 Binary files /dev/null and b/01 Training road maps/ICPC_Community-Building_and_Training.pdf differ diff --git a/01 Training road maps/ICPC_Community-Egyptian_Case_Studies.pdf b/01 Training road maps/ICPC_Community-Egyptian_Case_Studies.pdf new file mode 100644 index 0000000..47cb29b Binary files /dev/null and b/01 Training road maps/ICPC_Community-Egyptian_Case_Studies.pdf differ diff --git a/06 String Processing/String_Processing_Rolling_Hash.cpp b/06 String Processing/String_Processing_Rolling_Hash.cpp new file mode 100644 index 0000000..0acc364 --- /dev/null +++ b/06 String Processing/String_Processing_Rolling_Hash.cpp @@ -0,0 +1,141 @@ +#include +using namespace std; + +#define all(v) ((v).begin()), ((v).end()) +#define sz(v) ((int)((v).size())) +#define clr(v, d) memset(v, d, sizeof(v)) +#define rep(i, v) for(int i=0;i=(int)(n);--i) +typedef long long ll; + +/* + Another base, in case needed. + + #define BASE 53ll + #define BASE_INV 682323657ll // pow(BASE, MOD-2)%MOD + System.out.println(BigInteger.probablePrime(35, new Random())); + + (MOD-1)^2 and (MOD-1)*BASE_INV MUST fit in your data type(E.g. ll) + + + bases 33, 37, 39, or 41 are pretty good for dictionary strings (< 7 collisions) + */ + +#define MOD 2000000011ll +#define BASE 53ll +#define BASE_INV 1283018875ll // pow(BASE, MOD-2)%MOD + +ll fastpow(ll num, ll p) { + if (p == 0) + return 1; + if (p % 2) + return (num % MOD * fastpow(num, p - 1)) % MOD; + ll a = fastpow(num, p / 2); + return (a * a) % MOD; +} + +ll removeAt(ll code, int idx, int val) { + return (code - (val * fastpow(BASE, idx)) % MOD + MOD) % MOD; +} + +ll addAt(ll code, int idx, int val) { + return (code + (val * fastpow(BASE, idx)) % MOD) % MOD; +} + +ll shiftLeft(ll code) { + return (code * BASE) % MOD; +} + +ll shiftRight(ll code) { + return (code * BASE_INV) % MOD; +} + +/////////////////////////////////////////////////////////////////////////// +// better reduce chars values by reindexing +int val(char c) { + return c; // no reduction + return 1 + islower(c) ? c - 'a' : c - 'A' + 26; +} + +ll getHashValue1(string pat) { + ll patCode = 0; + for (int i = 0; i < (int) pat.size(); ++i) { + patCode = patCode * BASE; // left shift + patCode += val(pat[i]); // add value + patCode %= MOD; // mod to avoid overflow + } + return patCode; +} + +ll getHashValue2(string pat) { + ll patCode = 0; + for (int i = 0; i < (int) pat.size(); ++i) { + patCode = shiftLeft(patCode); + patCode = addAt(patCode, 0, val(pat[i])); + } + return patCode; +} + +/////////////////////////////////////////////////////////////////////////// + +void pattern_search(string main, string pat) { + int n = pat.size(); + ll patCode = 0; + for (int i = 0; i < (int) pat.size(); ++i) { + patCode = shiftLeft(patCode); + patCode = addAt(patCode, 0, val(pat[i])); + } + + ll subCode = 0; + string subStr; + for (int i = 0; i < (int) main.size(); ++i) { + if (i - n >= 0) { + subCode = removeAt(subCode, n - 1, val(main[i - n])); + subStr.erase(subStr.end() - 1); + } + subCode = shiftLeft(subCode); + subCode = addAt(subCode, 0, val(main[i])); + subStr.insert(subStr.begin(), main[i]); + if (patCode == subCode) + cout << subCode << "\t" << subStr << "\n"; + } +} + + // return lowest suffix index that is palindrome + int longestSuffixPalindrome(string str) { + int n = str.size(), longestSuffix = 0; + ll strCode = 0, strRevCode = 0; + + // start from end, find longest suffix = reverse of suffix + for (int i = n - 1, len = 0; i >= 0; --i, ++len) { + strCode = shiftLeft(strCode); + strCode = addAt(strCode, 0, str[i]); + //Note, next is not so efficient, as we compute pow each step + strRevCode = addAt(strRevCode, len, str[i]); + + if (strCode == strRevCode) + longestSuffix = n - i; + } + return longestSuffix; + } + + int main() { + #ifndef ONLINE_JUDGE + freopen("test.txt", "rt", stdin); + #endif + + string str; + while (getline(cin, str)) { + + int longestSuffix = longestSuffixPalindrome(str); + + cout<= 0; i--) + cout< +#include +using namespace std; + +#define all(v) ((v).begin()), ((v).end()) +#define sz(v) ((int)((v).size())) +#define clr(v, d) memset(v, d, sizeof(v)) +#define rep(i, v) for(int i=0;i=(int)(n);--i) +typedef long long ll; + +void buildSuffixArraySlow(string str) { + map suffix_idx_map; + vector suffixes; + + for (int i = 0; i <= (int) str.size(); i++) { + string suffix = str.substr(i, str.size() - i); + suffix_idx_map[suffix] = i; + suffixes.push_back(suffix); + } + sort(suffixes.begin(), suffixes.end()); + for (int i = 0; i < (int) suffixes.size(); i++) + cout << suffixes[i] << "\t" << suffix_idx_map[suffixes[i]] << "\n"; +} + +//////////////////////////////////////////////////// +//////////////////////////////////////////////////// + +// Use N_LOGN_LOGN and N_LOGN to switch between 2 codes if needed + +const int MAXLENGTH = 5000; + +char str[MAXLENGTH + 1]; //the string we are building its suffix array +int suf[MAXLENGTH + 1];//the sorted array of suffix indices +int group[MAXLENGTH + 1];//In ith iteration: what is the group of the suffix index +int sorGroup[MAXLENGTH + 1];//temp array to build grouping of ith iteration + +struct comp//compare to suffixes on the first 2h chars +{ + int h; + comp(int h) + : h(h) { + } + + bool operator()(int i, int j) { + if (group[i] != group[j]) // previous h-groups are different + return group[i] < group[j]; + return group[i + h] < group[j + h]; + } +}; + +void print_suffix(int suf_pos, int n) { + for (int j = suf_pos; j < n - 1; ++j) // n-1 is string length NOT n + cout << str[j]; +} + +void buildSuffixArray() { + int n; //number of suffixes = 1+strlen(str) + //Initially assume that the group index is the ASCII + for (n = 0; n - 1 < 0 || str[n - 1]; n++) + suf[n] = n, group[n] = str[n];//code of the first char in the suffix + + sort(suf, suf + n, comp(0));//sort the array the suf on the first char only + sorGroup[0] = sorGroup[n - 1] = 0; + + //loop until the number of groups=number of suffixes + for (int h = 1; sorGroup[n - 1] != n - 1; h <<= 1) { + sort(suf, suf + n, comp(h)); //sort the array using the first 2h chars + + for (int i = 1; i < n; i++)//compute the 2h group data given h group data + sorGroup[i] = sorGroup[i - 1] + comp(h)(suf[i - 1], suf[i]); + + for (int i = 0; i < n; i++)//copy the computed groups to the group array + group[suf[i]] = sorGroup[i]; + + + if (true) { // For print + for (int i = 0; i < n; i++) { + print_suffix(suf[i], n); + + cout << "\t" << suf[i] << "\n"; + } + cout << "\n"; + } + } +} + +int main() { +#ifndef ONLINE_JUDGE + freopen("test.txt", "rt", stdin); +#endif + + cin >> str; // aaabaca + buildSuffixArray(); + + return 0; +} diff --git a/06 String Processing/String_Processing_Suffix_Array_1_O(nlognlogn).pdf b/06 String Processing/String_Processing_Suffix_Array_1_O(nlognlogn).pdf new file mode 100644 index 0000000..0a49a4a Binary files /dev/null and b/06 String Processing/String_Processing_Suffix_Array_1_O(nlognlogn).pdf differ diff --git a/06 String Processing/String_Processing_Suffix_Array_2_O(nlogn).cpp b/06 String Processing/String_Processing_Suffix_Array_2_O(nlogn).cpp new file mode 100644 index 0000000..2241a42 --- /dev/null +++ b/06 String Processing/String_Processing_Suffix_Array_2_O(nlogn).cpp @@ -0,0 +1,174 @@ +// Suffix array algorithms (nlognlog and nlogn) are from my coach Mohamed Abd Wahab, aka Fegla + +#include +#include +using namespace std; + +#define all(v) ((v).begin()), ((v).end()) +#define sz(v) ((int)((v).size())) +#define clr(v, d) memset(v, d, sizeof(v)) +#define rep(i, v) for(int i=0;i=(int)(n);--i) +typedef long long ll; + +void buildSuffixArraySlow(string str) { + map suffix_idx_map; + vector suffixes; + + for (int i = 0; i <= (int) str.size(); i++) { + string suffix = str.substr(i, str.size() - i); + suffix_idx_map[suffix] = i; + suffixes.push_back(suffix); + } + sort(suffixes.begin(), suffixes.end()); + for (int i = 0; i < (int) suffixes.size(); i++) + cout << suffixes[i] << "\t" << suffix_idx_map[suffixes[i]] << "\n"; +} + +//////////////////////////////////////////////////// +//////////////////////////////////////////////////// + +// Use N_LOGN_LOGN and N_LOGN to switch between 2 codes if needed + +//#define N_LOGN_LOGN +#ifdef N_LOGN_LOGN + +const int MAXLENGTH = 5000; + +char str[MAXLENGTH + 1]; //the string we are building its suffix array +int suf[MAXLENGTH + 1];//the sorted array of suffix indices +int group[MAXLENGTH + 1];//In ith iteration: what is the group of the suffix index +int sorGroup[MAXLENGTH + 1];//temp array to build grouping of ith iteration + +struct comp//compare to suffixes on the first 2h chars +{ + int h; + comp(int h) + : h(h) { + } + + bool operator()(int i, int j) { + if (group[i] != group[j]) // previous h-groups are different + return group[i] < group[j]; + return group[i + h] < group[j + h]; + } +}; + +void buildSuffixArray() { + int n; //number of suffixes = 1+strlen(str) + //Initially assume that the group index is the ASCII + for (n = 0; n - 1 < 0 || str[n - 1]; n++) + suf[n] = n, group[n] = str[n];//code of the first char in the suffix + + sort(suf, suf + n, comp(0));//sort the array the suf on the first char only + sorGroup[0] = sorGroup[n - 1] = 0; + + //loop until the number of groups=number of suffixes + for (int h = 1; sorGroup[n - 1] != n - 1; h <<= 1) { + + sort(suf, suf + n, comp(h)); //sort the array using the first 2h chars + + for (int i = 1; i < n; i++)//compute the 2h group data given h group data + sorGroup[i] = sorGroup[i - 1] + comp(h)(suf[i - 1], suf[i]); + + for (int i = 0; i < n; i++)//copy the computed groups to the group array + group[suf[i]] = sorGroup[i]; + } +} + +#endif + +#define N_LOGN +#ifdef N_LOGN + +//////////////////////////////////////////////////// +//////////////////////////////////////////////////// + +const int MAXLENGTH = 2 * 100 * 1000 + 9; +char str[MAXLENGTH + 1]; //the string we are building its suffix array +int suf[MAXLENGTH + 1]; // the sorted array of suffix indices +int group[MAXLENGTH + 1]; //In ith iteration: what is the group of the suffix index +int sorGroup[MAXLENGTH + 1 < 128 ? 128 : MAXLENGTH + 1]; //temp array to build grouping of ith iteration + +int groupStart[MAXLENGTH + 1]; //the start index in the sorted array of the current group +int newSuf[MAXLENGTH + 1]; //temp array to store in it the new sorted array +int n; //number of suffixes + +void print_suffix(int suf_pos) { + for (int j = suf_pos; j < n - 1; ++j) // n-1 is string length NOT n + cout << str[j]; +} + +void buildSuffixArray() { + + n = 0; + memset(sorGroup, -1, (sizeof sorGroup[0]) * 128); + + //bucket sort on the first char of suffix + for (n = 0; n - 1 < 0 || str[n - 1]; n++) + //treat sorGroup as head of linked list and newSuf as next + newSuf[n] = sorGroup[str[n]], sorGroup[str[n]] = n; + + int numGroup = -1, j = 0; + for (int i = 0; i < 128; i++) { + //compute the groups and groupStart and starting suf + if (sorGroup[i] != -1) { + groupStart[++numGroup] = j; + int cur = sorGroup[i]; // cur = head + + while (cur != -1) { + suf[j++] = cur; + group[cur] = numGroup; + cur = newSuf[cur]; // cur->next + } + } + } + + sorGroup[0] = sorGroup[n - 1] = 0; //assume that the first group index 0 for next iteration; + newSuf[0] = suf[0]; //put the empty suffix to be the smallest suffix + + //loop until the number of groups=number of suffixes + for (int h = 1; sorGroup[n - 1] != n - 1; h <<= 1) { + if (true) { // For print + for (int i = 0; i < n; i++) { + print_suffix(suf[i]); + + cout << "\t" << suf[i] << "\t" << group[suf[i]] << "\t" << groupStart[group[suf[i]]] << "\n"; + } + cout << "\n"; + } + for (int i = 0; i < n; i++) { //sort using 2h in the array newSuf + int j = suf[i] - h; + if (j < 0) + continue; + newSuf[groupStart[group[j]]++] = j; + } + for (int i = 1; i < n; i++) { //compute the 2h group data given h group data + bool newgroup = group[newSuf[i - 1]] < group[newSuf[i]] || (group[newSuf[i - 1]] == group[newSuf[i]] && group[newSuf[i - 1] + h] < group[newSuf[i] + h]); + + sorGroup[i] = sorGroup[i - 1] + newgroup; + if (newgroup) + groupStart[sorGroup[i]] = i; + } + for (int i = 0; i < n; i++) { //copy the data + suf[i] = newSuf[i]; + group[suf[i]] = sorGroup[i]; + } + } +} + +#endif + + +int main() { +#ifndef ONLINE_JUDGE + freopen("test.txt", "rt", stdin); +#endif + + cin >> str; // aaabaca + buildSuffixArray(); + + return 0; +} diff --git a/06 String Processing/String_Processing_Suffix_Array_2_O(nlogn).pdf b/06 String Processing/String_Processing_Suffix_Array_2_O(nlogn).pdf new file mode 100644 index 0000000..d4b1cbd Binary files /dev/null and b/06 String Processing/String_Processing_Suffix_Array_2_O(nlogn).pdf differ diff --git a/06 String Processing/String_Processing_Suffix_Array_3_LCP.cpp b/06 String Processing/String_Processing_Suffix_Array_3_LCP.cpp new file mode 100644 index 0000000..7bc8abf --- /dev/null +++ b/06 String Processing/String_Processing_Suffix_Array_3_LCP.cpp @@ -0,0 +1,300 @@ +// Suffix array algorithms (nlognlog and nlogn) are from my coach Mohamed Abd Wahab, aka Fegla + +#include +#include +using namespace std; + +#define all(v) ((v).begin()), ((v).end()) +#define sz(v) ((int)((v).size())) +#define clr(v, d) memset(v, d, sizeof(v)) +#define rep(i, v) for(int i=0;i=(int)(n);--i) +typedef long long ll; + +void buildSuffixArraySlow(string str) { + map suffix_idx_map; + vector suffixes; + + for (int i = 0; i <= (int) str.size(); i++) { + string suffix = str.substr(i, str.size() - i); + suffix_idx_map[suffix] = i; + suffixes.push_back(suffix); + } + sort(suffixes.begin(), suffixes.end()); + for (int i = 0; i < (int) suffixes.size(); i++) + cout << suffixes[i] << "\t" << suffix_idx_map[suffixes[i]] << "\n"; +} + +//////////////////////////////////////////////////// +//////////////////////////////////////////////////// + +// Use N_LOGN_LOGN and N_LOGN to switch between 2 codes if needed + +//#define N_LOGN_LOGN +#ifdef N_LOGN_LOGN + +const int MAXLENGTH = 5000; + +char str[MAXLENGTH + 1]; //the string we are building its suffix array +int suf[MAXLENGTH + 1];//the sorted array of suffix indices +int group[MAXLENGTH + 1];//In ith iteration: what is the group of the suffix index +int sorGroup[MAXLENGTH + 1];//temp array to build grouping of ith iteration + +struct comp//compare to suffixes on the first 2h chars +{ + int h; + comp(int h) + : h(h) { + } + + bool operator()(int i, int j) { + if (group[i] != group[j]) // previous h-groups are different + return group[i] < group[j]; + return group[i + h] < group[j + h]; + } +}; + +void buildSuffixArray() { + int n; //number of suffixes = 1+strlen(str) + //Initially assume that the group index is the ASCII + for (n = 0; n - 1 < 0 || str[n - 1]; n++) + suf[n] = n, group[n] = str[n];//code of the first char in the suffix + + sort(suf, suf + n, comp(0));//sort the array the suf on the first char only + sorGroup[0] = sorGroup[n - 1] = 0; + + //loop until the number of groups=number of suffixes + for (int h = 1; sorGroup[n - 1] != n - 1; h <<= 1) { + + sort(suf, suf + n, comp(h)); //sort the array using the first 2h chars + + for (int i = 1; i < n; i++)//compute the 2h group data given h group data + sorGroup[i] = sorGroup[i - 1] + comp(h)(suf[i - 1], suf[i]); + + for (int i = 0; i < n; i++)//copy the computed groups to the group array + group[suf[i]] = sorGroup[i]; + } +} + +#endif + +#define N_LOGN +#ifdef N_LOGN + +//////////////////////////////////////////////////// +//////////////////////////////////////////////////// + +const int MAXLENGTH = 2 * 100 * 1000 + 9; +char str[MAXLENGTH + 1]; //the string we are building its suffix array +int suf[MAXLENGTH + 1]; // the sorted array of suffix indices +int group[MAXLENGTH + 1]; //In ith iteration: what is the group of the suffix index +int sorGroup[MAXLENGTH + 1 < 128 ? 128 : MAXLENGTH + 1]; //temp array to build grouping of ith iteration + +int groupStart[MAXLENGTH + 1]; //the start index in the sorted array of the current group +int newSuf[MAXLENGTH + 1]; //temp array to store in it the new sorted array +int n; //number of suffixes + +void print_suffix(int suf_pos) { + for (int j = suf_pos; j < n - 1; ++j) // n-1 is string length NOT n + cout << str[j]; +} + +void buildSuffixArray() { + + n = 0; + memset(sorGroup, -1, (sizeof sorGroup[0]) * 128); + + //bucket sort on the first char of suffix + for (n = 0; n - 1 < 0 || str[n - 1]; n++) + //treat sorGroup as head of linked list and newSuf as next + newSuf[n] = sorGroup[str[n]], sorGroup[str[n]] = n; + + int numGroup = -1, j = 0; + for (int i = 0; i < 128; i++) { + //compute the groups and groupStart and starting suf + if (sorGroup[i] != -1) { + groupStart[++numGroup] = j; + int cur = sorGroup[i]; // cur = head + + while (cur != -1) { + suf[j++] = cur; + group[cur] = numGroup; + cur = newSuf[cur]; // cur->next + } + } + } + + sorGroup[0] = sorGroup[n - 1] = 0; //assume that the first group index 0 for next iteration; + newSuf[0] = suf[0]; //put the empty suffix to be the smallest suffix + + //loop until the number of groups=number of suffixes + for (int h = 1; sorGroup[n - 1] != n - 1; h <<= 1) { + if (false) { // For print + for (int i = 0; i < n; i++) { + print_suffix(suf[i]); + + cout << "\t" << suf[i] << "\t" << group[suf[i]] << "\t" << groupStart[group[suf[i]]] << "\n"; + } + cout << "\n"; + } + for (int i = 0; i < n; i++) { //sort using 2h in the array newSuf + int j = suf[i] - h; + if (j < 0) + continue; + newSuf[groupStart[group[j]]++] = j; + } + for (int i = 1; i < n; i++) { //compute the 2h group data given h group data + bool newgroup = group[newSuf[i - 1]] < group[newSuf[i]] || (group[newSuf[i - 1]] == group[newSuf[i]] && group[newSuf[i - 1] + h] < group[newSuf[i] + h]); + + sorGroup[i] = sorGroup[i - 1] + newgroup; + if (newgroup) + groupStart[sorGroup[i]] = i; + } + for (int i = 0; i < n; i++) { //copy the data + suf[i] = newSuf[i]; + group[suf[i]] = sorGroup[i]; + } + } +} + +#endif + +int Rank[MAXLENGTH + 1]; +int lcp[MAXLENGTH + 1]; + +void buildLcp() { + //compute the rank of each suffix + for (int i = 0; i - 1 < 0 || str[i - 1]; i++) + Rank[suf[i]] = i; + + int c = 0; // the length of lcp between i and j + for (int i = 0; i - 1 < 0 || str[i - 1]; i++) { + if (Rank[i]) { //if i is not the first suffix in the sorted array + int j = suf[Rank[i] - 1]; //find the element before i and name it j + while (str[i + c] == str[j + c]) + c++; //count the number of shared chars + } + lcp[Rank[i]] = c; //store the result in lcp array + if (c) + c--; //Decrement c by one because length of lcp of i+1 is c-1 + } + if (false) { + for (int i = 0; i < n; i++) { + print_suffix(suf[i]); + cout << "\t" << suf[i] << "\t" << Rank[i] << "\t" << lcp[i] << "\n"; + } + } +} + +/////////////////////////////////////////////////////////////////////////////// +char pat[MAXLENGTH + 1]; + +void find_patterns_queries() { + cin >> str; + buildSuffixArray(); + cout << "\n**************************************\n\n"; + + start_again: + // Src: http://www.geeksforgeeks.org/suffix-array-set-1-introduction/ + while (cin >> pat) { // O(mLogn) + int m = strlen(pat); // get length of pattern, needed for strncmp() + + int l = 0, r = n - 1; + while (l <= r) { + // See if 'pat' is prefix of middle suffix in suffix array + int mid = l + (r - l) / 2; + int res = strncmp(pat, str + suf[mid], m); + + if (res == 0) { + cout << "Pattern found at suffix: ["; + print_suffix(suf[mid]); + cout << "]\n"; + goto start_again; + } + // Move to left or right based on string comparison results + if (res < 0) + r = mid - 1; + else + l = mid + 1; + } + // We reach here if return statement in loop is not executed + cout << "Pattern not found\n"; + } + exit(0); +} + +void smallest_lexicographically() { + cin >> str; + int n = strlen(str); + + for (int i = 0; i < n; ++i) // Concatenate + str[i + n] = str[i]; + str[2 * n] = 0; + + buildSuffixArray(); + buildLcp(); + + // cases: aa is tricky. Fail if used <= n NOT <= 2*n + // Ass the first string suffixes are all in 2nd part of array + for (int i = 0; i <= 2*n; ++i) { + if (suf[i] < n) { // from suffixes of 1st string + while (lcp[i + 1] >= n) + ++i; // last one of common prefix will have smallest index + cout << suf[i] << "\n"; + break; + } + } + + /* + int lexi_tie_first = -1; + for (int i = 0; i <= 2*n; ++i) { + if (suf[i] >= n) { + if (lexi_tie_first == -1) + continue; // from 2nd concatenated string + else + break; + } + if (lexi_tie_first == -1) + lexi_tie_first = suf[i]; // we found 1 + else if (lcp[i] >= n) // another one of our n letters + lexi_tie_first = min(lexi_tie_first, suf[i]); // we found 1 + else + break; // we have already the smallest one + } + cout << lexi_tie_first << "\n"; + */ +} + +//Modification of Lyndon decomposition: The concatenation will have in between one of si +//that is less than reminder +int min_cyclic_shift(string s) { + s += s; + int n = sz(s), i = 0, ans = 0; + while (i < n / 2) { + ans = i; + int j = i + 1, k = i; + while (j < n && s[k] <= s[j]) { + if (s[k] < s[j]) + k = i; + else + ++k; + ++j; + } + while (i <= k) + i += j - k; + } + //solution is in s.substr (ans, n/2) + return ans; //0-based idx of position where rotating string cause it lexico +} + +int main() { +#ifndef ONLINE_JUDGE + freopen("test.txt", "rt", stdin); +#endif + + smallest_lexicographically(); + + return 0; +} diff --git a/06 String Processing/String_Processing_Suffix_Array_3_LCP.pdf b/06 String Processing/String_Processing_Suffix_Array_3_LCP.pdf new file mode 100644 index 0000000..f24d7cb Binary files /dev/null and b/06 String Processing/String_Processing_Suffix_Array_3_LCP.pdf differ diff --git a/06 String Processing/String_Processing_Suffix_Array_4_Examples.pdf b/06 String Processing/String_Processing_Suffix_Array_4_Examples.pdf new file mode 100644 index 0000000..1498848 Binary files /dev/null and b/06 String Processing/String_Processing_Suffix_Array_4_Examples.pdf differ diff --git a/07 Dynamic Programming/Algorithms - Dynamic Programming - 07 - Counting/10617 0.004.cpp b/07 Dynamic Programming/Algorithms - Dynamic Programming - 07 - Counting/10617 0.004.cpp new file mode 100644 index 0000000..de5da2c --- /dev/null +++ b/07 Dynamic Programming/Algorithms - Dynamic Programming - 07 - Counting/10617 0.004.cpp @@ -0,0 +1,85 @@ +#include +#include +using namespace std; + +// Solves computes number of ways to cross out characters in a string +// so that the remaining characters form a palindrome. + +// This programme uses dynamic programming. Some tried to solve the +// problem by brute force, but their programmes ran for too long, in +// spite of the fact that the longest input word was only 19 characters. + +long long A[1001][1001]; +// For i<=j, A[i,j] will hold the number of palindromes +// that can be formed from the substring a[i..j] by +// crossing out some characters +long long B[1001][1001]; +// For i<=j, B[i,j] will hold the number of palindromes +// that can be formed from the substring a[i..j] by +// crossing out some characters, not including a[i]. +// (i.e. not allowed to cross out a[i]) + +// Note: for the above definition, I count the empty string as a +// palindrome. However, the problem says the empty string is not a +// palindrome, so when I output the answer in the last line of the big +// loop, I subtract 1 from A[0,m-1]. + +int main() +{ + long long n; + char a[100]; + + cin>>n; + + for (int ix = 1; ix <= n; ix++) + { + cin>>a; + + int m=strlen(a); + + for (int j=0; j +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +using namespace std; + +#define all(v) ((v).begin()), ((v).end()) +#define sz(v) ((int)((v).size())) +#define clr(v, d) memset(v, d, sizeof(v)) +#define repi(i, j, n) for(int i=(j);i<(int)(n);++i) +#define repd(i, j, n) for(int i=(j);i>=(int)(n);--i) +#define repa(v) repi(i, 0, sz(v)) repi(j, 0, sz(v[i])) +#define rep(i, v) repi(i, 0, sz(v)) +#define lp(i, cnt) repi(i, 0, cnt) +#define lpi(i, s, cnt) repi(i, s, cnt) +#define P(x) cout<<#x<<" = { "< vi; +typedef vector vd; +typedef vector< vi > vvi; +typedef vector< vd > vvd; +typedef vector vs; +typedef long long ll; +typedef long double ld; + +const int OO = (int)1e8; //Small -> WRONG, Large -> OVERFLOW + +const double PI = acos(-1.0); +const double EPS = (1e-7); + +int dcmp(double x, double y) { return fabs(x-y) <= EPS ? 0 : x < y ? -1 : 1; } + +string str; +ll memo[100][100]; + +ll best(int i, int j) { + if(i == j) return 1; + if(i+1 == j) return 2 + (str[i] == str[j]); // handle length=2 as special case + + ll &ret = memo[i][j]; + if(ret != -1) return ret; + + ret = 0; + if(str[i] == str[j]) + ret += best(i+1, j-1) +1; // +1 for the container palindrome when body is empty + + ret += best(i+1, j); + ret += best(i, j-1); + ret -= best(i+1, j-1); // remove duplication of (i+1, j), (i, j-1) + + return ret; +} + +int main() +{ +#ifndef ONLINE_JUDGE + freopen("c.in", "rt", stdin); +#endif + + int cases; + cin>>cases; + + while(cases--) + { + cin>>str; + clr(memo, -1); + + cout< + + + + + + + + + + +Problem I - Again Palindromes + + + + + + + +
+ +

Problem I

+ +

Again Palindromes

+ +

Input: Standard Input

+ +

Output: Standard Output

+ +

Time Limit: 2 Seconds

+ +

 

+ +

A palindorme is a sequence of one or more characters that reads the same +from the left as it does from the right. For example, Z, TOT and MADAM +are palindromes, but ADAM is not.

+ +

 

+ +

Given a sequence S of N capital latin letters. How many ways +can one score out a few symbols (maybe 0) that the rest of sequence become a +palidrome. Varints that are only  +different by an order of scoring out should be considered the same.

+ +

 

+ +

Input

+ +

The input file contains several +test cases (less than 15). The first line contains an integer T +that indicates how many test cases are to follow.

+ +

 

+ +

Each of the T lines +contains a sequence S (1≤N≤60). So actually each of these +lines is a test case.

+ +

 

+ +

Output

+ +

For each test case output in a single line an integer – +the number of ways.

+ +
 
+ +

Sample Input                             Output for Sample Input

+ + + + + + +
+

3

+

BAOBAB

+

AAAA

+
ABA
+

22

+

15

+

5

+
+ + +
+ +
+ +
+ + +

Russian +Olympic Camp

+ +
+ + + + diff --git a/07 Dynamic Programming/Algorithms - Dynamic Programming - 07 - Counting/Note.txt b/07 Dynamic Programming/Algorithms - Dynamic Programming - 07 - Counting/Note.txt new file mode 100644 index 0000000..78571ea --- /dev/null +++ b/07 Dynamic Programming/Algorithms - Dynamic Programming - 07 - Counting/Note.txt @@ -0,0 +1 @@ +These codes are the ones used in the session. \ No newline at end of file diff --git a/07 Dynamic Programming/Algorithms - Dynamic Programming - 07 - Counting/meeda 10617.cpp b/07 Dynamic Programming/Algorithms - Dynamic Programming - 07 - Counting/meeda 10617.cpp new file mode 100644 index 0000000..4dd896d --- /dev/null +++ b/07 Dynamic Programming/Algorithms - Dynamic Programming - 07 - Counting/meeda 10617.cpp @@ -0,0 +1,65 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +using namespace std; +#define pb push_back +#define all(v) v.begin(),v.end() +#define sz size() +#define rep(i,m) for(int i=0;i pii; +typedef vector vpii; +typedef vector vs; +typedef vector vi; +typedef vector > vii; +typedef long long ll; +int oo=0x7FFFFFFF; +ll dp[60][60]; +char s[61]; +int n; +ll calc(int f,int t) +{ + if(dp[f][t]!=-1) + return dp[f][t]; + ll ret=1; + for(int i=f+1;i +#include +using namespace std; + +long long A[61][61]; +/* + * For i<=j, A[i,j] will hold the number of palindromes + * that can be formed from the substring a[i..j] by + * crossing out some characters, considering empty as pal + */ + +int main() +{ + int n; + char a[100]; + + cin>>n; + + while(n--) + { + cin>>a; + + int m=strlen(a); + + for (int j=0; j +using namespace std; + +// Original (elegant) source: http://codeforces.com/blog/entry/22072 +// Heavy-light Decomposition to compute max query on path: http://www.spoj.com/problems/QTREE/ + +const int N = 10000 + 9; +const int SEG_MAX = 32770 + 9; //L = Ceil(log2(V)). TREE_SIZE = 2 + (1<<(L+1)) +int interval[SEG_MAX]; +int mxV; // current # of tree nodes + +struct SegmentTree { // Range Max Query + int idx, val, from, to; + + void init(int n) { + mxV = n; + memset(interval, 0, n * sizeof(int)); + } + // Initialize idx & val before update + int update(int s = 0, int e = mxV, int p = 1) { + if (s == e) + return interval[p] = val; + int mid = (s + e) / 2; + if (idx <= mid) + update(s, (s + e) / 2, 2 * p); + else if (idx > mid) + update((s + e) / 2 + 1, e, 2 * p + 1); + return interval[p] = max(interval[2 * p], interval[2 * p + 1]); + } + // Initialize from & to before query + int query(int s = 0, int e = mxV, int p = 1) { + if (from <= s && to >= e) + return interval[p]; + int mid = (s + e) / 2; + if (to <= mid) + return query(s, (s + e) / 2, 2 * p); + if (from > mid) + return query((s + e) / 2 + 1, e, 2 * p + 1); + int a = query(s, (s + e) / 2, 2 * p); + int b = query((s + e) / 2 + 1, e, 2 * p + 1); + return max(a, b); + } +}; + +///////////////////////////////////////////////////////////////////////////////////// + +const int isValueOnEdge = 1; // switch to 0 for value on node +vector> tree; // undirected tree +// For values on edge +vector> treeEdgeIdx; +vector edge_to; // which end point used in directing the edge +vector edge_cost; + +struct HeavyLight { + int parent[N], depth[N], heavy[N], root[N], segTreePos[N]; + int queryRes; // e.g. max value on path + SegmentTree segTree; + + int dfs_hld(int v) { + int size = 1, maxSubtree = 0; + for (int k = 0; k < (int) tree[v].size(); ++k) { + int u = tree[v][k], edgeIdx = treeEdgeIdx[v][k]; + if (u != parent[v]) { + edge_to[edgeIdx] = u; + parent[u] = v, depth[u] = depth[v] + 1; + int childTreeSize = dfs_hld(u); + if (childTreeSize > maxSubtree) + heavy[v] = u, maxSubtree = childTreeSize; + size += childTreeSize; + } + } + return size; + } + void buildChains() { + int n = tree.size(); + memset(heavy, -1, n * sizeof(int)); + parent[0] = -1, depth[0] = 0; + dfs_hld(0); + + // Connect chains to its root. Map chain to segment tree part + for (int chainRoot = 0, pos = 0; chainRoot < n; ++chainRoot) { + if (parent[chainRoot] == -1 || heavy[parent[chainRoot]] != chainRoot) { + for (int j = chainRoot; j != -1; j = heavy[j]) // iterate on a chain + root[j] = chainRoot, segTreePos[j] = pos++; + } + } + segTree.init(n); + } + void queryChain(int l, int r) { + segTree.from = l, segTree.to = r; + queryRes = max(queryRes, segTree.query()); + } + int queryPath(int u, int v) { + queryRes = 0; // be careful from u = v for isValueOnEdge + for (; root[u] != root[v]; v = parent[root[v]]) { + if (depth[root[u]] > depth[root[v]]) + swap(u, v); + queryChain(segTreePos[root[v]], segTreePos[v]); + } + if (depth[u] > depth[v]) + swap(u, v); + if (!isValueOnEdge || u != v) + queryChain(segTreePos[u] + isValueOnEdge, segTreePos[v]); + return queryRes; // u = LCA node + } + // For value on DIRECTED edge (f, t, value), call update_node(t, value) + void updatePos(int treeNode, int value) { + segTree.idx = segTreePos[treeNode], segTree.val = value; + segTree.update(); + } +}; +///////////////////////////////////////////////////////////////////////////////////// + +int main() { +#ifndef ONLINE_JUDGE + freopen("test.txt", "rt", stdin); +#endif + int cases; + scanf("%d", &cases); + + HeavyLight hdl; + + for (int cc = 0; cc < cases; ++cc) { + int n; + scanf("%d", &n); + tree.clear(), edge_cost.clear(), treeEdgeIdx.clear(), edge_to.clear(); + tree.resize(n), edge_cost.resize(n), treeEdgeIdx.resize(n), edge_to.resize(n); + + for (int i = 0; i < n - 1; ++i) { + int f, t, c; + scanf("%d%d%d", &f, &t, &c); + + tree[f - 1].push_back(t - 1), tree[t - 1].push_back(f - 1); + treeEdgeIdx[f - 1].push_back(i), treeEdgeIdx[t - 1].push_back(i); + edge_cost[i] = c; + } + hdl.buildChains(); + for (int i = 0; i < n - 1; ++i) + hdl.updatePos(edge_to[i], edge_cost[i]); + + char s[100]; + while (scanf("%s", s) && s[0] != 'D') { + int a, b; + scanf("%d%d", &a, &b); + + if (s[0] != 'Q') + hdl.updatePos(edge_to[a - 1], b); + else + printf("%d\n", hdl.queryPath(a - 1, b - 1)); + } + } + return 0; +} diff --git a/09 Graph_Theory/Algorithms_Graph Theory_22_Heavy_light_decomposition_1.pdf b/09 Graph_Theory/Algorithms_Graph Theory_22_Heavy_light_decomposition_1.pdf new file mode 100644 index 0000000..f8a5190 Binary files /dev/null and b/09 Graph_Theory/Algorithms_Graph Theory_22_Heavy_light_decomposition_1.pdf differ diff --git a/11 Data Structures/Algorithms_Data_Structures_00_What_and_Why.pdf b/11 Data Structures/Algorithms_Data_Structures_00_What_and_Why.pdf new file mode 100644 index 0000000..8dca127 Binary files /dev/null and b/11 Data Structures/Algorithms_Data_Structures_00_What_and_Why.pdf differ diff --git a/11 Data Structures/Algorithms_Data_Structures_02_Queue_basic.cpp b/11 Data Structures/Algorithms_Data_Structures_02_Queue_basic.cpp deleted file mode 100644 index 2ebd536..0000000 --- a/11 Data Structures/Algorithms_Data_Structures_02_Queue_basic.cpp +++ /dev/null @@ -1,66 +0,0 @@ -#include -using namespace std; - - -const int MAX_SIZE = 5; - -class queue { -private: - int *qu, front, rear; -public: - queue() { - front = -1; - rear = -1; - qu = new int(MAX_SIZE); - } - - void push(int data); - int pop(); - bool IsFull(); - bool IsEmpty(); - void display(); -}; - -void queue::push(int d) { - if (IsFull()) { - cout << "\nNo more memory\n"; - exit(1); - } - qu[++rear] = d; -} - -int queue::pop() { - if (IsEmpty()) { - cout << "\nQueue is empty\n"; - exit(1); - } - return qu[++front]; -} - -bool queue::IsFull() { - return rear == MAX_SIZE - 1; -} - -bool queue::IsEmpty() { - return rear == front; -} - -void queue::display() { - while(!IsEmpty()) - cout< -using namespace std; -const int MAX_SIZE = 2; - -class MyQueue { -private: - int qu[MAX_SIZE], front, size; - -public: - MyQueue() { - front = 0; - size = 0; - } - void push(int data); - int pop(); - bool IsFull(); - bool IsEmpty(); - void display(); -}; - -void MyQueue::push(int d) { - - if(IsFull()) - { - cout<<"Error: Complete queue\n"; - assert(false); - } - - qu[(front+size)%MAX_SIZE] = d; - ++size; -} - -int MyQueue::pop() { - if (IsEmpty()) { - cout << "\Error: Empty queue\n"; - assert(false); - } - - int ret = qu[front]; - front = (front+1)%MAX_SIZE; - size--; - - return ret; -} - -void MyQueue::display() { - while(!IsEmpty()) - cout< +#include using namespace std; @@ -50,7 +51,7 @@ struct node{ } int balanceFactor(){ - return right->left - left->right; + return left->height - right->height; } }; @@ -116,3 +117,8 @@ node* insert(node* root, int val){ root = balance(root); return root; } + + +int main() { + return 0; +} diff --git a/16 Misc/Algorithms_Cumulative_(Prefix)_Sums.cpp b/16 Misc/Algorithms_Cumulative_(Prefix)_Sums.cpp new file mode 100644 index 0000000..ac5ad59 --- /dev/null +++ b/16 Misc/Algorithms_Cumulative_(Prefix)_Sums.cpp @@ -0,0 +1,102 @@ +#include +using namespace std; + +#define all(v) ((v).begin()), ((v).end()) +#define sz(v) ((int)((v).size())) +#define clr(v, d) memset(v, d, sizeof(v)) +#define repi(i, j, n) for(int i=(j);i<(int)(n);++i) +#define repd(i, j, n) for(int i=(j);i>=(int)(n);--i) +#define repa(v) repi(i, 0, sz(v)) repi(j, 0, sz(v[i])) +#define rep(i, v) repi(i, 0, sz(v)) +#define lp(i, cnt) repi(i, 0, cnt) +#define lpi(i, s, cnt) repi(i, s, cnt) +#define P(x) cout<<#x<<" = { "< vi; +typedef vector vd; +typedef vector vvi; +typedef vector vvd; +typedef vector vs; +typedef long long ll; +typedef long double ld; + +int sum_range1(int S, int E, vector & cum_sum) { + if (S == 0) + return cum_sum[E]; + + return cum_sum[E] - cum_sum[S - 1]; +} + +void zero_based() { + vector A = { 2, 1, 4, 5, 3, 7 }; + vector S(A.size(), 0); + + //pre-processing: Compute cumulative sum array + for (int i = 0; i < (int) A.size(); i++) + S[i] += (i == 0) ? A[i] : A[i] + S[i - 1]; + + cout << sum_range1(0, 5, S) << "\n"; + cout << sum_range1(1, 5, S) << "\n"; + cout << sum_range1(2, 4, S) << "\n"; +} + +int sum_range2(int S, int E, vector & cum_sum) { + return cum_sum[E] - cum_sum[S - 1]; +} + +void one_based() { + vector A = { 0, 2, 1, 4, 5, 3, 7 }; // let A[0] = 0 + vector S(A.size(), 0); + + //pre-processing: Compute cumulative sum array: Start from 1 + for (int i = 1; i < (int) A.size(); i++) + S[i] += A[i] + S[i - 1]; + + // 1-based queries + cout << sum_range1(1, 6, S) << "\n"; + cout << sum_range1(2, 6, S) << "\n"; + cout << sum_range1(3, 5, S) << "\n"; +} + + // sum((i, j) (k, l)) where (k, l) is the bottom right + int sum_range(int i, int j, int k, int l, vector> & S) { + return S[k][l] - S[k][j-1] - S[i-1][l] + S[i-1][j-1]; + } + + void accumSum2D() { + // 1-based matrix + // Append extra top row and col with zero + vector> A = + { { 0, 0, 0, 0, 0, 0 }, + { 0, 1, 2, 2, 4, 1 }, + { 0, 3, 4, 1, 5, 2 }, + { 0, 2, 3, 3, 2, 4 }, + { 0, 4, 1, 5, 4, 6 }, + { 0, 6, 3, 2, 1, 3 }, }; + + // Accumulate each row + for (int i = 1; i < (int) A.size(); i++) + for (int j = 1; j < (int) A[0].size(); j++) + A[i][j] += A[i][j-1]; + + // Accumulate each col + for (int j = 1; j < (int) A[0].size(); j++) + for (int i = 1; i < (int) A.size(); i++) + A[i][j] += A[i-1][j]; + + // 1, 5, 2 + // 3, 2, 4 + cout << sum_range(2, 3, 3, 5, A) << "\n"; + } + +int main() { +#ifndef ONLINE_JUDGE + freopen("test.txt", "rt", stdin); +#endif + + accumSum2D(); + + return 0; +} diff --git a/16 Misc/Algorithms_Cumulative_(Prefix)_Sums.pdf b/16 Misc/Algorithms_Cumulative_(Prefix)_Sums.pdf new file mode 100644 index 0000000..ff6c208 Binary files /dev/null and b/16 Misc/Algorithms_Cumulative_(Prefix)_Sums.pdf differ diff --git a/16 Misc/MO's_Algorithm.cpp b/16 Misc/MO's_Algorithm.cpp new file mode 100644 index 0000000..0bc6de9 --- /dev/null +++ b/16 Misc/MO's_Algorithm.cpp @@ -0,0 +1,87 @@ +#include +using namespace std; + +#define all(v) ((v).begin()), ((v).end()) +#define sz(v) ((int)((v).size())) +#define clr(v, d) memset(v, d, sizeof(v)) +#define rep(i, v) for(int i=0;i=(int)(n);--i) +typedef long long ll; + +const int INP_SIZE = 30000+9; +const int QUERIES_SIZE = 200000+9; +const int SQRTN = 175; // sqrt(INP_SIZE) + +struct query { + int l, r, q_idx, block_idx; + + query() {} + query(int _l, int _r, int _q_idx) { + l = _l - 1, r = _r - 1, q_idx = _q_idx, block_idx = _l / SQRTN; + } + bool operator <(const query &y) const { + if (block_idx != y.block_idx) + return block_idx < y.block_idx; + return r < y.r; + } +}; + +int n, m; // input size and queries +int inp[INP_SIZE], result = 0; +int q_ans[QUERIES_SIZE]; +query queries[QUERIES_SIZE]; + +// You need to update following data structure + // per problem (e.g. use mutliset) +int cnt[1000000 + 9]; + +// You need to update these 2 methods per a problem +void add(int idx) { + cnt[inp[idx]]++; + if (cnt[inp[idx]] == 3) + result++; +} + +void remove(int idx) { + cnt[inp[idx]]--; + if (cnt[inp[idx]] == 2) + result--; +} + +void process() { // don't change + sort(queries, queries+m); + + int curL = 1, curR = 0; // tricky initialization and indexing + for (int i = 0; i < m; i++) { + while (curL < queries[i].l) remove(curL++); + while (curL > queries[i].l) add(--curL); + while (curR < queries[i].r) add(++curR); + while (curR > queries[i].r) remove(curR--); + q_ans[queries[i].q_idx] = result; + } +} + +////////////// + +int main() { +#ifndef ONLINE_JUDGE + freopen("test.txt", "rt", stdin); +#endif + + scanf("%d", &n); + for (int i = 0; i < n; i++) + scanf("%d", &inp[i]); + + scanf("%d", &m); + for (int i = 0; i < m; i++) { + int left, right; + scanf("%d%d", &left, &right); + queries[i] = query(left, right, i); + } + process(); + + for (int i = 0; i < m; i++) + printf("%d\n", q_ans[i]); +} diff --git a/16 Misc/MO's_Algorithm.pdf b/16 Misc/MO's_Algorithm.pdf new file mode 100644 index 0000000..f455290 Binary files /dev/null and b/16 Misc/MO's_Algorithm.pdf differ diff --git a/16 Misc/Two_pointers_technique.pdf b/16 Misc/Two_pointers_technique.pdf new file mode 100644 index 0000000..8f4c805 Binary files /dev/null and b/16 Misc/Two_pointers_technique.pdf differ diff --git a/17-contests-stratigies/MostafaCheatSheet.pdf b/17-contests-stratigies/MostafaCheatSheet.pdf new file mode 100644 index 0000000..239f275 Binary files /dev/null and b/17-contests-stratigies/MostafaCheatSheet.pdf differ diff --git a/17-contests-stratigies/finals-contest-strategy-team-1.txt b/17-contests-stratigies/finals-contest-strategy-team-1.txt new file mode 100644 index 0000000..84bf650 --- /dev/null +++ b/17-contests-stratigies/finals-contest-strategy-team-1.txt @@ -0,0 +1,7 @@ +The contest is tough and causes much pressure +Without proper individual and team training = many mistakes occur even if members are strong +Typically other teams lead the scoreboard. You will recognize the easy 1-3 problems reasonably +For problems 4-6 the scoreboard also will highlight them but in a little rate. It might be misleading scoreboard +Avoid starting in a problem that not one tries so far! +Avoid problems solved only by the top 10 teams (it can be 8/10 success rate, and feels promising, but it is not) +Very early switch to 2-3 members per a problem diff --git a/17-contests-stratigies/regionals-contest-strategy-Individual-1.txt b/17-contests-stratigies/regionals-contest-strategy-Individual-1.txt new file mode 100644 index 0000000..49ae2a3 --- /dev/null +++ b/17-contests-stratigies/regionals-contest-strategy-Individual-1.txt @@ -0,0 +1,42 @@ +Following are some thoughts and "initial" guidelines for individual contest strategy. +- It is your Displine +- Adjust if want +- Apply it per a contest +- After contest, check your performance. +- Adjust the strategy to handle the missing sceanrios (Monitor) + +==== + + +Some notes: +a- A good strategy gets the problems AC (First submission) in terms of their hardness, relative to your knowledge and skills. +b- Scoreboard can be very helpful (what is the next to solve) or misleading (a harder problem solved before easier one(s)). So don't trust it all the time +b1- E.g. An experineced team might solve a hard problem of short code very early, but you need 1-2 years training to get it AC! You keep trying and fail, although easier ones not submitted so far +c- Compete against the problemset not the scorebaord. Don't let scoreboard be a stress source for you +d- Make checkpoints. Say every hour. Review your status and what is the right thing to do +e- Sometimes, one might need to switch from one strategy to another based on team/contest status. + + +Initial Strategy +1- Open all the problems in tabs. Reorder them based on their text length (and your intuition, but don't avoid what you don't like such as geometry). +1a- Sometimes, a very lengthy problem is one of the easiest problems. +2- Start to read in your sorted order till find a problem that you think is probbaly the easiest (5-10 min problem in ECPC/ACPC - 30-45 min ICPC) +3- Before coding, does the scoreboard inform us about a problem we did not read? If yes, check it. If no, go with the selected problem. +4- Code. Test the problem (Add your cases/boundries). Submit. Hopefully AC. Now, What is the next? +5- What does the scoreboard inform us? +5a- If a problem is solved by many teams, be biased toward checking/solving it +5b- Order the new problems by how many teams solved it. But, be very careful with ones that needed 3+ submissions till AC. Maybe unclear text, tricky problem, tight time limit..etc +5c- If a problem is solved by few, be careful, it might be a trap. Solved by some junior teams? or all are seniors? +5d- Decide if worth reading more unread problems or go\think with one of the solved problems that you know +5e- Remember, problems have some reasonable order. If you scalled your first 2 solved problems as 2/10, 3/10. The next shouldn't be 6/10. So, if your selection is for a hard problem, this is not the right decision. Find the problems in the right order +6- Go to 4 + +Further notes +- When you move to those hard problems, don't forget the scoreboard. Check it from time to time (say 10-15 min). +- Plan to read ALL problems before X (1-1.5) hours passes from the contest. + +In Case WA Status: +1- Fast revise for: Corner Cases, Limits, data types, Output Format, whole problem statement +2- If no bugs, If Stress Test is effective, DO IT. [Max 10 min] +3- Decide if we should left it for now or put little more time? +4- Don't let a problem kills your time. diff --git a/17-contests-stratigies/regionals-contest-strategy-team-1.txt b/17-contests-stratigies/regionals-contest-strategy-team-1.txt new file mode 100644 index 0000000..3f231b7 --- /dev/null +++ b/17-contests-stratigies/regionals-contest-strategy-team-1.txt @@ -0,0 +1,34 @@ +As per contestant, we should have displine in tackling a problem. + Team too should have displine in behaviour. + Every team should relaize its skills, and develop strategy and practise it. + + +E.g. This was my team strategy in Regionals 2010. + Code idea: the fast member (e.g. meeda) on PC and others are thinking and preparing staff for him. + We used this plan to utilize the special skills in the teams. + + 1- Meeda will setup the environment, and write the template. + 2- Mostafa will sort the problems, and give a problem to Yasser and read another one. + 3- Team should manage reading all problems within 1st hour, discussing all problems (except n+1's) within another 30 minute + 4- If Mostafa or Yasser found an ace before Meeda finish they will give it to Meeda to solve it. + 5- If Meeda finished before finding an ace he will take the next problem to read. + 6- Mostafa and Yasser will be thinking and if they got a solution for a problem they will add it to Meeda's queue. + 7- Everyone should estimate the size of code & time carefully as much as possible. + 8- Meeda should utilize scoreboard as main guide for solving problems, and in case tie, work on shortest first + 9- Before writing any problem, Meeda should read the problem statement, input and output sections again. + 0- If Meeda finished writing a problem, Mostafa or Yasser will join him to review his code and put some corner cases. + 1- Yasser pipeline if: Meeda got stuck in a problem, or other teams can beat our score in case tie of problems + 2- Once Meeda's queue is empty, he joins the team and work in pair style or triple in last 1.5 hour + 3- Yasser and Mostafa keep working to sketch problems solutions until discovering n+1's problems + 4- Yasser and Mostafa work hard to find the easiest n+1, and write its code & revise it very well + 5- once Meeda finished all medium problems, all team work on writing the n+1 problem together + 6- After each hour, break-point is done to check team status and other teams scores & accepted proplems + + In Case WA Status: + 1- Fast revise for: Corner Cases, Limits, Output Format should be considered (May be original reader of problem join that) [10 Min] + 2- If no bugs, If Stress Test is effective, DO IT. [Max 10 min] + 3- Original reader of problem should get a printed copy and debug, while Meeda Navigate to next [10 Min] + 4- If no bugs, Pend the problem, and later, 3rd member may debug code or rewrite it from scratch + + Notes + - Don't let a problem kills the team time diff --git a/17-contests-stratigies/regionals-contest-strategy-team-2.txt b/17-contests-stratigies/regionals-contest-strategy-team-2.txt new file mode 100644 index 0000000..9b5e257 --- /dev/null +++ b/17-contests-stratigies/regionals-contest-strategy-team-2.txt @@ -0,0 +1,32 @@ +Assume Team skills + The 3 members are seniors: Very knowledgeable / skilled + Assume their order based on CF/TC profiles + Ziad = Fast coder, low rate of bugs, individual behaviour + Saad = Fan of analyzing, like pair thinking, Not fast + Hani = Not biased to a specific concern + + +The opening (1 problem, the ace) + Goal: Find the easiest problem + Ziad: Jump to the machine - prepare the code templates + Saad: order problems based on length + Saad / Hani: Inspect the problems very fast to find the easiest and push to Ziad to code + +The early game (1-2 problems) + Goal: Catch the other 1-2 easy problems + Keep your eyes on the scoreboard for new ACs + Avoid/Minimize idea/code reviews -Ziad on machine + +The mid game (2-3) + Team members read at least 75% of the problems + Identify mid-level problems - reviewer role - code on paper - Owner types code to the terminal + Short codes directly to the machine NOT on papers + Check point after 1.5 & 3 hours + Read all papers by 1.5-2 hours + +The end game + Don’t open new problems if multiple non ACs + Start with 1-code-2-think with rotations + Switch to 3-in-1 when problems are very hard + + diff --git a/18-Programming-4kids/01_01.cpp b/18-Programming-4kids/01_01.cpp new file mode 100644 index 0000000..b1428cc --- /dev/null +++ b/18-Programming-4kids/01_01.cpp @@ -0,0 +1,11 @@ +#include +using namespace std; + + + +int main() +{ + cout<<"My First Program. Helllllllo."< +using namespace std; + +int main() +{ + cout<<"I am Mostafa"; + cout<<"I was born in Giza"; + cout<<"I graduated from Cairo university"; + + return 0; +} diff --git a/18-Programming-4kids/02_02.cpp b/18-Programming-4kids/02_02.cpp new file mode 100644 index 0000000..c0b66bb --- /dev/null +++ b/18-Programming-4kids/02_02.cpp @@ -0,0 +1,13 @@ +#include +using namespace std; + +int main() +{ + cout<<"I am Mostafa"; + cout< +using namespace std; + +int main() +{ + cout<<"I am "<<"Mostafa"< +using namespace std; + +int main() +{ + cout<<"I am Mostafa"< +using namespace std; + +int main() +{ + cout<<"I am Mostafa" + < +using namespace std; + +int main() +{ + cout<<"I am Mostafa\nI was born in Giza\nI graduated from Cairo university\n"; + + return 0; +} diff --git a/18-Programming-4kids/02_07.cpp b/18-Programming-4kids/02_07.cpp new file mode 100644 index 0000000..a6a0afa --- /dev/null +++ b/18-Programming-4kids/02_07.cpp @@ -0,0 +1,13 @@ +#include +using namespace std; + +int main() +{ + cout<<"I am Mostafa"; + return 0; + + cout< +using namespace std; + +int main() +{ + cout<<"I am Mostafa"; + cout< +using namespace std; + +int main() +{ + cout<<"I am Mostafa"; + /* + cout< +using namespace std; + +int main() +{ + cout<<1<<"\n"; + cout<<12<<"\n"; + cout<<123<<" is a number\n"; + cout<<"123"<<" is NOT a number\n"; + cout< +using namespace std; + +int main() +{ + cout<<1<<"\n"; + cout<<1+2<<"\n"; + cout<<1+2+3<<"\n"; + cout<<1+2+3+4<<"\n"; + cout<<"1+2+3+4"<<"\n"; + cout<<"1+2+3+4="<<1+2+3+4<<"\n\n"; + + cout<<1+2+3+4-10<<"\n"; + cout<<17-10<<"\n\n"; + + cout<<"2*3*4 = "<<2*3*4<<"\n"; + cout<<"12/2 = "<<12/2<<"\n"; + cout<<"12/2/3 = "<<12/2/3<<"\n\n"; + + cout<<"6/2 = "<<6/2<<"\n"; + cout<<"7/2 = "<<7/2<<"\n"; + cout<<"7.0/2.0 = "<<7.0/2.0<<"\n\n"; + + cout<<10*10*10*10*10*10*10*10*10<<"\n"; + cout<<10*10*10*10*10*10*10*10*10*10<<"\n"; + + return 0; +} diff --git a/18-Programming-4kids/02_12.cpp b/18-Programming-4kids/02_12.cpp new file mode 100644 index 0000000..0074fa1 --- /dev/null +++ b/18-Programming-4kids/02_12.cpp @@ -0,0 +1,29 @@ +#include +using namespace std; + +// Go over code line by line! + +int main() +{ + cout<<"If your dream only includes you, it’s too small\n\n"; + + cout<<30+20+10-10-20-30< +using namespace std; + +int main() +{ + cout<<"\n\nGuess the " + <<"output\n---\n"; + + cout<<10+20-5< +using namespace std; + +int main() +{ + cout<<"*"<> "Children need models rather than critics\n"; + + out<<"Children have never been very good at listening to their elders, but they have never failed to imitate them"; + + cout < "Children are our most valuable resource\n"; + diff --git a/18-Programming-4kids/03_homework_01_answer.cpp b/18-Programming-4kids/03_homework_01_answer.cpp new file mode 100644 index 0000000..b64a3f7 --- /dev/null +++ b/18-Programming-4kids/03_homework_01_answer.cpp @@ -0,0 +1,42 @@ +#include // NOT > + cout << "Children need models rather than critics\n"; + + // cout NOT out + cout<<"Children have never been very good at listening to their elders, but they have never failed to imitate them"; + + // << not < + cout << "Children are our most valuable resource\n"; + + + // Add return 0; + return 0; + + // Add } +} diff --git a/18-Programming-4kids/04_01.cpp b/18-Programming-4kids/04_01.cpp new file mode 100644 index 0000000..fc06c54 --- /dev/null +++ b/18-Programming-4kids/04_01.cpp @@ -0,0 +1,17 @@ +#include +using namespace std; + +int main() +{ + // int for integer + int age = 55; + + cout< +using namespace std; + +int main() +{ + // Declare variable in memory. Garbage value + int number1; + int number2; + + // Assign values (in memory( + number1 = 30; + number2 = 10; + + // Get values + cout< +using namespace std; + +int main() +{ + double weight = -92.5; + + char group = 'd'; + + bool is_male = true; + bool like_football = false; + + int age = 55; + string name = "mostafa"; + + cout<<"I am "< +using namespace std; + +int main() +{ + int num; + + cout<<"Enter your lucky number\n"; + + cin>>num; + + cout<<"********\n"; + cout<<2 * num + 1<<"\n"; + + return 0; +} diff --git a/18-Programming-4kids/04_05.cpp b/18-Programming-4kids/04_05.cpp new file mode 100644 index 0000000..085d24c --- /dev/null +++ b/18-Programming-4kids/04_05.cpp @@ -0,0 +1,14 @@ +#include +using namespace std; + +int main() { + int a, b; + + cout << "Enter 2 numbers\n"; + + cin >> a >> b; + + cout << a * b << " " << a + b << "\n"; + + return 0; +} diff --git a/18-Programming-4kids/04_06.cpp b/18-Programming-4kids/04_06.cpp new file mode 100644 index 0000000..78d5799 --- /dev/null +++ b/18-Programming-4kids/04_06.cpp @@ -0,0 +1,25 @@ +#include +using namespace std; + +int main() { + int age; + cout<<"Enter age: "; + cin>>age; + + double weight; + cout<<"Enter weight: "; + cin>>weight; + + char group; + cout<<"Enter group: "; + cin>>group; + + string name; + cout<<"Enter name: "; + cin>>name; + + cout<<"I am "< +using namespace std; + +int main() { + int num1 = 20; + int num2 = num1 + 5; + + cout<<"num2 "< +using namespace std; + +int main() { + int a, b; + + cin >> a >> b; + + cout << a << " + " << b << " = " << a + b << "\n"; + cout << a << " - " << b << " = " << a - b << "\n"; + cout << a << " / " << b << " = " << a / b << "\n"; + cout << a << " * " << b << " = " << a * b << "\n"; + + return 0; +} + +/* +Try inputs + +12 3 +15 0 +0 15 +2147483647 2147483647 + + */ diff --git a/18-Programming-4kids/04_homework_02_answer.cpp b/18-Programming-4kids/04_homework_02_answer.cpp new file mode 100644 index 0000000..fd61164 --- /dev/null +++ b/18-Programming-4kids/04_homework_02_answer.cpp @@ -0,0 +1,56 @@ +/* + +A teacher want a program that reads 2 students information about math exam + Read per student: name, id and grade + Then print them. See the picture in the slides + + +Be a good software engineer + Think deeply in your selected data types + The teacher gives us this dialogue to guide us + Be careful from your assumptions? + Is exam’s grade an integer? + + +*/ + +#include +using namespace std; + +int main() { + string name1; + cout<<"What is student 1 name: "; + cin>>name1; + + // Although looks as integer, no guarantee (make be big or has letters) + string id1; + cout<<"His id: "; + cin>>id1; + + // Although looks as integer, but grade could be 30.5 + double grade1; + cout<<"His math exam grade: "; + cin>>grade1; + + ///////////////////////// + string name2; + cout<<"What is student 2 name: "; + cin>>name2; + + string id2; + cout<<"His id: "; + cin>>id2; + + double grade2; + cout<<"His math exam grade: "; + cin>>grade2; + + cout<<"\nStudents grades in math\n"; + + cout< +using namespace std; + +int main() { + /* + * We know we will read 8 numbers + * The first number is the first odd + * The third number is the second odd + * The fifth number is the their odd + * The seventh number is the forth odd + * + * Same logic for even numbers + * + * The key: good naming variables and read them in right order + */ + int even1, even2, even3, even4; + int odd1, odd2, odd3, odd4; + + cin>>odd1>>even1; + cin>>odd2>>even2; + cin>>odd3>>even3; + cin>>odd4>>even4; + + int even_sum = even1 + even2 + even3 + even4; + int odd_sum = odd1 + odd2 + odd3 + odd4; + + cout< +using namespace std; + +int main() { + int num1, num2, num3; + + num1 = 0, num2 = 1, num3 = num1 + num2, cout < +using namespace std; + +int main() { + int num = 0; + + ++num; + num *= 10; + num += 2; + num = num * 10; + num += 3; + num = num * 10 + 4; + num = 5 + num * 10; + num = (num * 10 + 6) * 10 + 7; + num = 5 * num * 2 * 1 + 5 + 2 + 1; + + cout< +using namespace std; + +int main() { + int num1, num2, num3; + + cin>>num1>>num2; + + // Swap operation in 3 steps using num3 as temporary storage + // 1) put num2 value in num3 + num3 = num2; // now num3 is 231 + + // put num1 in num2 + num2 = num1; // now num2 is 7 + + // get the temp value in num3 in num1 + num1 = num3; + + cout< +using namespace std; + +int main() { + int num1, num2, num3, temp = -1; + + // We can reduce a hard to easier problems + // We solve it as separate swap operations + + cin>>num1>>num2>>num3; + + // swap num1, num2 + temp = num2; + num2 = num1; + num1 = temp; + + // swap num2, num3 + temp = num3; + num3 = num2; + num2 = temp; + + cout<>num1>>num2>>num3; + temp = num1; + num1 = num2; + num2 = num3; + num3 = temp; + + cout<=, etc) +*/ + +#include +using namespace std; + +int main() { + int a, b; + + cin >> a >> b; + + // Let's code the 2 possible results + int equ_is_1 = a * a; + int equ_is_neg_1 = 2 * a + 1; + + // The trick: we want to make them in 1 equation + // Where if input is: only 1 equation is computed and the second is zer0 + // To do so: convert -1 to 0 and 1 to 1 + // With simple math, we can convert [-1 1] to [0 1] range + + // value 1 for (b 1) and value 0 for (b -1) + int is_1 = (b + 1) / 2; + // value 1 for (b -1) and value 0 for (b 1) + int is_neg_1 = 1 - is_1; + + // Either 1*something + 0*something for b = 1 + // Or 0*something + 1*something for b = -1 + cout< +using namespace std; + +int main() { + int n; + + cin >> n; + + cout<< n * (n+1) / 2; + + /* + Why this equation? + Here is an intuition for N = 8 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + Let's arrange as following + 1 8 2 7 3 6 4 5 [first number and last number] [2nd number, and 2nd from back] ... + What is the value of each pair? 9 = n+1 + How many pairs? 4 = n/2 + + So n/2 pair, each has value n+1 + So total sum is (n * (n+1))/2 + + Now, this works for even N + Your turn: why works for odd N + + More readings: http://mathcentral.uregina.ca/qq/database/qq.02.06/jo1.html + */ + + return 0; +} + diff --git a/18-Programming-4kids/05_1.cpp b/18-Programming-4kids/05_1.cpp new file mode 100644 index 0000000..d88aa39 --- /dev/null +++ b/18-Programming-4kids/05_1.cpp @@ -0,0 +1,16 @@ +#include +using namespace std; + +int main() { + cout << (3 > 5) << "\n"; + cout << (3 < 5) << "\n"; + cout << (3 == 5) << "\n"; + cout << (3 >= 5) << "\n"; + cout << (3 >= 3) << "\n"; + cout << (3 == 3) << "\n"; + cout << (3 > 1) << "\n"; + cout << (3 != 4) << "\n"; + cout << (3 != 3) << "\n"; + + return 0; +} diff --git a/18-Programming-4kids/05_2.cpp b/18-Programming-4kids/05_2.cpp new file mode 100644 index 0000000..66e282f --- /dev/null +++ b/18-Programming-4kids/05_2.cpp @@ -0,0 +1,14 @@ +#include +using namespace std; + +int main() { + int x, y; + x = 3, y = 5; + + cout << (x > y) << "\n"; + cout << (x < y) << "\n"; + cout << (x == y) << "\n"; + cout << (x >= y) << "\n"; + + return 0; +} diff --git a/18-Programming-4kids/05_2_B.cpp b/18-Programming-4kids/05_2_B.cpp new file mode 100644 index 0000000..ca9bff2 --- /dev/null +++ b/18-Programming-4kids/05_2_B.cpp @@ -0,0 +1,18 @@ +#include +using namespace std; + +int main() { + int x, y; + x = 3, y = 5; + + bool result = (x > y); + cout << result << "\n"; + + result = (x < y); + cout << result << "\n"; + + cout << !result << "\n"; + cout << !(x < y) << "\n"; + + return 0; +} diff --git a/18-Programming-4kids/05_3.cpp b/18-Programming-4kids/05_3.cpp new file mode 100644 index 0000000..df179cb --- /dev/null +++ b/18-Programming-4kids/05_3.cpp @@ -0,0 +1,18 @@ +#include +using namespace std; + +int main() { + string name1 = "ali", name2 = "ali mostafa"; + string name3 = "ziad", name4 = "ali", name5 = "ALI"; + + cout<<(name1 < name2) <<"\n"; + cout<<(name1 > name3) <<"\n"; + cout<<(name1 != name4) <<"\n"; + cout<<(name1 == name4) <<"\n"; + + cout<<(name1 == name5) <<"\n"; + cout<<(name1 > name5) <<"\n"; + + return 0; +} + diff --git a/18-Programming-4kids/05_4.cpp b/18-Programming-4kids/05_4.cpp new file mode 100644 index 0000000..fa86b8a --- /dev/null +++ b/18-Programming-4kids/05_4.cpp @@ -0,0 +1,17 @@ +#include +using namespace std; + +int main() { + int age = 30, salary = 7000; + + bool result = (age > 25) && (salary < 8000); + cout< 25) && (salary > 9000) )<<"\n"; + + cout<<( (age > 35) || (salary < 8500) )<<"\n"; + cout<<( (age > 35) || (salary > 9000) )<<"\n"; + + return 0; +} + diff --git a/18-Programming-4kids/05_5.cpp b/18-Programming-4kids/05_5.cpp new file mode 100644 index 0000000..59f7f54 --- /dev/null +++ b/18-Programming-4kids/05_5.cpp @@ -0,0 +1,17 @@ +#include +using namespace std; + +int main() { + int age = 30, salary = 7000, weight = 110; + + cout<<( (age > 25) && (salary < 8000) && (weight < 150) )<<"\n"; + cout<<( (age > 25) && (salary < 8000) && (weight > 200) )<<"\n"; + + cout<<( (age > 35) || (salary > 6000) || (weight > 200) )<<"\n"; + + cout<<( (age > 35) && (salary > 6000) || (weight > 200) )<<"\n"; + cout<<( (age > 20) && (salary > 6000) || (weight > 200) )<<"\n"; + + return 0; +} + diff --git a/18-Programming-4kids/05_6.cpp b/18-Programming-4kids/05_6.cpp new file mode 100644 index 0000000..2a9cd5a --- /dev/null +++ b/18-Programming-4kids/05_6.cpp @@ -0,0 +1,15 @@ +#include +using namespace std; + +int main() { + int age = 30, salary = 7000, weight = 110; + + // ANDs are evaluated + cout << ( age > 35 || salary > 6000 && weight > 200) << "\n"; + + // () are evaluated FIRST even before some ANDS + cout << ((age > 35 || salary > 6000) && weight > 200) << "\n"; + + return 0; +} + diff --git a/18-Programming-4kids/05_homework_01.cpp b/18-Programming-4kids/05_homework_01.cpp new file mode 100644 index 0000000..052c1f0 --- /dev/null +++ b/18-Programming-4kids/05_homework_01.cpp @@ -0,0 +1,28 @@ +// Homework 1: Guess the output + +#include +using namespace std; + +int main() { + + int a = 10, b = 20, c = 30, d = 40; + + cout << (a + b == c) << "\n"; + cout << (a + b + c >= 2 * d) << "\n"; + + cout << (a > 5 || d < 30) << "\n"; + cout << (a > 5 && d < 30) << "\n"; + cout << (a <= b && b <= c) << "\n"; + + cout << (a > 5 && d < 30 || c - b == 10) << "\n"; + cout << (a <= b && b <= c && c <= d) << "\n"; + + cout << (a > 5 && d < 30 || c > d || d % 2 == 0) << "\n"; + cout << (a > 5 && d < 30 || c > d && d % 2 == 0) << "\n"; + + cout << ( a == 10 || b != 20 && c != 30 || d != 40) << "\n"; + cout << ((a == 10 || b != 20) && c != 30 || d != 40) << "\n"; + + return 0; +} + diff --git a/18-Programming-4kids/05_homework_02_answer.cpp b/18-Programming-4kids/05_homework_02_answer.cpp new file mode 100644 index 0000000..159ccf6 --- /dev/null +++ b/18-Programming-4kids/05_homework_02_answer.cpp @@ -0,0 +1,51 @@ +/* + Homework 2: Create logic! + + Write a program that reads 3 integers about the class room + Number of boys (nb), number of girls (ng), number of teachers (nt) + + Prepare and print a boolean variable for these cases: + nb greater than 25 + ng less than or equal to 30 + nb > 20 and nt > 2 or ng > 30 and nt > 4 + Either nb < 60 or ng < 70 + Neither nb >= 60 nor ng >= 70 + nb is 10 more students than ng + Difference between nb and ng is more than 10 or nt > 5 + Either nb is 10 more students than ng or ng is 15 more students than nb + */ + +#include +using namespace std; + +int main() { + int nb, ng, nt; + cin >> nb >> ng >> nt; + + // nb greater than 25 + cout << (nb > 25) << "\n"; + + // ng less than or equal to 30 + cout << (ng <= 30) << "\n"; + + // nb > 20 and nt > 2 or ng > 30 and nt > 4 + cout << (nb > 20 && nt > 2 || ng > 30 && nt > 4) << "\n"; + + // Either nb < 60 or ng < 70 + cout << (nb < 60 || ng < 70) << "\n"; + + // Neither nb >= 60 nor ng >= 70 + cout << ( !(nb >= 60) && !(ng >= 70) ) << "\n"; + + // nb is 10 more students than ng + cout << (nb == ng + 10) << "\n"; + + // Difference between nb and ng is more than 10 or nt > 5 + cout << (nb - ng > 10 || nt > 5) << "\n"; + + // Either nb is 10 more students than ng or ng is 15 more students than nb + cout << (nb == ng + 10 || ng == nb + 15) << "\n"; + + return 0; +} + diff --git a/18-Programming-4kids/05_homework_03_answer.txt b/18-Programming-4kids/05_homework_03_answer.txt new file mode 100644 index 0000000..2bcad6a --- /dev/null +++ b/18-Programming-4kids/05_homework_03_answer.txt @@ -0,0 +1,75 @@ +Homework 3: Simplify expressions + + + +T && T && F && T +- F [as all of them are && and one of them is F] +======================================================================== + +T && T && F && T || T && T +- T && T && F && T ==> Reduce to F +- F || T ==> T +======================================================================== + +T && T && T && T || T && (T || F) +- (T || F) ==> Reduce to T +- T && T && T && T || T && T +- T && T && T && T ==> reduce to T +- T || T && T +- T && T ==> Reduce to T +- T || T ==> T +======================================================================== + +T && T && T || T && (F || (T && (T && T))) +- (T && T) ==> reduce to T +- T && T && T || T && (F || (T && T)) +- (T && T) ==> reduce to T +- T && T && T || T && (F || T) +- (F || T) ==> reduce to T +- T && T && T || T && T +- T && T && T ==> reduce to T +- T || T && T +- T && T ==> reduce to T +- T || T ==> T +======================================================================== + +T && T || T && F && T || T && T && F || (T && (T || F)) +- (T || F) ==> reduce to T +- T && T || T && F && T || T && T && F || (T && T) +- (T && T) ==> reduce to T +- T && T || T && F && T || T && T && F || T +- T && T ==> reduce to T +- T || T && F && T || T && T && F || T +- T && F && T ==> Reduce to F +- T || F || T && T && F || T +- T && F && T ==> Reduce to F +- T || F || T && T && F || T +- T && T && F ==> Reduce to F +- T || F || F || T ==> T +======================================================================== + +T && T || T && F && T || T && T && F || (T && (T || F)) +- (T || F) ==> reduce to T +- T && T || T && F && T || T && T && F || (T && T) +- (T && T) ==> reduce to T +- T && T || T && F && T || T && T && F || T +- (T && T) ==> reduce to T +- T || whatever = T [smart reduction] +======================================================================== + +T && T || T && F && T || (T && T && F || (T && (T || F))) +- Notice T && T || something = T, so we know the answer T +======================================================================== + +(T && T || T && F && T || T) && T && F || (T && (T || F)) +- (T && (T || F)) ==> reduced in 2 steps to: T +- (T && T || T && F && T || T) ==> (T || F || T) ==> T +- So now is: +- T && T && F || T ==> F || T ==> T +======================================================================== + + +T && T || T && (F && T || T && T) && F || (T && (T || F)) +- (T && (T || F)) ==> reduced in 2 steps to: T +- (F && T || T && T) ==> (F || T) ==> T +- T && T || T && T && F || T ==> T || F || T = T diff --git a/18-Programming-4kids/06_1.cpp b/18-Programming-4kids/06_1.cpp new file mode 100644 index 0000000..ca44d96 --- /dev/null +++ b/18-Programming-4kids/06_1.cpp @@ -0,0 +1,23 @@ +#include +using namespace std; + +int main() { + cout << 25 / 5 << "\n"; + cout << 26 / 5 << "\n"; + cout << 27 / 5 << "\n"; + cout << 28 / 5 << "\n"; + cout << 29 / 5 << "\n"; + cout << 30 / 5 << "\n"; + cout << 31 / 5 << "\n"; + cout << "******\n"; + cout << 25 / 5.0 << "\n"; + cout << 26 / 5.0 << "\n"; + cout << 27.0 / 5 << "\n"; + cout << 28.0 / 5.0 << "\n"; + cout << 29.0 / 5.0 << "\n"; + cout << 30.0 / 5.0 << "\n"; + cout << 31.0 / 5 << "\n"; + + return 0; +} + diff --git a/18-Programming-4kids/06_2.cpp b/18-Programming-4kids/06_2.cpp new file mode 100644 index 0000000..70b4bb1 --- /dev/null +++ b/18-Programming-4kids/06_2.cpp @@ -0,0 +1,24 @@ +#include +using namespace std; + +int main() { + int num = 12345; + + cout< +using namespace std; + +int main() { + int num = 12345; + + cout< +using namespace std; + +int main() { + // 8/3 = 2.6666666666666 ..... 6666 + double num = 8/3.0; + + cout< +using namespace std; + +int main() { + + int num; + cin >> num; + + // Is even using %2 + bool is_even1 = (num % 2 == 0); + + // is even using /2 + double by2 = (double) num / 2.0;// this is either X.0 or X.5 (try 10, 11) + by2 = by2 - (int) by2;// Remove X. This is now either 0 (for even) or 0.5 (for odd) + bool is_even2 = by2 == 0; + + // is even using %10 + int last_digit = num % 10; // even last digit is 0, 2, 4, 6, 8 + bool is_even3 = last_digit == 0 || last_digit == 2 || last_digit == 4 || last_digit == 6 || last_digit == 8; + + return 0; +} + diff --git a/18-Programming-4kids/06_homework_02_answer.cpp b/18-Programming-4kids/06_homework_02_answer.cpp new file mode 100644 index 0000000..12cd1b8 --- /dev/null +++ b/18-Programming-4kids/06_homework_02_answer.cpp @@ -0,0 +1,23 @@ +#include +using namespace std; + +int main() { + + double a1, a2, a3, a4, a5; + cin >> a1 >> a2 >> a3 >> a4 >> a5; + + double avg1 = (a1+a2+a3+a4+a5) / 5.0; // A + double sum1 = (a1+a2+a3) / (a4+a5); // B + double first3_avg = (a1+a2+a3) / 3.0; + double last2_avg = (a4+a5) / 2.0; + double avg2 = first3_avg / last2_avg; // C + + cout< +using namespace std; + +int main() { + + int n; + cin >> n; + + int last1 = n % 10; + n /= 10; + + int last2 = n % 10; + n /= 10; + + int last3 = n % 10; + n /= 10; + + cout << last1 + last2 + last3 << "\n"; + + return 0; +} + diff --git a/18-Programming-4kids/06_homework_04_answer.cpp b/18-Programming-4kids/06_homework_04_answer.cpp new file mode 100644 index 0000000..c37ab45 --- /dev/null +++ b/18-Programming-4kids/06_homework_04_answer.cpp @@ -0,0 +1,15 @@ +#include +using namespace std; + +int main() { + + int n; + cin >> n; + + // /1000 => removes last 3 digits + // %10 get next digit = 4th + cout << (n / 1000) % 10 << "\n"; + + return 0; +} + diff --git a/18-Programming-4kids/06_homework_05_answer.cpp b/18-Programming-4kids/06_homework_05_answer.cpp new file mode 100644 index 0000000..ad0272d --- /dev/null +++ b/18-Programming-4kids/06_homework_05_answer.cpp @@ -0,0 +1,15 @@ +#include +using namespace std; + +int main() { + + double a, b; + cin>>a>>b; + + double result = a/b; + + cout< +using namespace std; + +int main() { + + int n, m; + cin >> n >> m; + + // let's try 13/5 + // 13/5 = 2 [2 complete units, each is 5] + // 2*5 = 10 [total complete units] + // Reminder is 13-10 = 3. This number generates the fractional part + int result = n - (n / m) * m; + + cout << result << " " << n % m << "\n"; + + return 0; +} + diff --git a/18-Programming-4kids/06_homework_07_answer.cpp b/18-Programming-4kids/06_homework_07_answer.cpp new file mode 100644 index 0000000..580a028 --- /dev/null +++ b/18-Programming-4kids/06_homework_07_answer.cpp @@ -0,0 +1,21 @@ +#include +using namespace std; + +int main() { + + int n; + cin >> n; + + int is_even = n % 2 == 0; + int is_odd = 1 - is_even; + + // formula of 2 parts: only one of them will be activated + int result = is_even * 100 + is_odd * 7; + + cout< +using namespace std; + +int main() { + + int days; + + cin >> days; + + int years = days / 360; + days = days % 360; // now we remove # of complete years + + int months = days / 30; + days = days % 30; + + cout< +using namespace std; + +int main() { + int salary; + cin>>salary; + + if (salary < 1000) + cout<<"you are poor\n"; + + cout<<"Salam"; + + return 0; +} + diff --git a/18-Programming-4kids/07_10.cpp b/18-Programming-4kids/07_10.cpp new file mode 100644 index 0000000..f91c3e5 --- /dev/null +++ b/18-Programming-4kids/07_10.cpp @@ -0,0 +1,36 @@ +#include +using namespace std; + +int main() { + int n; + cin>>n; + + if (n < 10000) + cout<<"this is a small number\n"; + else + { + int digit1 = n%10; + n = n/10; + int digit2 = n%10; + n = n/10; + int digit3 = n%10; // old value of n gone + + int sum = digit1+digit2+digit3; + + if ((sum%2) != 0) // odd + cout<<"this is a great number\n"; + else + { + bool is_digit1_odd = (digit1 % 2 == 1); + bool is_digit2_odd = (digit2 % 2 == 1); + bool is_digit3_odd = (digit3 % 2 == 1); + + if (is_digit1_odd || is_digit2_odd || is_digit3_odd) + cout<<"this is a good number\n"; + else + cout<<"this is a bad number\n"; + } + } + return 0; +} + diff --git a/18-Programming-4kids/07_2.cpp b/18-Programming-4kids/07_2.cpp new file mode 100644 index 0000000..d531884 --- /dev/null +++ b/18-Programming-4kids/07_2.cpp @@ -0,0 +1,18 @@ +#include +using namespace std; + +int main() { + int num; + cin>>num; + + if (num == 10) + { + int x = 3; + cout<<"10 is lucky number\n"; + cout<<"also "<<2*num + x<<"\n"; + } + //cout< +using namespace std; + +int main() { + int salary; + cin>>salary; + + if (salary < 1000) + cout<<"you are poor\n"; + else if (salary >= 1000 && salary < 20000) + cout<<"good salary\n"; + else + cout<<"you are rich\n"; + + return 0; +} + diff --git a/18-Programming-4kids/07_4.cpp b/18-Programming-4kids/07_4.cpp new file mode 100644 index 0000000..35764cd --- /dev/null +++ b/18-Programming-4kids/07_4.cpp @@ -0,0 +1,26 @@ +#include +using namespace std; + +int main() { + int salary; + + cout<<"Enter salary: "; + cin>>salary; + + if (salary < 1000) + { + cout<<"Enter age: "; + int age; + cin>>age; + + if (age < 22) + cout<<"You are still young."; + } + else + cout<<"you are rich\n"; + + //cout< +using namespace std; + +int main() { + int num; + cin>>num; + + if (num < 10) + cout<<"1 digit\n"; + else if (num < 100) + cout<<"2 digits\n"; + else if (num < 1000) + cout<<"3 digits\n"; + else if (num < 10000) + cout<<"4 digits\n"; + else + cout<<"5 or more digits\n"; + + return 0; +} + diff --git a/18-Programming-4kids/07_6.cpp b/18-Programming-4kids/07_6.cpp new file mode 100644 index 0000000..f904c62 --- /dev/null +++ b/18-Programming-4kids/07_6.cpp @@ -0,0 +1,25 @@ +#include +using namespace std; + +int main() { + // Good choice for a number here is double + double num1, num2; + char operation; + + cin >> num1 >> operation >> num2; + + if (operation == '+') + cout << num1 + num2 << "\n"; + + else if (operation == '-') + cout << num1 - num2 << "\n"; + + else if (operation == '*') + cout << num1 * num2 << "\n"; + + else + cout << num1 / num2 << "\n"; + + return 0; +} + diff --git a/18-Programming-4kids/07_7.cpp b/18-Programming-4kids/07_7.cpp new file mode 100644 index 0000000..3f5f630 --- /dev/null +++ b/18-Programming-4kids/07_7.cpp @@ -0,0 +1,16 @@ +#include +using namespace std; + +int main() { + int num1, num2; + + cin >> num1 >> num2; + + if (num1 < num2) + cout << num1 << "\n"; + else + cout << num2 << "\n"; + + return 0; +} + diff --git a/18-Programming-4kids/07_8_A.cpp b/18-Programming-4kids/07_8_A.cpp new file mode 100644 index 0000000..836bbd1 --- /dev/null +++ b/18-Programming-4kids/07_8_A.cpp @@ -0,0 +1,25 @@ +#include +using namespace std; + +int main() { + int num1, num2, num3; + + cin >> num1 >> num2 >> num3; + + if (num1 < num2) { + // Then either num1 or num3 is the answer + if (num1 < num3) + cout << num1 << "\n"; + else + cout << num3 << "\n"; + } else // Then either num2 or num3 is the answer + { + if (num2 < num3) + cout << num2 << "\n"; + else + cout << num3 << "\n"; + } + + return 0; +} + diff --git a/18-Programming-4kids/07_8_B.cpp b/18-Programming-4kids/07_8_B.cpp new file mode 100644 index 0000000..51a052f --- /dev/null +++ b/18-Programming-4kids/07_8_B.cpp @@ -0,0 +1,18 @@ +#include +using namespace std; + +int main() { + int num1, num2, num3; + + cin >> num1 >> num2 >> num3; + + if (num1 < num2 && num1 < num3) + cout << num1 << "\n"; + else if (num2 < num1 && num2 < num3) + cout << num2 << "\n"; + else + cout << num3 << "\n"; + + return 0; +} + diff --git a/18-Programming-4kids/07_8_C.cpp b/18-Programming-4kids/07_8_C.cpp new file mode 100644 index 0000000..2d3a293 --- /dev/null +++ b/18-Programming-4kids/07_8_C.cpp @@ -0,0 +1,21 @@ +#include +using namespace std; + +int main() { + int num1, num2, num3; + + cin >> num1 >> num2 >> num3; + + int answer = num1; + + if (answer > num2) + answer = num2; + + if (answer > num3) + answer = num3; + + cout << answer << "\n"; + + return 0; +} + diff --git a/18-Programming-4kids/07_9.cpp b/18-Programming-4kids/07_9.cpp new file mode 100644 index 0000000..d45db60 --- /dev/null +++ b/18-Programming-4kids/07_9.cpp @@ -0,0 +1,22 @@ +#include +using namespace std; + +int main() { + int num; + cin >> num; + + bool is_even = (num % 2 == 0); + + if (is_even) + cout << num % 10 << "\n"; + else { + if (num < 1000) + cout << num % 100 << "\n"; + else if (num < 1000000) + cout << num % 10000 << "\n"; + else + cout << -num << "\n"; + } + return 0; +} + diff --git a/18-Programming-4kids/07_homework_01_answer.cpp b/18-Programming-4kids/07_homework_01_answer.cpp new file mode 100644 index 0000000..78c8845 --- /dev/null +++ b/18-Programming-4kids/07_homework_01_answer.cpp @@ -0,0 +1,22 @@ +#include +using namespace std; + +int main() { + int a, b; + cin >> a >> b; + + bool is_a_even = (a % 2 == 0); + bool is_b_even = (b % 2 == 0); + + if (!is_a_even && !is_b_even) + cout << a * b << "\n"; + else if (is_a_even && is_b_even) + cout << a / b << "\n"; + else if (!is_a_even && is_b_even) + cout << a + b << "\n"; + else + cout << a - b << "\n"; + + return 0; +} + diff --git a/18-Programming-4kids/07_homework_02_answer.cpp b/18-Programming-4kids/07_homework_02_answer.cpp new file mode 100644 index 0000000..b93e11e --- /dev/null +++ b/18-Programming-4kids/07_homework_02_answer.cpp @@ -0,0 +1,35 @@ +#include +using namespace std; + +int main() { + int a, b, c, tmp; + cin >> a >> b >> c; + + if (b < a) { // Swap them + + tmp = a; + a = b; + b = tmp; + } + // Now a, b are correct + + if (c < b) { // Swap them + + tmp = b; + b = c; + c = tmp; + + // Now b, c are correct + // But a, b may not be again + + if (b < a) { // Swap them{ + tmp = a; + a = b; + b = tmp; + } + } + cout< +using namespace std; + +int main() { + int a, b, c, tmp; + cin >> a >> b >> c; + + int res = -1; + + if (a < 100 && a > res) + res = a; + + if (b < 100 && b > res) + res = b; + + if (c < 100 && c > res) + res = c; + + cout< +using namespace std; + +int main() { + int x, a1, a2, a3, a4, a5; + + cin >> x >> a1 >> a2 >> a3 >> a4 >> a5; + + int cnt = 0; + + cnt += (a1 <= x); + cnt += (a2 <= x); + cnt += (a3 <= x); + cnt += (a4 <= x); + cnt += (a5 <= x); + + cout << cnt << " " << 5 - cnt << "\n"; + + return 0; +} + diff --git a/18-Programming-4kids/07_homework_05_answer.cpp b/18-Programming-4kids/07_homework_05_answer.cpp new file mode 100644 index 0000000..53d51b9 --- /dev/null +++ b/18-Programming-4kids/07_homework_05_answer.cpp @@ -0,0 +1,24 @@ +#include +using namespace std; + +int main() { + int result, num; + + cin>>result; // First number + + // Read 9 times and maximize + cin>>num; if(result < num) result = num; + cin>>num; if(result < num) result = num; + cin>>num; if(result < num) result = num; + cin>>num; if(result < num) result = num; + cin>>num; if(result < num) result = num; + cin>>num; if(result < num) result = num; + cin>>num; if(result < num) result = num; + cin>>num; if(result < num) result = num; + cin>>num; if(result < num) result = num; + + cout< +using namespace std; + +int main() { + int cnt, result, num; + + cin>>cnt; + + cin>>result; // First number + cnt -= 1; + + // Read times and maximize + if(cnt > 0) {cnt -=1; cin>>num; if(result < num) result = num; } + if(cnt > 0) {cnt -=1; cin>>num; if(result < num) result = num; } + if(cnt > 0) {cnt -=1; cin>>num; if(result < num) result = num; } + if(cnt > 0) {cnt -=1; cin>>num; if(result < num) result = num; } + if(cnt > 0) {cnt -=1; cin>>num; if(result < num) result = num; } + if(cnt > 0) {cnt -=1; cin>>num; if(result < num) result = num; } + if(cnt > 0) {cnt -=1; cin>>num; if(result < num) result = num; } + if(cnt > 0) {cnt -=1; cin>>num; if(result < num) result = num; } + if(cnt > 0) {cnt -=1; cin>>num; if(result < num) result = num; } + + cout< +using namespace std; + +int main() { + int x, start, end, cnt = 0; + + cin>>x; + + //Read start and end, then see if X is between them or not, 3 times + cin>>start>>end; + cnt += (start <= x && x <= end); + + cin>>start>>end; + cnt += (start <= x && x <= end); + + cin>>start>>end; + cnt += (start <= x && x <= end); + + cout< +using namespace std; + +int main() { + int s1, e1, s2, e2; + + cin >> s1 >> e1 >> s2 >> e2; + + if(e1 < s2 || e2 < s1) + cout<<-1<<"\n"; // One of them ends before start of the another + else + { + // This is tricky. Trying to list all cases will be hard and buggy + // You need to notice which ones came first + // Then consider the possible cases (e.g. one of them completely inside the second) + + // However, more thinking makes it easier + // The intersection starts at the maximum of the starts + // The intersection ends at the minimum of the ends + // Draw some examples + + if(s1 < s2) s1 = s2; // maximum of (s1, s2) + if(e1 > e2) e1 = e2; // minimum of (e1, e2) + + cout< -1 + 20 30 1 15 ==> -1 + 1 6 1 6 ==> 1 6 + 1 6 1 3 ==> 1 3 + 1 6 2 3 ==> 2 3 + 1 6 3 8 ==> 3 6 + 3 8 1 6 ==> 3 6 + + */ + return 0; +} + diff --git a/18-Programming-4kids/08_1.cpp b/18-Programming-4kids/08_1.cpp new file mode 100644 index 0000000..fb96d12 --- /dev/null +++ b/18-Programming-4kids/08_1.cpp @@ -0,0 +1,12 @@ +#include +using namespace std; + +int main() { + + while (2 < 6) + { + cout<<"2 < 5. Forever\n"; + } + + return 0; +} diff --git a/18-Programming-4kids/08_2.cpp b/18-Programming-4kids/08_2.cpp new file mode 100644 index 0000000..b292da3 --- /dev/null +++ b/18-Programming-4kids/08_2.cpp @@ -0,0 +1,14 @@ +#include +using namespace std; + +int main() { + int x = 1; + + while (x <= 5) + { + cout << x << " "; + x = x + 1; + } + + return 0; +} diff --git a/18-Programming-4kids/08_3.cpp b/18-Programming-4kids/08_3.cpp new file mode 100644 index 0000000..8ed4cdd --- /dev/null +++ b/18-Programming-4kids/08_3.cpp @@ -0,0 +1,16 @@ +#include +using namespace std; + +int main() { + int x = 1; + int sum = 0; + + while (x < 6) + { + sum += x; + ++x; + } + cout< +using namespace std; + +int main() { + int x = 5; + int sum = 0; + + while (x >= 0) + { + sum += x; + x--; + } + cout< +using namespace std; + +int main() { + int x, y; + + while (true) { + cin >> x >> y; + + if (y == 0) + { + cout<<"Y is zero!!\n"; + break; + } + cout << x / y << "\n"; + } + cout<<"Bye\n"; + + return 0; +} diff --git a/18-Programming-4kids/08_6.cpp b/18-Programming-4kids/08_6.cpp new file mode 100644 index 0000000..bfeac96 --- /dev/null +++ b/18-Programming-4kids/08_6.cpp @@ -0,0 +1,20 @@ +#include +using namespace std; + +int main() { + int x, y; + + while (true) { + cin >> x >> y; + + if (y == 0) + { + cout<<"Y is zero. Try other 2 numbers\n"; + continue; + } + cout << x / y << "\n"; + } + cout<<"Bye\n"; // never reached + + return 0; +} diff --git a/18-Programming-4kids/08_7.cpp b/18-Programming-4kids/08_7.cpp new file mode 100644 index 0000000..d04613a --- /dev/null +++ b/18-Programming-4kids/08_7.cpp @@ -0,0 +1,16 @@ +#include +using namespace std; + +int main() { + int end; + cin >> end; + + int start = 1; + + while (start <= end) { + if (start % 3 == 0) + cout << start << "\n"; + start += 1; + } + return 0; +} diff --git a/18-Programming-4kids/08_8_A_2bugs.cpp b/18-Programming-4kids/08_8_A_2bugs.cpp new file mode 100644 index 0000000..0a37522 --- /dev/null +++ b/18-Programming-4kids/08_8_A_2bugs.cpp @@ -0,0 +1,16 @@ +#include +using namespace std; + +int main() { + int num; + cin >> num; + + int digits = 0; + + while (num > 0) { + digits += 1; + num = num / 10; + } + cout< +using namespace std; + +int main() { + int num; + cin >> num; + + int digits = 0; + + if (num == 0) + digits = 1; + else { + while (num > 0) { + digits += 1; + num = num / 10; + } + } + cout << digits; + return 0; +} diff --git a/18-Programming-4kids/08_8_C_still_1bug.cpp b/18-Programming-4kids/08_8_C_still_1bug.cpp new file mode 100644 index 0000000..becac5e --- /dev/null +++ b/18-Programming-4kids/08_8_C_still_1bug.cpp @@ -0,0 +1,25 @@ +#include +using namespace std; + +int main() { + int num; + cin >> num; + + int digits = 0; + + if (num == 0) + digits = 1; + else if (num == -2147483648) + digits = 10; + else { + if (num < 0) + num = -num; + + while (num > 0) { + digits += 1; + num = num / 10; + } + } + cout << "# of digits of "< +using namespace std; + +int main() { + int num; + cin >> num; + + int tem_num = num; + int digits = 0; + + if (num == 0) + digits = 1; + else if (num == -2147483648) + digits = 10; + else { + if (num < 0) + num = -num; + + while (num > 0) { + digits += 1; + num = num / 10; + } + } + cout << "# of digits of "< +using namespace std; + +int main() { + int T; + cin >> T; + + while (T > 0) { + int num; + cin >> num; + + int sum = 0; + int start = 1; + + while (start <= num) { + sum += start; + start++; + } + --T; + cout << "Sum from 1 to " << num << " = " << sum << "\n"; + } + + return 0; +} diff --git a/18-Programming-4kids/08_homework_01_answer.cpp b/18-Programming-4kids/08_homework_01_answer.cpp new file mode 100644 index 0000000..1dd61d3 --- /dev/null +++ b/18-Programming-4kids/08_homework_01_answer.cpp @@ -0,0 +1,20 @@ +/* + */ + +#include +using namespace std; + +int main() { + int start, end; + + cin>>start>>end; + + while(start <= end) + { + cout< +using namespace std; + +int main() { + int num; + char ch; + + cin>>num>>ch; + + while(num > 0) + { + cout< +using namespace std; + +int main() { + int N; + + cin >> N; + + int row = 1; + while (row <= N) { + int stars_count = 1; + + while (stars_count <= row) { + cout << '*'; + ++stars_count; + } + cout << "\n"; + row++; + } + + return 0; +} + diff --git a/18-Programming-4kids/08_homework_04_answer.cpp b/18-Programming-4kids/08_homework_04_answer.cpp new file mode 100644 index 0000000..be88ac4 --- /dev/null +++ b/18-Programming-4kids/08_homework_04_answer.cpp @@ -0,0 +1,26 @@ +/* + */ + +#include +using namespace std; + +int main() { + int N; + + cin >> N; + + int row = N; + while (row > 0) { + int stars_count = 1; + + while (stars_count <= row) { + cout << '*'; + ++stars_count; + } + cout << "\n"; + row--; + } + + return 0; +} + diff --git a/18-Programming-4kids/08_homework_05_answer.cpp b/18-Programming-4kids/08_homework_05_answer.cpp new file mode 100644 index 0000000..fe9352b --- /dev/null +++ b/18-Programming-4kids/08_homework_05_answer.cpp @@ -0,0 +1,77 @@ +/* + * Homework 5: Print diamond + * + * Given a number N. Print diamond of 2N rows as in. + * https://codeforces.com/group/MWSDmqGsZm/contest/219432/problem/X + */ + +#include +using namespace std; + +int main() { + int N; + + cin >> N; + + /* + * Let's print the upper triangle first + * Let's assume N = 4, how many spaces and starts we print + * Row 1 Spaces 3 Stars 1 + * Row 2 Spaces 2 Stars 3 + * Row 3 Spaces 1 Stars 5 + * Row 4 Spaces 0 Stars 7 + * + * Now we wanna develop formulas for number of spaces and number of starts + * For a given 'row' + * Spaces are: N - rows (3, 2, 1, 0) + * Starts are: 2*row -1 (1, 3, 5, 7) + * + * Now we just iterate for each row + * print spaces + * then print starts + */ + int row = 1; + while (row <= N) { + int stars_count = 1; + + // Print N - rows spaces + while (stars_count <= N-row) { + cout << ' '; + ++stars_count; + } + + // Print 2*rows-1 stars + stars_count = 1; + while (stars_count <= 2*row-1) { + cout << '*'; + ++stars_count; + } + cout << "\n"; + ++row; + } + + /* + * Let's print the lower triangle second + * Same logic, we just switch looping from N to 1 + */ + row = N; + while (row >= 1) { + int stars_count = 1; + + while (stars_count <= N-row) { + cout << ' '; + ++stars_count; + } + + stars_count = 1; + + while (stars_count <= 2*row-1) { + cout << '*'; + ++stars_count; + } + cout << "\n"; + --row; + } + return 0; +} + diff --git a/18-Programming-4kids/08_homework_06_answer.cpp b/18-Programming-4kids/08_homework_06_answer.cpp new file mode 100644 index 0000000..5ab88e1 --- /dev/null +++ b/18-Programming-4kids/08_homework_06_answer.cpp @@ -0,0 +1,40 @@ + + +/* + * + * Test cases + * Input: 7 11 101 21 201 31 602 78 + * + * Output: 35.25 301.333 + */ + +#include +using namespace std; + +int main() { + int N; + + cin >> N; + + // Use doubles to: 1) allow any values 2) get average correctly + double even_sum = 0, odd_sum = 0; + int even_count = 0, odd_count = 0; + + int cnt = 1; + while (cnt <= N) { + double value; + cin >> value; + + if (cnt % 2 == 0) // even position + even_sum += value, even_count++; + else // odd position + odd_sum += value, odd_count++; + + cnt++; + } + + cout < +using namespace std; + +int main() { + int N, result = 0; + + cin >> N; + + int cnt = 0; + + while (cnt <= N) + { + if (cnt % 8 == 0 || cnt % 3 == 0 && cnt % 4 == 0) + cout< +using namespace std; + +int main() { + int N, result = 0; + + cin >> N; + + int cnt = 0; + int current_number = 0; + + while (cnt < N) { + if (current_number % 3 == 0 && current_number % 4 != 0) { + cout << current_number << " "; + cnt++; + } + current_number++; + } + return 0; +} + diff --git a/18-Programming-4kids/08_homework_09_answer.cpp b/18-Programming-4kids/08_homework_09_answer.cpp new file mode 100644 index 0000000..f250040 --- /dev/null +++ b/18-Programming-4kids/08_homework_09_answer.cpp @@ -0,0 +1,24 @@ +#include +using namespace std; + +int main() { + int N; + + cin >> N; + + int pos = 0; + + while (pos < N) { + string str; + cin>>str; + + // there are 8 different ways to make 2 letters no in lower/upper cases + if (str == "no" || str == "No" || str == "nO" || str == "NO" || + str == "on" || str == "oN" || str == "On" || str == "ON") + cout< +using namespace std; + +int main() { + int N; + + cin >> N; + + int number = 0; + + while (N > 0) { + int last_digits = N % 10; + N /= 10; // remove last digit + + number = number * 10 + last_digits; + } + cout << number << " " << number * 3 << "\n"; + + return 0; +} + diff --git a/18-Programming-4kids/08_homework_11_answer.cpp b/18-Programming-4kids/08_homework_11_answer.cpp new file mode 100644 index 0000000..204084e --- /dev/null +++ b/18-Programming-4kids/08_homework_11_answer.cpp @@ -0,0 +1,34 @@ +#include +using namespace std; + +int main() { + int T; + + cin >> T; + + while (T > 0) { + int N; + cin >> N; + + int pos = 0; + int result; + + while (pos < N) { + int value; + cin >> value; + + if (pos == 0) + result = value; + else if (result > value) + result = value; + + pos++; + } + cout< +using namespace std; + +int main() { + int n, m; + + cin >> n >> m; + + int cnt_n = 1; + + while (cnt_n <= n) { + int cnt_m = 1; + + while (cnt_m <= m) { + cout << cnt_n << " x " << cnt_m << " = " << cnt_n * cnt_m << "\n"; + cnt_m++; + } + cnt_n++; + } + + return 0; +} + diff --git a/18-Programming-4kids/08_homework_13_answer.cpp b/18-Programming-4kids/08_homework_13_answer.cpp new file mode 100644 index 0000000..0032f5b --- /dev/null +++ b/18-Programming-4kids/08_homework_13_answer.cpp @@ -0,0 +1,42 @@ +#include +using namespace std; + +int main() { + int T; + + cin >> T; + + /** + * We need 3 nested loops + * loop over test cases + * loop over reading numbers + * loop to repeat the number K times (multiplication) + */ + + while (T > 0) { + int N; + cin >> N; + + int cnt_N = 1; + int sum = 0; + while (cnt_N <= N) { + int value = 0; + cin >> value; + + int cnt_deep = cnt_N; + int result = 1; + + while (cnt_deep > 0) + result *= value, cnt_deep--; + + sum += result; + cnt_N++; + } + cout< +using namespace std; + +int main() { + int sum = 0; + + for (int x = 1; x < 6; ++x) + sum += x; + + cout< +using namespace std; + +int main() { + int T; + cin >> T; + + for (int t = 0; t < T; ++t) { + int num, sum = 0; + cin >> num; + + for (int start = 1; start <= num; ++start) + sum += start; + + cout << "Sum from 1 to " << num << " = " << sum << "\n"; + } + return 0; +} diff --git a/18-Programming-4kids/09_3.cpp b/18-Programming-4kids/09_3.cpp new file mode 100644 index 0000000..6ae186e --- /dev/null +++ b/18-Programming-4kids/09_3.cpp @@ -0,0 +1,21 @@ +#include +using namespace std; + +int main() { + int T; + cin >> T; + + for (int t = 0; t < T; ++t) { + int num, sum = 0; + cin >> num; + + int start = 1; + for (; start <= num;) { + sum += start; + ++start; + } + + cout << "Sum from 1 to " << num << " = " << sum << "\n"; + } + return 0; +} diff --git a/18-Programming-4kids/09_4.cpp b/18-Programming-4kids/09_4.cpp new file mode 100644 index 0000000..a24b1cf --- /dev/null +++ b/18-Programming-4kids/09_4.cpp @@ -0,0 +1,23 @@ +#include +using namespace std; + +int main() { + int T; + cin >> T; + + for (int t = 0; t < T; ++t) { + int num, sum = 0; + cin >> num; + + int start = 1; + for (; ;) { // ame as while (true) + if(!(start <= num)) + break; + sum += start; + ++start; + } + + cout << "Sum from 1 to " << num << " = " << sum << "\n"; + } + return 0; +} diff --git a/18-Programming-4kids/09_5.cpp b/18-Programming-4kids/09_5.cpp new file mode 100644 index 0000000..d99518a --- /dev/null +++ b/18-Programming-4kids/09_5.cpp @@ -0,0 +1,26 @@ +#include +using namespace std; + +int main() { + int N, T, value; + + cin >> T; + + while (T--) { + cin >> N; + + int sum = 0; + for (int i = 0; i < N; ++i) { + cin >> value; + + int result = 1; + for (int j = 0; j < i + 1; ++j) + result *= value; + sum += result; + } + cout << sum << "\n"; + } + + return 0; +} + diff --git a/18-Programming-4kids/09_6_A.cpp b/18-Programming-4kids/09_6_A.cpp new file mode 100644 index 0000000..c849bd7 --- /dev/null +++ b/18-Programming-4kids/09_6_A.cpp @@ -0,0 +1,21 @@ +#include +using namespace std; + +int main() { + int n, m, sum; + + cin >> n >> m >> sum; + + int cnt = 0; + + for (int i = 1; i <= n; ++i) + for (int j = 1; j <= m; ++j) + if (i + j == sum) + cnt++; + + + cout << cnt << "\n"; + + return 0; +} + diff --git a/18-Programming-4kids/09_6_B.cpp b/18-Programming-4kids/09_6_B.cpp new file mode 100644 index 0000000..8fa5020 --- /dev/null +++ b/18-Programming-4kids/09_6_B.cpp @@ -0,0 +1,24 @@ +#include +using namespace std; + +int main() { + int n, m, sum; + + cin >> n >> m >> sum; + + int cnt = 0; + + for (int i = 1; i <= n; ++i) + { + int j = sum - i; // i + j == sum + + if (1 <= j && j <= m) + cnt++; + + } + + cout << cnt << "\n"; + + return 0; +} + diff --git a/18-Programming-4kids/09_7_A.cpp b/18-Programming-4kids/09_7_A.cpp new file mode 100644 index 0000000..dc1c820 --- /dev/null +++ b/18-Programming-4kids/09_7_A.cpp @@ -0,0 +1,21 @@ +#include +using namespace std; + +int main() { + int n, m, w; + + cin >> n >> m >> w; + + int cnt = 0; + + for (int i = 1; i <= n; ++i) + for (int j = i; j <= m; ++j) + for (int k = 1; k <= w; ++k) + if (i + j <= k) + cnt++; + + cout << cnt << "\n"; + + return 0; +} + diff --git a/18-Programming-4kids/09_7_B.cpp b/18-Programming-4kids/09_7_B.cpp new file mode 100644 index 0000000..435c468 --- /dev/null +++ b/18-Programming-4kids/09_7_B.cpp @@ -0,0 +1,23 @@ +#include +using namespace std; + +int main() { + int n, m, w; + + cin >> n >> m >> w; + + int cnt = 0; + + for (int i = 1; i <= n; ++i) + for (int j = 1; j <= m; ++j) { + int k = i + j; + + if (1 <= k && k <= w) + cnt += w - k + 1; + } + +cout << cnt << "\n"; + +return 0; +} + diff --git "a/18-Programming-4kids/09_8_\331\220A.cpp" "b/18-Programming-4kids/09_8_\331\220A.cpp" new file mode 100644 index 0000000..fd3615a --- /dev/null +++ "b/18-Programming-4kids/09_8_\331\220A.cpp" @@ -0,0 +1,21 @@ +#include +using namespace std; + +int main() { + int n = 10; + + int a = 0, b = 1; + + cout< +using namespace std; + +int main() { + int n = 10; + + for (int a = 0, b = 1, c = -1, cnt = 0; cnt < n; + ++cnt, c = a + b, a = b, b = c) + cout << a << " "; + + return 0; +} + diff --git a/18-Programming-4kids/09_homework_01_answer.cpp b/18-Programming-4kids/09_homework_01_answer.cpp new file mode 100644 index 0000000..757f063 --- /dev/null +++ b/18-Programming-4kids/09_homework_01_answer.cpp @@ -0,0 +1,21 @@ +#include +using namespace std; + +int main() { + int n; + + cin>>n; + + for (int i = 0; i < n; ++i) { + for (int j = 0; j < n; ++j) { + if(i == j || n-i-1 == j) + cout<<"*"; + else + cout<<" "; + } + cout<<"\n"; + } + + return 0; +} + diff --git a/18-Programming-4kids/09_homework_02_answer_A.cpp b/18-Programming-4kids/09_homework_02_answer_A.cpp new file mode 100644 index 0000000..c55ef87 --- /dev/null +++ b/18-Programming-4kids/09_homework_02_answer_A.cpp @@ -0,0 +1,19 @@ +#include +using namespace std; + +int main() { + int count = 0; + + for (int x = 50; x <= 300; ++x) { + for (int y = 70; y <= 400; ++y) { + if (x < y && ((x + y) % 7 == 0)) { + //cout< +using namespace std; + +int main() { + int count = 0; + + for (int x = 50; x <= 300; ++x) { + // Let's speed it + // We can always start from the right condition maximum(70, x+1) + // Saves some Y iterations + // Remove the x < y condition + int start = 70; + + if (start < x+1) + start = x+1; + + for (int y = start; y <= 400; ++y) { + if ((x + y) % 7 == 0) { + //cout< +using namespace std; + +int main() { + int count = 0; + + for (int a = 1; a <= 200; ++a) { + for (int b = 1; b <= 200; ++b) { + for (int c = 1; c <= 200; ++c) { + for (int d = 1; d <= 200; ++d) { + count += (a + b == c + d); + } + } + } + } + + cout << count << "\n"; + + return 0; +} + diff --git a/18-Programming-4kids/09_homework_03_answer_B.cpp b/18-Programming-4kids/09_homework_03_answer_B.cpp new file mode 100644 index 0000000..7f9ae93 --- /dev/null +++ b/18-Programming-4kids/09_homework_03_answer_B.cpp @@ -0,0 +1,22 @@ +#include +using namespace std; + +int main() { + int count = 0; + + for (int a = 1; a <= 200; ++a) { + for (int b = 1; b <= 200; ++b) { + for (int c = 1; c <= 200; ++c) { + int d = a + b - c; + + if(1 <= d && d <= 200) + count++; + } + } + } + + cout << count << "\n"; + + return 0; +} + diff --git a/18-Programming-4kids/09_homework_04_answer.cpp b/18-Programming-4kids/09_homework_04_answer.cpp new file mode 100644 index 0000000..db486cb --- /dev/null +++ b/18-Programming-4kids/09_homework_04_answer.cpp @@ -0,0 +1,29 @@ +#include +using namespace std; + +int main() { + int number; + + cin >> number; + + if (number == 1) + cout << "NO\n"; + else { + bool is_ok = true; + + for (int i = 2; i < number; ++i) { + if (number % i == 0) { + is_ok = false; + break; + } + } + + if (is_ok) + cout << "YES"; + else + cout << "NO"; + } + + return 0; +} + diff --git a/18-Programming-4kids/09_homework_05_answer.cpp b/18-Programming-4kids/09_homework_05_answer.cpp new file mode 100644 index 0000000..68df949 --- /dev/null +++ b/18-Programming-4kids/09_homework_05_answer.cpp @@ -0,0 +1,33 @@ +#include +using namespace std; + +int main() { + int target; + bool first_print = true; + + cin >> target; + + for (int number = 2; number <= target; ++number) { + bool is_ok = true; + + for (int i = 2; i < number; ++i) { + if (number % i == 0) { + is_ok = false; + break; + } + } + + if (is_ok) + { + if(!first_print) + cout<<","; + + cout << number; + + first_print = false; + } + } + + return 0; +} + diff --git a/18-Programming-4kids/09_homework_06_answer.cpp b/18-Programming-4kids/09_homework_06_answer.cpp new file mode 100644 index 0000000..c0257d1 --- /dev/null +++ b/18-Programming-4kids/09_homework_06_answer.cpp @@ -0,0 +1,25 @@ +#include +using namespace std; + +int main() { + int n, a, b, total = 0; + + cin >> n >> a >> b; + + for (int i = 1; i <= n; ++i) { + int tmp = i; // be careful - take copy + int digits_sum = 0; + + while (tmp) { + digits_sum += tmp % 10; + tmp /= 10; + } + + if (a <= digits_sum && digits_sum <= b) + total += i; + } + cout << total << "\n"; + + return 0; +} + diff --git a/18-Programming-4kids/10_01.cpp b/18-Programming-4kids/10_01.cpp new file mode 100644 index 0000000..727dedf --- /dev/null +++ b/18-Programming-4kids/10_01.cpp @@ -0,0 +1,18 @@ +#include +using namespace std; + +int main() { + const int size = 5; + + // Declare 5 positions of type integer + int numbers[size] = {10, 2, 7, 5, 3}; + + + numbers[0] = 9; + numbers[2] *= 3; + numbers[4]++; + + cout< +using namespace std; + +int main() { + const int size = 5; + + // Declare 5 positions of type integer + int numbers[size] = {1, 2, 3, 4, 5}; + + for (int i = 0; i < size; ++i) + cout< +using namespace std; + +int main() { + const int size = 5; + + // Declare 5 positions of type integer + int numbers[size]; + + for (int i = 0; i < size; ++i) + cin >> numbers[i]; + + int minimum = numbers[0]; + for (int i = 1; i < size; ++i) + if (minimum > numbers[i]) + minimum = numbers[i]; + + cout << minimum; + + return 0; +} + diff --git a/18-Programming-4kids/10_04.cpp b/18-Programming-4kids/10_04.cpp new file mode 100644 index 0000000..9b0719b --- /dev/null +++ b/18-Programming-4kids/10_04.cpp @@ -0,0 +1,28 @@ +#include +using namespace std; + +int main() { + int n, numbers[200]; // max expected size + + cin>>n; + for (int i = 0; i < n; ++i) + cin >> numbers[i]; + + int maximum_idx = 0; + for (int i = 1; i < n; ++i) + if (numbers[maximum_idx] < numbers[i]) + maximum_idx = i; + + int max1 = numbers[maximum_idx]; + numbers[maximum_idx] = -1000000; // assume good value + + maximum_idx = 0; // same code again + for (int i = 1; i < n; ++i) + if (numbers[maximum_idx] < numbers[i]) + maximum_idx = i; + + int max2 = numbers[maximum_idx]; + cout << max1 << " " << max2; + return 0; +} + diff --git a/18-Programming-4kids/10_05.cpp b/18-Programming-4kids/10_05.cpp new file mode 100644 index 0000000..ed83e94 --- /dev/null +++ b/18-Programming-4kids/10_05.cpp @@ -0,0 +1,26 @@ +#include +using namespace std; + +int main() { + int n, numbers[200]; // max expected size + + cin >> n; + for (int i = 0; i < n; ++i) + cin >> numbers[i]; + + int max1, max2; + if (numbers[0] >= numbers[1]) + max1 = numbers[0], max2 = numbers[1]; + else + max1 = numbers[1], max2 = numbers[0]; + + for (int i = 2; i < n; ++i) + if (max1 <= numbers[i]) + max2 = max1, max1 = numbers[i]; + else if (max2 < numbers[i]) + max2 = numbers[i]; + + cout << max1 << " " << max2; + return 0; +} + diff --git a/18-Programming-4kids/10_06_bug.cpp b/18-Programming-4kids/10_06_bug.cpp new file mode 100644 index 0000000..27591d4 --- /dev/null +++ b/18-Programming-4kids/10_06_bug.cpp @@ -0,0 +1,26 @@ +#include +using namespace std; + +int main() { + int n, numbers[200]; + + cin >> n; + for (int i = 0; i < n; ++i) + cin >> numbers[i]; + + int idx1 = -1, idx2 = -1; + + for (int i = 0; i < n; ++i) { + for (int j = 0; j < n; ++j) { + if (idx1 == -1) + idx1 = i, idx2 = j; + else if (numbers[idx1] + numbers[idx2] < + numbers[i] + numbers[j]) + idx1 = i, idx2 = j; + } + } + cout< +using namespace std; + +int main() { + int n, numbers[200]; + + cin >> n; + for (int i = 0; i < n; ++i) + cin >> numbers[i]; + + int idx1 = -1, idx2 = -1; + + for (int i = 0; i < n; ++i) { + for (int j = i+1; j < n; ++j) { + if (idx1 == -1) + idx1 = i, idx2 = j; + else if (numbers[idx1] + numbers[idx2] < + numbers[i] + numbers[j]) + idx1 = i, idx2 = j; + } + } + cout< +using namespace std; + +int main() { + int n, numbers[200]; + + cin >> n; + for (int i = 0; i < n; ++i) + cin >> numbers[i]; + + for (int i = 0; i < n/2; ++i) { + int last = n - i - 1; + // swap positions: i and last + int temp = numbers[i]; + numbers[i] = numbers[last]; + numbers[last] = temp; + } + + for (int i = 0; i < n; ++i) + cout< +using namespace std; + +int main() { + int n, numbers[200]; + + cin >> n; + for (int i = 0; i < n; ++i) + cin >> numbers[i]; + + int max_value = -1, max_repeat = -1; + + for (int i = 0; i < n; ++i) + { + // count how many times numbers[i] exists + int repeat = 0; + for (int j = 0; j < n; ++j) + repeat += numbers[i] == numbers[j]; + + if (max_repeat == -1 || max_repeat < repeat) + max_repeat = repeat, max_value = numbers[i]; + } + cout< +using namespace std; + +int main() { + int n, numbers[200]; + + // Be careful: max value is 150. + // So we need to access the array at 150 + int frequency[150+1] = {0}; // {0} set all to zeros + + cin >> n; + for (int i = 0; i < n; ++i) + { + cin >> numbers[i]; + frequency[numbers[i]]++; + } + + // just find max position in the array + int max_pos = -1; + + for (int i = 0; i < 151; ++i) // Iterate on ALL array + { + if (max_pos == -1 || frequency[max_pos] < frequency[i]) + max_pos = i; + } + cout< +using namespace std; + +int main() { + int n, q, a[200]; + + cin >> n; + for (int i = 0; i < n; i++) + cin >> a[i]; + + cin >> q; + while (q--) { + int num; + cin >> num; + + int pos = -1; + // search from the end + for (int i = n-1; i >= 0; --i) { + if (a[i] == num) { + pos = i; + break; + } + } + cout << pos << "\n"; + } + return 0; +} diff --git a/18-Programming-4kids/10_homework_01_answer_2.cpp b/18-Programming-4kids/10_homework_01_answer_2.cpp new file mode 100644 index 0000000..c0fb959 --- /dev/null +++ b/18-Programming-4kids/10_homework_01_answer_2.cpp @@ -0,0 +1,28 @@ +// By Basel Bairkdar https://www.facebook.com/baselbairkdar + +#include +using namespace std; + +int main() { + // As values are 0-500, we can make array of 501 mark the last value in it + // Then we answer the queries directly + + const int N = 500 + 1; + int n, q, x, ans[N]; + + for (int i = 0; i < N; i++) + ans[i] = -1; /** at first the answer of any number is -1 **/ + + cin >> n; + for (int i = 0; i < n; i++) { + cin >> x; + ans[x] = i;/** update the answer for x to be i **/ + } + int num; + cin >> q; + while (q--) { + cin >> num; + cout << ans[num] << endl; + } + return 0; +} diff --git a/18-Programming-4kids/10_homework_02_answer.cpp b/18-Programming-4kids/10_homework_02_answer.cpp new file mode 100644 index 0000000..335ef9b --- /dev/null +++ b/18-Programming-4kids/10_homework_02_answer.cpp @@ -0,0 +1,29 @@ +// By Basel Bairkdar https://www.facebook.com/baselbairkdar + +#include +using namespace std; + + +int main() { + const int N = 200; + int n, a[N]; + + cin >> n; + for (int i = 0; i < n; i++) { + cin >> a[i]; + } + + bool increasing = 1; /** we will assume that the array is increasing at first **/ + for (int i = 1; i < n; i++) { + if (a[i] < a[i - 1]) { + increasing = 0; + break; + } + } + if (increasing) { + cout << "YES\n"; + } else { + cout << "NO\n"; + } + return 0; +} diff --git a/18-Programming-4kids/10_homework_03_answer.cpp b/18-Programming-4kids/10_homework_03_answer.cpp new file mode 100644 index 0000000..d55da62 --- /dev/null +++ b/18-Programming-4kids/10_homework_03_answer.cpp @@ -0,0 +1,36 @@ +// By Basel Bairkdar https://www.facebook.com/baselbairkdar + +#include +using namespace std; + +int main() { + + const int N = 100; + + int n, a[N], mn = 10000, mx = -1; + + cin >> n; + for (int i = 0; i < n; i++) { + cin >> a[i]; + if (a[i] < mn) { + mn = a[i]; + } + if (a[i] > mx) { + mx = a[i]; + } + } + + for (int i = 0; i < n; i++) { + if (a[i] == mn) + a[i] = mx; + else if (a[i] == mx) + a[i] = mn; + } + + for (int i = 0; i < n; i++) { + if (i) + cout << " "; + cout << a[i]; + } + return 0; +} diff --git a/18-Programming-4kids/10_homework_04_answer.cpp b/18-Programming-4kids/10_homework_04_answer.cpp new file mode 100644 index 0000000..cc2ae0c --- /dev/null +++ b/18-Programming-4kids/10_homework_04_answer.cpp @@ -0,0 +1,51 @@ +#include +using namespace std; + +int main() { + int n, tmp, mn[3]; + + cin >> n; + for (int i = 0; i < n; i++) { + int value; + cin >> value; + + if (i < 3) + mn[i] = value; + else { + // Find maximum position + int mx_pos = 0; + for (int j = 1; j < 3; ++j) { + if (mn[mx_pos] < mn[j]) + mx_pos = j; + } + + if (value < mn[mx_pos]) + mn[mx_pos] = value; + } + } + + // let's order the first 3 values. We can do in several ways + // Find maximum position + int mx_pos = 0; + for (int j = 1; j < 3; ++j) { + if (mn[mx_pos] < mn[j]) + mx_pos = j; + } + // swap max with last + tmp = mn[2]; + mn[2] = mn[mx_pos]; + mn[mx_pos] = tmp; + + // Swap first 2 elements if needed + if (mn[0] > mn[1]) { + tmp = mn[0]; + mn[0] = mn[1]; + mn[1] = tmp; + } + + for (int i = 0; i < 3; i++) + cout << mn[i] << " "; // not ordered + + + return 0; +} diff --git a/18-Programming-4kids/10_homework_05_answer.cpp b/18-Programming-4kids/10_homework_05_answer.cpp new file mode 100644 index 0000000..9e971c5 --- /dev/null +++ b/18-Programming-4kids/10_homework_05_answer.cpp @@ -0,0 +1,34 @@ +// By Basel Bairkdar https://www.facebook.com/baselbairkdar - modified +#include +using namespace std; + +int main() { + const int N = 200; + + int n, a[N]; + + cin >> n; + for (int i = 0; i < n; i++) + cin >> a[i]; + + /** + let's calculate Ai+Aj+j-i for every pair (i,j) + such that i < j + this can be done using nested for loops. + **/ + // let's use some big value and later minimize + int mn; + bool first_time = true; + + for (int i = 0; i < n; i++) { + for (int j = i + 1; j < n; j++) { + int tmp = a[i] + a[j] + j - i; + if (first_time || tmp < mn) { + mn = tmp; + first_time = false; + } + } + } + cout << mn << endl; + return 0; +} diff --git a/18-Programming-4kids/10_homework_06_answer.cpp b/18-Programming-4kids/10_homework_06_answer.cpp new file mode 100644 index 0000000..0094f53 --- /dev/null +++ b/18-Programming-4kids/10_homework_06_answer.cpp @@ -0,0 +1,32 @@ +// By Amr Keleg https://www.facebook.com/amr.keleg + +#include +using namespace std; + +int main() { + // The size of the array should be larger than + // the maximum value of N + int arr[1000]; + + int N; + cin >> N; + + for (int i = 0; i < N; i++) + cin >> arr[i]; + + // We need to compare the value at the left half + // to those in the right half + // The value at index (0) should be compared to the value at index (N-1) + // Then the value at index (1) should be compared to the value at index (N-2) + // So, clearly we need to increment the left index and decrement the right one + // On reaching the index N/2, we are sure that we have compared all the elements + // of both sides so we don't need to do anything and the array is palindrome + for (int i = 0; i < N / 2; i++) { + if (arr[i] != arr[N - 1 - i]) { + cout << "NO"; + return 0; + } + } + cout << "YES"; + return 0; +} diff --git a/18-Programming-4kids/10_homework_07_answer.cpp b/18-Programming-4kids/10_homework_07_answer.cpp new file mode 100644 index 0000000..9e0e16d --- /dev/null +++ b/18-Programming-4kids/10_homework_07_answer.cpp @@ -0,0 +1,24 @@ +#include +using namespace std; + +int main() { + int n; + cin >> n; + const int MAX = 270 + 500 + 1; + int frequency[MAX] = { 0 }; // initialize with zeros. You can't do for other values (e.g. 1) this way. + + for (int i = 0; i < n; i++) { + int value; + cin >> value; + + value += 500; // shift all values to be positive + frequency[value]++; + } + + int mx_pos = 0; + for (int i = 1; i < MAX; i++) { + if (frequency[mx_pos] < frequency[i]) + mx_pos = i; + } + cout << mx_pos - 500 << " has repeated " << frequency[mx_pos] << " times "; +} diff --git a/18-Programming-4kids/10_homework_08_answer.cpp b/18-Programming-4kids/10_homework_08_answer.cpp new file mode 100644 index 0000000..eadf32c --- /dev/null +++ b/18-Programming-4kids/10_homework_08_answer.cpp @@ -0,0 +1,27 @@ +// By Amr Fahim https://www.facebook.com/amrfahim2020 +// Homework 8 solution + +#include +using namespace std; + +int main() { + int n, x, occurrence[10] = {0}; + + cin >> n; + + for (int i = 0; i < n; i++) { + cin >> x; + + while (x) { + int digit = x % 10; + occurrence[digit]++; + x /= 10; + } + + } + for (int i = 0; i <= 9; i++) { + cout << i << " " << occurrence[i] << endl; + } + +} + diff --git a/18-Programming-4kids/10_homework_09_answer.cpp b/18-Programming-4kids/10_homework_09_answer.cpp new file mode 100644 index 0000000..7fb1479 --- /dev/null +++ b/18-Programming-4kids/10_homework_09_answer.cpp @@ -0,0 +1,29 @@ +// By Amr Fahim https://www.facebook.com/amrfahim2020 +// Homework 9 solution +#include +using namespace std; + +int main() { + const int N = 201; // Be careful. We need 201 values NOT 200 + int sequence[N], indx; + + int occurrence[N * 10] = { 0 }; // possibly i-th value is much less than 10 * i + + cin >> indx; + sequence[0] = 0; + occurrence[0] = 1; // use a value as an index in the array + + for (int i = 1; i <= indx; i++) { + int cur = sequence[i - 1] - (i - 1) - 1; + + if (cur < 0 || occurrence[cur]) + cur = sequence[i - 1] + (i - 1) + 1; + + sequence[i] = cur; + occurrence[cur] = 1; + } + + cout << sequence[indx]; + +} + diff --git a/18-Programming-4kids/10_homework_10_answer_1.cpp b/18-Programming-4kids/10_homework_10_answer_1.cpp new file mode 100644 index 0000000..613d332 --- /dev/null +++ b/18-Programming-4kids/10_homework_10_answer_1.cpp @@ -0,0 +1,26 @@ +#include +using namespace std; + +int main() { + const int N = 200; + int n, arr[N], k, min_index, max_sum = -10000000; + + cin >> k >> n; + for (int i = 0; i < n; i++) + cin >> arr[i]; + + for (int i = 0; i < n - k + 1; i++) { + int sum = 0; + for (int j = 0; j < k; ++j) + sum += arr[i + j]; + + if (sum > max_sum) { + max_sum = sum; + min_index = i; + + } + } + cout << min_index << " " << min_index + k - 1 << " " << max_sum << "\n"; + +} + diff --git a/18-Programming-4kids/10_homework_10_answer_2.cpp b/18-Programming-4kids/10_homework_10_answer_2.cpp new file mode 100644 index 0000000..2681455 --- /dev/null +++ b/18-Programming-4kids/10_homework_10_answer_2.cpp @@ -0,0 +1,31 @@ +#include +using namespace std; + +int main() { + const int N = 200; + int n, k; + int arr[N]; + + cin >> k >> n; + for (int i = 0; i < n; i++) + cin >> arr[i]; + + int max_sum = 0; // First k values + int min_index = 0; + for (int i = 0; i < k; i++) + max_sum += arr[i]; + + int sum = max_sum; + for (int i = k; i < n; i++) { + // remove element before and add current element. Now they are new k elements + sum = sum - arr[i - k] + arr[i]; + + if (sum > max_sum) { + max_sum = sum; + min_index = i - (k - 1); + } + } + cout << min_index << " " << min_index + k - 1 << " " << max_sum << "\n"; + +} + diff --git a/18-Programming-4kids/10_homework_10_answer_3.cpp b/18-Programming-4kids/10_homework_10_answer_3.cpp new file mode 100644 index 0000000..a5fa948 --- /dev/null +++ b/18-Programming-4kids/10_homework_10_answer_3.cpp @@ -0,0 +1,31 @@ +// By Amr Fahim https://www.facebook.com/amrfahim2020 +// Homework 10 solution + +#include +using namespace std; + +int main() { + const int N = 200; + int n, arr[N] = {0}, k, min_index, max_sum = -10000000; + + cin >> k >> n; + // Note that we deal with 1-base array + for (int i = 1; i <= n; i++) { + cin >> arr[i]; + + // Cumulative sum for the array to get sum of subarray without nested loop + // Each element of the array carries the sum of all previous elements + arr[i] += arr[i - 1]; + } + + for (int i = k; i <= n; i++) { + if (arr[i] - arr[i - k] > max_sum) { + max_sum = arr[i] - arr[i - k]; + min_index = i - k + 1; + + } + } + cout << min_index-1 << " " << min_index + k -2<< " " << max_sum << "\n"; + +} + diff --git a/18-Programming-4kids/10_homework_11_answer_1.cpp b/18-Programming-4kids/10_homework_11_answer_1.cpp new file mode 100644 index 0000000..84032af --- /dev/null +++ b/18-Programming-4kids/10_homework_11_answer_1.cpp @@ -0,0 +1,33 @@ +// By Ayman Salah https://www.facebook.com/ayman.salah.abdelaziz +#include +using namespace std; + +int main() { + int a[200]; + + int n; + cin >> n; + + for (int i = 0; i < n; i++) + cin >> a[i]; + + int result = 0; + + // For every possible array length + // Try all possible sub-arrays + // Verify and sum + for (int len = 1; len <= n; ++len) { + for (int st = 0; st < n - len + 1; ++st) { + bool is_ok = true; + for (int k = 1; k < len && is_ok; ++k) { + if (a[st + k] <= a[st + k - 1]) + is_ok = false; + } + result += is_ok; + } + } + + cout << result << endl; + + return 0; +} diff --git a/18-Programming-4kids/10_homework_11_answer_2.cpp b/18-Programming-4kids/10_homework_11_answer_2.cpp new file mode 100644 index 0000000..d757636 --- /dev/null +++ b/18-Programming-4kids/10_homework_11_answer_2.cpp @@ -0,0 +1,40 @@ +// By Ayman Salah https://www.facebook.com/ayman.salah.abdelaziz +#include +using namespace std; + +int main() { + int a[200]; + + int n; + cin >> n; + + for (int i = 0; i < n; i++) + cin >> a[i]; + + int result = 0; + + // for every index i in the array we consider it as the start of a subarry + for (int i = 0; i < n; i++) { + // adding one to result because any subarray of size one considered increasing + // this subarray will include the value in index i + result++; + // trying expanding a subarray which starts with at index i and + // if this subarray still increasing then we add one to our result + // otherwise we should stop expanding this subarray + for (int j = i + 1; j < n; j++) { + // if the current value is greater than or equal the previous one + // then it's increasing + if (a[j] >= a[j - 1]) + result++; + // otherwise stop + else + break; + } + } + + // printing the result + cout << result << endl; + + return 0; +} + diff --git a/18-Programming-4kids/10_homework_11_answer_3.cpp b/18-Programming-4kids/10_homework_11_answer_3.cpp new file mode 100644 index 0000000..47ec48e --- /dev/null +++ b/18-Programming-4kids/10_homework_11_answer_3.cpp @@ -0,0 +1,36 @@ +#include +using namespace std; + +int main() { + int a[200]; + + int n; + cin >> n; + + for (int i = 0; i < n; i++) + cin >> a[i]; + + int result = 0; + int len = 1; + + + // Let say we have increasing sequence of length 4. It means we have 4*5/2 valid sub arrays + // So, find each maximual sub-sequence and add them using n*(n+1) /2 + // Or just increment with length each time we extend it + + + // We will count sequence of length > 1. Later add +n + for (int i = 1; i < n; i++) { + // Keep expand len as long as the sub-array is increasing. + if (a[i - 1] <= a[i]) { + result += len; + ++len; + } else + len = 1; + } + + cout << result + n << endl; + + return 0; +} + diff --git a/18-Programming-4kids/10_homework_12_answer.cpp b/18-Programming-4kids/10_homework_12_answer.cpp new file mode 100644 index 0000000..c57ac50 --- /dev/null +++ b/18-Programming-4kids/10_homework_12_answer.cpp @@ -0,0 +1,58 @@ +#include +using namespace std; + +int main() { + int n, k; + + cin >> n >> k; + + // Let's mark them in 0-based array + bool is_removed[200] = { 0 }; + + int last_pos = 0; // The first position to simulate from it + + // We will just simulate the running. + // Start from last killed position + // Count K times, but skip these killed positions already + for (int t = 0; t < n; ++t) { + int remaining_alive = n - t; + + int current_k = k; + // Ignore this if/else condition for now. See bottom of code. It is for handling very large K + if (k % remaining_alive == 0) + current_k = remaining_alive; + else + current_k = k % remaining_alive; + + int step = 0; + int last_person = -1; + while (step < current_k) { + if (is_removed[last_pos] == 0) // not removed. consider it and increment the step + last_person = last_pos, step++; + last_pos = (last_pos + 1) % n; // loop back to the array if needed + } + is_removed[last_person] = 1; + cout << last_person + 1 << "\n"; + last_person = -10; + } + /* + * About the if else. We want to handle when k is so big + * Let's say remaining_alive = 4 and k = 6 + * This is the same as if k = 2 (6%4 = 2) + * + * Similarly + * Let's say remaining_alive = 4 and k = 6 + * This is the same as if k = 2 (10%4 = 2) + * + * This is the same as the useless cycles in the clock + * 4 is same as any 4 + k*12 + * + * So in general, we don't need to iterate k times + * we only need: k % remaining_alive + * + * But we need 1 special case handling to k % remaining_alive == 0 + * In this case we iterate remaining_alive steps + */ + + return 0; +} diff --git a/18-Programming-4kids/10_homework_13_answer_1.cpp b/18-Programming-4kids/10_homework_13_answer_1.cpp new file mode 100644 index 0000000..2d10253 --- /dev/null +++ b/18-Programming-4kids/10_homework_13_answer_1.cpp @@ -0,0 +1,86 @@ +// By Ayman Salah https://www.facebook.com/ayman.salah.abdelaziz +#include +using namespace std; + +int main() { + + // declaring a variable to store size of the array + int n; + // declaring the array itself to store the values in it + // notice here the maximum size of any given array in the problem will be 1000 + int a[1000]; + + // reading size of the array + cin >> n; + + // reading array values + for (int i = 0; i < n; i++) + cin >> a[i]; + + // we can solve this problem with more than one way + + // ====================================== + // let's start with the easist one + + // declaring a variable to store the length of the maximum subarray + // that has zeros count equals ones count + // intially we have an empty subarray with length 0 + int maxSubarrayLength = 0; + + // declaring a variable to store the start index of maximum subarray with our condition + // intially we set this value with -1, that means we didn't find any subarray + int maxSubarrayStartIndex = -1; + + // the same with the end index + int maxSubarrayEndIndex = -1; + + // simply we try all start and end indices of subarrays + for (int start = 0; start < n; start++) { + for (int end = start; end < n; end++) { + // intializing a variable to hold zeros count + int zerosCount = 0; + // intializing a variable to hold ones count + int onesCount = 0; + + // another loop to count zeros and ones in subarray [start, end] + for (int i = start; i <= end; i++) { + // if value at index i equals one then add one to onesCount + if (a[i] == 1) + onesCount++; + // if value at index i equals zero then add one to zerosCount + else if (a[i] == 0) + zerosCount++; + } + // checking if zeros count equals ones count or not + if (zerosCount == onesCount) { + // calculating length of current subarray + int subarrayLength = end - start + 1; + + // checking if the length of this subarray is larger than the current maximum one or not + if (subarrayLength > maxSubarrayLength) { + // setting current max length with this value + maxSubarrayLength = subarrayLength; + // changing start and end index as well + maxSubarrayStartIndex = start; + maxSubarrayEndIndex = end; + } + + } + } + } + + // checking if we found a subarray with this conditions or not + if (maxSubarrayLength == 0) + cout << "NOT FOUND" << endl; + else { + // a subarray is found, + // printing it's length + cout << maxSubarrayLength << endl; + // printing it's values + for (int i = maxSubarrayStartIndex; i <= maxSubarrayEndIndex; i++) + cout << a[i] << " "; + cout << endl; + } + + return 0; +} diff --git a/18-Programming-4kids/10_homework_13_answer_2.cpp b/18-Programming-4kids/10_homework_13_answer_2.cpp new file mode 100644 index 0000000..f8cb2aa --- /dev/null +++ b/18-Programming-4kids/10_homework_13_answer_2.cpp @@ -0,0 +1,53 @@ +// By Ayman Salah https://www.facebook.com/ayman.salah.abdelaziz +#include +using namespace std; + +int main() { + + int n; + int a[1000]; + + cin >> n; + + for (int i = 0; i < n; i++) + cin >> a[i]; + + int maxSubarrayLength1 = 0; + int maxSubarrayStartIndex1 = -1; + int maxSubarrayEndIndex1 = -1; + + for (int start = 0; start < n; start++) { + int zerosCount = 0; + int onesCount = 0; + + // While expanding a sub-array just check if it is 0 or 1 + + for (int end = start; end < n; end++) { + if (a[end] == 0) + zerosCount++; + else if (a[end] == 1) + onesCount++; + + if (zerosCount == onesCount) { + int subarrayLength = end - start + 1; + if (subarrayLength > maxSubarrayLength1) { + maxSubarrayLength1 = subarrayLength; + maxSubarrayStartIndex1 = start; + maxSubarrayEndIndex1 = end; + } + } + } + } + + if (maxSubarrayLength1 == 0) + cout << "NOT FOUND" << endl; + else { + cout << maxSubarrayLength1 << endl; + for (int i = maxSubarrayStartIndex1; i <= maxSubarrayEndIndex1; i++) + cout << a[i] << " "; + cout << endl; + } + + + return 0; +} diff --git a/18-Programming-4kids/10_homework_13_answer_3.cpp b/18-Programming-4kids/10_homework_13_answer_3.cpp new file mode 100644 index 0000000..648f330 --- /dev/null +++ b/18-Programming-4kids/10_homework_13_answer_3.cpp @@ -0,0 +1,62 @@ +#include +using namespace std; + +int main() { + + int n; + int a[1000]; + int difference[1000*2+1]; // maximum 2000 values with shift 1000 + + // mark the difference as never appeared + for (int i = 0; i < 2001; ++i) + difference[i] = 99999; + + cin >> n; + + for (int i = 0; i < n; i++) + cin >> a[i]; + + int maxSubarrayLength1 = 0; + int maxSubarrayStartIndex1 = -1; + int maxSubarrayEndIndex1 = -1; + + int added = 0; + + difference[0+1000] = -1; // difference 0 appears before the array (-1) + + for (int i = 0; i < n; i++) + { + if(a[i] == 1) + added += 1; + else + added -= 1; + + int shift = added + 1000; // shift to make sure positive + + if(difference[shift] == 99999) + difference[shift] = i; // first time for such accumulated difference to appear + else { + int subarrayLength = i - difference[shift]; + + if (subarrayLength > maxSubarrayLength1) { + maxSubarrayLength1 = subarrayLength; + maxSubarrayStartIndex1 = difference[shift]+1; + maxSubarrayEndIndex1 = i; + } + } + } + + if (maxSubarrayLength1 == 0) + cout << "NOT FOUND" << endl; + else { + cout << maxSubarrayLength1 << endl; + for (int i = maxSubarrayStartIndex1; i <= maxSubarrayEndIndex1; i++) + cout << a[i] << " "; + cout << endl; + } + // By adding 0 as -1 values, each group of equal ones and zeros + // is actually sub-array of sum zero + + + return 0; +} diff --git a/18-Programming-4kids/11_01.cpp b/18-Programming-4kids/11_01.cpp new file mode 100644 index 0000000..e35ca99 --- /dev/null +++ b/18-Programming-4kids/11_01.cpp @@ -0,0 +1,29 @@ +#include +using namespace std; + +int main() { + char ch1 = 'A'; + int ch_value = ch1; + + cout< +using namespace std; + +int main() { + char ch1 = 'D'; + + if ('A' <= ch1 && ch1 <= 'Z') { + cout << ch1 << " is an upper case\n"; + ch1 = ch1 - 'A' + 'a'; + cout << ch1 << " now is a lower case\n"; + } else if ('z' <= ch1 && ch1 <= 'z') + cout << ch1 << " is already a lower case\n"; + else if ('0' <= ch1 && ch1 <= '9') + cout << ch1 << " is a digit\n"; + else + cout << ch1 << " is neither a digit nor a letter\n"; + + return 0; +} + diff --git a/18-Programming-4kids/11_03.cpp b/18-Programming-4kids/11_03.cpp new file mode 100644 index 0000000..b217a9e --- /dev/null +++ b/18-Programming-4kids/11_03.cpp @@ -0,0 +1,17 @@ +#include +using namespace std; + +int main() { + string name = "Hany"; + + int sz = name.size(); // called function/method + cout << sz << "\n"; // 4 + + cout << name << "\n"; + + for (int i = 0; i < sz; ++i) + cout << name[i]; // internally array + + return 0; +} + diff --git a/18-Programming-4kids/11_04.cpp b/18-Programming-4kids/11_04.cpp new file mode 100644 index 0000000..5fac77d --- /dev/null +++ b/18-Programming-4kids/11_04.cpp @@ -0,0 +1,18 @@ +#include +using namespace std; + +int main() { + int numbers[5] = { 1, 2, 3, 4, 5 }; + + char name1[5] = { 'H', 'a', 'n', 'i' }; // 5 not 4 + char name2[5] = "Hani"; + + string name3 = "Hani"; + + cout << name1 << "\n"; + cout << name2 << "\n"; + cout << name3 << "\n"; + + return 0; +} + diff --git a/18-Programming-4kids/11_05.cpp b/18-Programming-4kids/11_05.cpp new file mode 100644 index 0000000..1f082e0 --- /dev/null +++ b/18-Programming-4kids/11_05.cpp @@ -0,0 +1,16 @@ +#include +using namespace std; + +int main() { + + char name1[4]; + name1[0] = 'H'; + name1[1] = 'a'; + name1[2] = 'n'; + name1[3] = 'i'; + + cout << name1 << "\n"; + + return 0; +} + diff --git a/18-Programming-4kids/11_06.cpp b/18-Programming-4kids/11_06.cpp new file mode 100644 index 0000000..0c0d929 --- /dev/null +++ b/18-Programming-4kids/11_06.cpp @@ -0,0 +1,17 @@ +#include +using namespace std; + +int main() { + + char name1[5]; + name1[0] = 'H'; + name1[1] = 'a'; + name1[2] = 'n'; + name1[3] = 'i'; + name1[4] = '\0'; // Null character + + cout << name1 << "\n"; + + return 0; +} + diff --git a/18-Programming-4kids/11_07.cpp b/18-Programming-4kids/11_07.cpp new file mode 100644 index 0000000..fc6cd74 --- /dev/null +++ b/18-Programming-4kids/11_07.cpp @@ -0,0 +1,17 @@ +#include +using namespace std; + +int main() { + + char name1[5]; + name1[0] = 'H'; + name1[1] = '\0'; + name1[2] = 'n'; + name1[3] = 'i'; + name1[4] = '\0'; // Null character + + cout << name1 << "\n"; + + return 0; +} + diff --git a/18-Programming-4kids/11_08.cpp b/18-Programming-4kids/11_08.cpp new file mode 100644 index 0000000..69b40b8 --- /dev/null +++ b/18-Programming-4kids/11_08.cpp @@ -0,0 +1,17 @@ +#include +using namespace std; + +int main() { + + string name1; + getline(cin, name1); + cout< +using namespace std; + +int main() { + + // Array of names - each name is sequence of letters! + string names[5] = {"Mostafa Saad", "Never Ever", "Hello world"}; + + for (int i = 0; i < 5; ++i) + cout< +using namespace std; + +int main() { + + // Array of names - each name is sequence of letters! + string names[2]; + + for (int i = 0; i < 2; ++i) + cin>>names[i]; + + return 0; +} + diff --git a/18-Programming-4kids/11_11.cpp b/18-Programming-4kids/11_11.cpp new file mode 100644 index 0000000..331c8dd --- /dev/null +++ b/18-Programming-4kids/11_11.cpp @@ -0,0 +1,13 @@ +#include +using namespace std; + +int main() { + + // Escape characters + cout<<"hello\tworld\n"; + cout<<"\0"; + cout<<"Let's print a double quote \" "; + + return 0; +} + diff --git a/18-Programming-4kids/11_11z.cpp b/18-Programming-4kids/11_11z.cpp new file mode 100644 index 0000000..0063323 --- /dev/null +++ b/18-Programming-4kids/11_11z.cpp @@ -0,0 +1,34 @@ +#include +using namespace std; + +// Practice count words + + +int main() { + string line; + getline(cin, line); + + int cnt = 0; + + int pos = 0; + + while (pos < line.size()) + { + // skip characters: space and tabs + while (pos < line.size() && (line[pos] == ' ' || line[pos] == '\t')) + pos++; + + if (pos >= line.size()) + break; // ended + + // we have a new word. let's read it + cnt++; + while (pos < line.size() && !(line[pos] == ' ' || line[pos] == '\t')) + pos++; + } + cout< +using namespace std; + +int main() { + string first, second; + + cin >> first >> second; + + int mx_sz = first.size(); + + if (mx_sz < second.size()) + mx_sz = second.size(); + + for (int i = 0; i < mx_sz; ++i) { + if (i < first.size()) + cout << first[i]; + + if (i < second.size()) + cout << second[i]; + } + + cout << "\n"; + return 0; +} diff --git a/18-Programming-4kids/11_13.cpp b/18-Programming-4kids/11_13.cpp new file mode 100644 index 0000000..c561c54 --- /dev/null +++ b/18-Programming-4kids/11_13.cpp @@ -0,0 +1,20 @@ +#include +using namespace std; + +int main() { + string str; + + cin >> str; + + int frequency[150] = {0}; // initalize to zeros + + for (int i = 0; i < str.size(); ++i) + frequency[str[i]]++; // Use char as frequency + + for (int i = 'a'; i <= 'z'; ++i) { + if (frequency[i]) + cout << (char) i << " " << frequency[i] << "\n"; + } + + return 0; +} diff --git a/18-Programming-4kids/11_14.cpp b/18-Programming-4kids/11_14.cpp new file mode 100644 index 0000000..5d1695d --- /dev/null +++ b/18-Programming-4kids/11_14.cpp @@ -0,0 +1,25 @@ +#include +using namespace std; + +int main() { + string from = "abcdefghijklmnopqrstuvwxyz0123456789"; + string to = "YZIMNESTODUAPWXHQFBRJKCGVL!@#$%^&*()"; + + char letter_map[150] = {0}; + + for (int i = 0; i < from.size(); ++i) + letter_map[from[i]] = to[i]; + + string str; + cin>>str; + + for (int i = 0; i < str.size(); ++i) { + if('A' <= str[i] && str[i] <= 'Z') + continue; + + str[i] = letter_map[str[i]]; + } + cout< +using namespace std; + +int main() { + //freopen("c.in", "rt", stdin); + + const int MAX = 10000; + + string names[MAX]; + int ages[MAX]; + double salaries[MAX]; + char genders[MAX]; + int added = 0; // Number of employees + + while (true) { + int choice = -1; + cout << "\nEnter your choice:\n"; + cout << "1) Add new employee\n"; + cout << "2) Print all employees\n"; + cout << "3) Delete by age\n"; + cout << "4) Update Salary by name\n"; + + cin >> choice; + + //if (cin.fail()) break; + + if (!(1 <= choice && choice <= 4)) { + cout << "Invalid choice. Try again\n"; + continue; + } + + if (choice == 1) { + cout << "Enter name: "; + cin >> names[added]; + + cout << "Enter age: "; + cin >> ages[added]; + + cout << "Enter salary: "; + cin >> salaries[added]; + + cout << "Enter gender (M/F): "; + cin >> genders[added]; + ++added; + } else if (choice == 2) { + cout << "****************************\n"; + for (int i = 0; i < added; ++i) { + if (ages[i] != -1) + cout << names[i] << " " << ages[i] << " " << salaries[i] + << " " << genders[i] << "\n"; + } + } else if (choice == 3) { + cout << "Enter start and end age: "; + int start, end; + cin >> start >> end; + + for (int i = 0; i < added; ++i) { + if (start <= ages[i] && ages[i] <= end) + ages[i] = -1;// Let's mark a removed entry with -1 (lazy delete) + } + } else { + cout << "Enter the name and salary: "; + string name; + int salary; + cin >> name >> salary; + + bool is_found = false; + for (int i = 0; i < added; ++i) { + if (ages[i] != -1 && names[i] == name) { + is_found = true; + salaries[i] = salary; + break; + } + } + if (!is_found) + cout << "No employee with this name!\n"; + } + } + return 0; +} + diff --git a/18-Programming-4kids/11_homework_1_answer.cpp b/18-Programming-4kids/11_homework_1_answer.cpp new file mode 100644 index 0000000..9944183 --- /dev/null +++ b/18-Programming-4kids/11_homework_1_answer.cpp @@ -0,0 +1,24 @@ +#include +using namespace std; + +int main() { + string big_str, small_str; + + cin >> big_str >> small_str; + + if (small_str.size() > big_str.size()) { + cout << "NO\n"; + return 0; + } + + // Compare the begin of the small with the large + for (int i = 0; i < (int) small_str.size(); i++) { + if (big_str[i] != small_str[i]) { + cout << "NO\n"; + return 0; + } + } + cout << "YES\n"; + + return 0; +} diff --git a/18-Programming-4kids/11_homework_2_answer.cpp b/18-Programming-4kids/11_homework_2_answer.cpp new file mode 100644 index 0000000..eb905e2 --- /dev/null +++ b/18-Programming-4kids/11_homework_2_answer.cpp @@ -0,0 +1,29 @@ +#include +using namespace std; + +// test +// aaa aaaaaaa NO +// aa AA NO + +int main() { + string big_str, small_str; + cin >> big_str >> small_str; + + if (small_str.size() > big_str.size()) { + cout << "NO\n"; + return 0; + } + + // Compare the end of the small with the large + int big_end = (int)big_str.size()-1; + int small_end = (int) small_str.size()-1; + for (int i = 0; i < (int) small_str.size(); i++) { + if (big_str[big_end--] != small_str[small_end--]) { + cout << "NO\n"; + return 0; + } + } + cout << "YES\n"; + + return 0; +} diff --git a/18-Programming-4kids/11_homework_3_answer.cpp b/18-Programming-4kids/11_homework_3_answer.cpp new file mode 100644 index 0000000..5e1e78c --- /dev/null +++ b/18-Programming-4kids/11_homework_3_answer.cpp @@ -0,0 +1,29 @@ +#include +using namespace std; + +int main() { + string big_str, small_str; + cin >> big_str >> small_str; + + if (small_str.size() > big_str.size()) { + cout << "NO\n"; + return 0; + } + + // For every possible position in big_str, try to match with the small + for (int i = 0; i < (int) big_str.size() - (int) small_str.size() + 1; ++i) { + bool is_match = true; + + for (int j = 0; j < (int) small_str.size() && is_match; ++j) { + if (small_str[j] != big_str[i + j]) + is_match = false; + } + if (is_match) { + cout << "YES\n"; + return 0; + } + } + cout << "NO\n"; + + return 0; +} diff --git a/18-Programming-4kids/11_homework_4_answer.cpp b/18-Programming-4kids/11_homework_4_answer.cpp new file mode 100644 index 0000000..5c6caba --- /dev/null +++ b/18-Programming-4kids/11_homework_4_answer.cpp @@ -0,0 +1,27 @@ +#include +using namespace std; + +int main() { + string big_str, small_str; + cin >> big_str >> small_str; + + if (small_str.size() > big_str.size()) { + cout << "NO\n"; + return 0; + } + + // Keep match letters in order from the big in the small + int next_to_match = 0; + for (int i = 0; i < (int) big_str.size(); ++i) { + if (big_str[i] == small_str[next_to_match]) { + ++next_to_match; + if (next_to_match == (int)small_str.size()) { + cout << "YES\n"; + return 0; + } + } + } + cout << "NO\n"; + + return 0; +} diff --git a/18-Programming-4kids/11_homework_5_answer.cpp b/18-Programming-4kids/11_homework_5_answer.cpp new file mode 100644 index 0000000..686cea4 --- /dev/null +++ b/18-Programming-4kids/11_homework_5_answer.cpp @@ -0,0 +1,17 @@ +#include +using namespace std; + +int main() { + int number = 0; + string str; + + cin >> str; + // How to convert digits 1 2 3 4 5 to 12345? + // Repeat: multiply with 10 then add digit + // 1 => 10 + 2 = 12 => 12 * 10 + 3 = 123 => 123 * 10 + 4 = 1234 => 1234 * 10 + 5 = 12345 + for (int i = 0; i < (int)str.size(); i++) { + number = number * 10 + (str[i] - '0'); + } + cout << number << " " << number * 3 << endl; + return 0; +} diff --git a/18-Programming-4kids/11_homework_6_answer.cpp b/18-Programming-4kids/11_homework_6_answer.cpp new file mode 100644 index 0000000..e72272d --- /dev/null +++ b/18-Programming-4kids/11_homework_6_answer.cpp @@ -0,0 +1,14 @@ +#include +using namespace std; + +int main() { + string str; + cin >> str; + + for (int i = 0; i < (int) str.size(); i++) { + if (i != 0 && str[i - 1] != str[i]) // new group, split by space + cout <<" "; + cout << str[i]; + } + return 0; +} diff --git a/18-Programming-4kids/11_homework_7_answer.cpp b/18-Programming-4kids/11_homework_7_answer.cpp new file mode 100644 index 0000000..64b3d85 --- /dev/null +++ b/18-Programming-4kids/11_homework_7_answer.cpp @@ -0,0 +1,25 @@ +#include +using namespace std; + +int main() { + string str; + cin >> str; + + str += "$"; // a small trick to avoid special handling for last group + + int group_sz = 1; // for first letter + bool is_first_group = true; // easy mark to avoid early _ + + for (int i = 1; i < (int) str.size(); i++) { // start from 1 + if (str[i - 1] != str[i]) { // new group + if (!is_first_group) + cout << "_"; // split with previous group + cout << str[i - 1] << group_sz; + + group_sz = 0; + is_first_group = 0; + } + ++group_sz; + } + return 0; +} diff --git a/18-Programming-4kids/11_homework_8_answer.cpp b/18-Programming-4kids/11_homework_8_answer.cpp new file mode 100644 index 0000000..617cbf3 --- /dev/null +++ b/18-Programming-4kids/11_homework_8_answer.cpp @@ -0,0 +1,36 @@ +#include +using namespace std; + +int main() { + string a, b; + + cin >> a >> b; + + int sz = a.size(); + + if (sz < b.size()) + sz = b.size(); + + int smaller = -1; + + for (int i = 0; smaller == -1 && i < sz; ++i) { + if (a[i] != b[i]) { + if (a[i] < b[i]) + smaller = 0; + else + smaller = 1; + } + } + if (smaller == -1) { // then the first letters are common. Small in length is smaller + if (a.size() <= b.size()) + smaller = 0; + else + smaller = 1; + } + if (smaller == 0) + cout << "YES\n"; + else + cout << "NO\n"; + + return 0; +} diff --git a/18-Programming-4kids/11_homework_9_answer.cpp b/18-Programming-4kids/11_homework_9_answer.cpp new file mode 100644 index 0000000..0dc953a --- /dev/null +++ b/18-Programming-4kids/11_homework_9_answer.cpp @@ -0,0 +1,32 @@ +#include +using namespace std; + +int main() { + string num; + + // Guarantee input: must be 6 digits or more + cin >> num; + + int sz = num.size(); + + int carry = 0; + for (int i = 0; i < sz; ++i) { + int digit = num[sz - 1 - i] - '0'; + + if (i < 4) + digit += 5; // add 5 in first 4 times + digit += carry; // add any carry + + if (digit >= 10) + digit -= 10, carry = 1; + else + carry = 0; + + num[sz - 1 - i] = digit + '0'; + } + if(carry) + cout<<1; + cout << num; + + return 0; +} diff --git a/18-Programming-4kids/12_1.cpp b/18-Programming-4kids/12_1.cpp new file mode 100644 index 0000000..dff8f59 --- /dev/null +++ b/18-Programming-4kids/12_1.cpp @@ -0,0 +1,21 @@ +#include +using namespace std; + +int main() { + + double grades[7][6] = {0}; + + // Mostafa Grades + grades[0][0] = 50, grades[0][1] = 33, grades[0][2] = 40, grades[0][3] = 30; + + // Asmaa Grades + grades[1][0] = 35, grades[1][1] = 50, grades[1][2] = 40, grades[1][3] = 30; + + // And so on + + // Mona Grades + grades[6][0] = 35, grades[6][1] = 30, grades[6][2] = 47, grades[6][3] = 16; + + return 0; +} + diff --git a/18-Programming-4kids/12_10.cpp b/18-Programming-4kids/12_10.cpp new file mode 100644 index 0000000..4d63cea --- /dev/null +++ b/18-Programming-4kids/12_10.cpp @@ -0,0 +1,44 @@ +#include +using namespace std; + +int main() { + int arr[100][100]; + + int rows, cols; + cin >> rows >> cols; + + for (int i = 0; i < rows; ++i) + for (int j = 0; j < cols; ++j) + cin >> arr[i][j]; + + int i = 0, j = 0, sum = 0; + + while (i < rows && j < cols) { + sum += arr[i][j]; + + int next_val, best_i = -1, best_j = -1; + + // is right ok position? + if (j + 1 < cols) + next_val = arr[i][j + 1], best_i = i, best_j = j + 1; + + // is down ok position? + if (i + 1 < rows) { + if (best_i == -1 || next_val < arr[i + 1][j]) + next_val = arr[i + 1][j], best_i = i + 1, best_j = j; + } + // is diagonal ok position? + if (i + 1 < rows && j + 1 < cols) { + if (best_i == -1 || next_val < arr[i + 1][j + 1]) + next_val = arr[i + 1][j + 1], best_i = i + 1, best_j = j + 1; + } + + if (best_i == -1) + break; + i = best_i, j = best_j; + } + cout << sum << "\n"; + + return 0; +} + diff --git a/18-Programming-4kids/12_10_shorter.cpp b/18-Programming-4kids/12_10_shorter.cpp new file mode 100644 index 0000000..70c6b16 --- /dev/null +++ b/18-Programming-4kids/12_10_shorter.cpp @@ -0,0 +1,38 @@ +#include +using namespace std; + +int main() { + int arr[100][100]; + int rows, cols; + + cin >> rows >> cols; + + for (int i = 0; i < rows; ++i) + for (int j = 0; j < cols; ++j) + cin >> arr[i][j]; + + int i = 0, j = 0, sum = 0; + int di[3] { 1, 0, 1 }; + int dj[3] { 0, 1, 1 }; + + while (i < rows && j < cols) { + sum += arr[i][j]; + + int next_val, best_i = -1, best_j = -1; + + for (int d = 0; d < 3; ++d) { + int ni = i + di[d], nj = j + dj[d]; + + if (ni < rows && nj < cols) { + if (best_i == -1 || next_val < arr[ni][nj]) + next_val = arr[ni][nj], best_i = ni, best_j = nj; + } + } + if (best_i == -1) + break; + i = best_i, j = best_j; + } + cout << sum << "\n"; + + return 0; +} diff --git a/18-Programming-4kids/12_2.cpp b/18-Programming-4kids/12_2.cpp new file mode 100644 index 0000000..cec15af --- /dev/null +++ b/18-Programming-4kids/12_2.cpp @@ -0,0 +1,22 @@ +#include +using namespace std; + +int main() { + double grades[7][6] = { 0 }; + + // Mostafa Grades + grades[0][0] = 50, grades[0][1] = 33, grades[0][2] = 40, grades[0][3] = 30; + + // Asmaa Grades + grades[1][0] = 35, grades[1][1] = 50, grades[1][2] = 40, grades[1][3] = 30; + + for (int row = 0; row < 7; ++row) { + cout << "Row " << row << ": "; + for (int col = 0; col < 4; ++col) { + cout << grades[row][col] << " "; + } + cout << "\n"; + } + return 0; +} + diff --git a/18-Programming-4kids/12_3.cpp b/18-Programming-4kids/12_3.cpp new file mode 100644 index 0000000..f9eb37a --- /dev/null +++ b/18-Programming-4kids/12_3.cpp @@ -0,0 +1,20 @@ +#include +using namespace std; + +int main() { + double grades[7][6] = { 0 }; + + for (int row = 0; row < 7; ++row) + for (int col = 0; col < 4; ++col) + cin >> grades[row][col]; + + for (int row = 0; row < 7; ++row) { + cout << "Row " << row << ": "; + for (int col = 0; col < 4; ++col) { + cout << grades[row][col] << " "; + } + cout << "\n"; + } + return 0; +} + diff --git a/18-Programming-4kids/12_4.cpp b/18-Programming-4kids/12_4.cpp new file mode 100644 index 0000000..f9eb37a --- /dev/null +++ b/18-Programming-4kids/12_4.cpp @@ -0,0 +1,20 @@ +#include +using namespace std; + +int main() { + double grades[7][6] = { 0 }; + + for (int row = 0; row < 7; ++row) + for (int col = 0; col < 4; ++col) + cin >> grades[row][col]; + + for (int row = 0; row < 7; ++row) { + cout << "Row " << row << ": "; + for (int col = 0; col < 4; ++col) { + cout << grades[row][col] << " "; + } + cout << "\n"; + } + return 0; +} + diff --git a/18-Programming-4kids/12_5.cpp b/18-Programming-4kids/12_5.cpp new file mode 100644 index 0000000..4ef32ba --- /dev/null +++ b/18-Programming-4kids/12_5.cpp @@ -0,0 +1,20 @@ +#include +using namespace std; + +int main() { + double grades[7][6] = { 0 }; + + for (int row = 0; row < 7; ++row) + for (int col = 0; col < 4; ++col) + cin >> grades[row][col]; + + for (int col = 0; col < 4; ++col) { + cout << "Col " << col << ": "; + for (int row = 0; row < 7; ++row) { + cout << grades[row][col] << " "; + } + cout << "\n"; + } + return 0; +} + diff --git a/18-Programming-4kids/12_6.cpp b/18-Programming-4kids/12_6.cpp new file mode 100644 index 0000000..85eba19 --- /dev/null +++ b/18-Programming-4kids/12_6.cpp @@ -0,0 +1,23 @@ +#include +using namespace std; + +int main() { + double grades[7][6] = { 0 }; + + for (int row = 0; row < 7; ++row) + for (int col = 0; col < 4; ++col) + cin >> grades[row][col]; + + for (int row = 0; row < 7; ++row) { + double sum = 0; + for (int col = 0; col < 4; ++col) + sum += grades[row][col]; + + double avg = sum / 7.0; + + cout << "Student # " << row + 1 + << " has average grade: " << avg << "\n"; + } + return 0; +} + diff --git a/18-Programming-4kids/12_7.cpp b/18-Programming-4kids/12_7.cpp new file mode 100644 index 0000000..5078533 --- /dev/null +++ b/18-Programming-4kids/12_7.cpp @@ -0,0 +1,26 @@ +#include +using namespace std; + +int main() { + int arr[100][100]; + + int rows, cols; + cin >> rows >> cols; + + for (int row = 0; row < rows; ++row) + for (int col = 0; col < cols; ++col) + cin >> arr[row][col]; + + int max_i = 0, max_j = 0; + + for (int i = 0; i < rows; ++i) { + for (int j = 0; j < cols; ++j) { + if (arr[i][j] >= arr[max_i][max_j]) + max_i = i, max_j = j; + } + } + cout << "Max value at position " << max_i << " " << max_j + << " with value = " << arr[max_i][max_j]; + return 0; +} + diff --git a/18-Programming-4kids/12_8.cpp b/18-Programming-4kids/12_8.cpp new file mode 100644 index 0000000..c0d78e2 --- /dev/null +++ b/18-Programming-4kids/12_8.cpp @@ -0,0 +1,40 @@ +#include +using namespace std; + +int main() { + int arr[100][100]; + + int rows, cols; + cin >> rows >> cols; + + for (int i = 0; i < rows; ++i) + for (int j = 0; j < cols; ++j) + cin >> arr[i][j]; + + int i = 0, j = 0; + + int left_diagonal = 0; + while (i < rows && j < cols) + left_diagonal += arr[i++][j++]; + + int right_diagonal = 0; + i = 0, j = cols-1; + while (i < rows && j >= 0) + right_diagonal += arr[i++][j--]; + + int last_row = 0; + j = 0; + while (j < cols) + last_row += arr[rows-1][j++]; + + int last_col = 0; + i = 0; + while (i < rows) + last_col += arr[i++][cols-1]; + + cout << left_diagonal << " " << right_diagonal << "\n"; + cout << last_row << " " << last_col << "\n"; + + return 0; +} + diff --git a/18-Programming-4kids/12_9.cpp b/18-Programming-4kids/12_9.cpp new file mode 100644 index 0000000..4c7e4da --- /dev/null +++ b/18-Programming-4kids/12_9.cpp @@ -0,0 +1,31 @@ +#include +using namespace std; + +int main() { + int arr[100][100]; + + int rows, cols; + cin >> rows >> cols; + + for (int i = 0; i < rows; ++i) + for (int j = 0; j < cols; ++j) + cin >> arr[i][j]; + + int c1, c2; + cin >> c1 >> c2; + + for (int i = 0; i < rows; ++i) { + // swap [i][c1] with [i][c2] + int tmp = arr[i][c1]; + arr[i][c1] = arr[i][c2]; + arr[i][c2] = tmp; + } + for (int i = 0; i < rows; ++i) { + for (int j = 0; j < cols; ++j) + cout << arr[i][j] << " "; + cout << "\n"; + } + + return 0; +} + diff --git a/18-Programming-4kids/12_homework_1_answer.cpp b/18-Programming-4kids/12_homework_1_answer.cpp new file mode 100644 index 0000000..04eba7f --- /dev/null +++ b/18-Programming-4kids/12_homework_1_answer.cpp @@ -0,0 +1,36 @@ +#include +using namespace std; + +int main() { + int arr[100][100]; + int n, m; + + cin >> n >> m; + for (int i = 0; i < n; ++i) { + for (int j = 0; j < m; ++j) { + cin >> arr[i][j]; + } + } + + int q; + cin >> q; + + while (q--) { + int r1, r2; + cin >> r1 >> r2; + r1--; + r2--; + + bool is_smaller = true; + for (int j = 0; j < m; ++j) + is_smaller &= (arr[r1][j] < arr[r2][j]); + + if (is_smaller) + cout << "YES\n"; + else + cout << "NO\n"; + } + + return 0; +} + diff --git a/18-Programming-4kids/12_homework_2_answer.cpp b/18-Programming-4kids/12_homework_2_answer.cpp new file mode 100644 index 0000000..1151537 --- /dev/null +++ b/18-Programming-4kids/12_homework_2_answer.cpp @@ -0,0 +1,25 @@ +#include +using namespace std; + +int main() { + int n, upper = 0, lower = 0, val; + // No need to create matrix! + cin >> n; + for (int i = 0; i < n; ++i) { + for (int j = 0; j < n; ++j) { + cin >> val; + + if (i <= j) + lower += val; + + if (i >= j) + upper += val; + } + } + + cout << lower << "\n"; + cout << upper << "\n"; + + return 0; +} + diff --git a/18-Programming-4kids/12_homework_3_answer.cpp b/18-Programming-4kids/12_homework_3_answer.cpp new file mode 100644 index 0000000..9decbf1 --- /dev/null +++ b/18-Programming-4kids/12_homework_3_answer.cpp @@ -0,0 +1,47 @@ +#include +using namespace std; + +int main() { + int arr[100][100]; + int n, m; + + cin >> n >> m; + for (int i = 0; i < n; ++i) + for (int j = 0; j < m; ++j) + cin >> arr[i][j]; + + //{ d, r, u, l, ul, dr, ur, dl }; + int di[8] = { 1, 0, -1, 0, -1, 1, -1, 1 }; + int dj[8] = { 0, 1, 0, -1, -1, 1, 1, -1 }; + + for (int i = 0; i < n; ++i) { + for (int j = 0; j < m; ++j) { + bool valid_mountain = true; // if no neighbors, will remain true! + + // check the 8 neighbors using dir array + for (int d = 0; d < 8 && valid_mountain; ++d) { + int ni = i + di[d]; + int nj = j + dj[d]; + + if (ni < 0 || nj >= n || nj < 0 || nj >= m) + continue; // outside borders + + valid_mountain &= (arr[i][j] > arr[ni][nj]); + } + + if (valid_mountain) + cout << i << " " << j << "\n"; + } + } + + return 0; +} +/** +important test +1 1 +1 + +answer +0 0 + */ + diff --git a/18-Programming-4kids/12_homework_4_answer.cpp b/18-Programming-4kids/12_homework_4_answer.cpp new file mode 100644 index 0000000..bcf0538 --- /dev/null +++ b/18-Programming-4kids/12_homework_4_answer.cpp @@ -0,0 +1,105 @@ +#include +using namespace std; + +int main() { + // 0 empty, 1 = x, 2 = o + int grid[100][100] = { 0 }; + + int n; + cout<<"Enter grid dimension: "; + cin >> n; + + // Direct way to verify rows, cols and diagonals. Let's do it in a different way (for learning) + // let's define all positions we want to verify and the DIRECTION we need to do it + + int rs[100], cs[100], dr[100], dc[100]; + + int verify = 0; + + // Add row n positions to verify + for (int r = 0; r < n; ++r) + rs[verify] = r, cs[verify] = 0, dr[verify] = 0, dc[verify++] = 1; + + // Add col n positions to verify + for (int c = 0; c < n; ++c) + rs[verify] = 0, cs[verify] = c, dr[verify] = 1, dc[verify++] = 0; + + // Add diagonal 1 + rs[verify] = 0, cs[verify] = 0, dr[verify] = 1, dc[verify++] = 1; + // Add diagonal 2 + rs[verify] = 0, cs[verify] = n - 1, dr[verify] = 1, dc[verify++] = -1; + + int turn = 0; // 0 for x, 1 for o. Don't get confused with grid values + + int steps = 0; + while (true) { + if (steps == n*n) { + cout<<"Tie\n"; + break; + } + char symbol = 'x'; + if (turn == 1) + symbol = 'o'; + + cout << "Player " << symbol << " turn. Enter empty location (r, c): "; + int r, c; + cin >> r >> c; + + r -= 1, c -= 1; + + if (r < 0 || r >= n || c < 0 || c >= n || grid[r][c] != 0) { + cout << "Invalid input. Try again\n"; + continue; + } + grid[r][c] = turn + 1; + + // print the grid + for (int r = 0; r < n; ++r) { + for (int c = 0; c < n; ++c) { + char ch = '.'; + if (grid[r][c] == 1) + ch = 'x'; + else if (grid[r][c] == 2) + ch = 'o'; + cout << ch; + } + cout << "\n"; + } + + // Check win status + for (int check = 0; check < verify; ++check) { + int r = rs[check], c = cs[check], rd = dr[check], cd = dc[check]; + int cnt = 0, first = grid[r][c]; + + if (first == 0) + continue; + + for (int step = 0; step < n; ++step, r += rd, c += cd) + cnt += grid[r][c] == first; + + if (cnt == n) { + cout << "Player " << symbol << " won\n"; + return 0; + } + } + + turn = !turn; // 0 be 1, 1 be 0 = flip player + steps++; + } + + return 0; +} +/* +For tie +3 +1 1 +1 3 +1 2 +2 2 +3 2 +2 1 +2 3 +3 3 +3 1 + */ + diff --git a/18-Programming-4kids/12_homework_5_answer.cpp b/18-Programming-4kids/12_homework_5_answer.cpp new file mode 100644 index 0000000..715cc80 --- /dev/null +++ b/18-Programming-4kids/12_homework_5_answer.cpp @@ -0,0 +1,43 @@ +#include +using namespace std; + +int main() { + + if (false) { + int idx = 0; + for (int dep = 0; dep < 3; ++dep) + for (int row = 0; row < 4; ++row) + for (int col = 0; col < 5; ++col) + cout << idx++ << " = " << dep << " " << row << " " << col + << "\n"; + } + + int D, R, C, type; + int d, r, c, idx; + + cin >> D >> R >> C >> type; + + int Db = R * C; + int Rb = C; + + if (type == 1) { + cin >> d >> r >> c; + idx = d * Db + r * Rb + c * 1; + cout << idx << "\n"; + } else { + cin>>idx; + + // r * Rb + c * 1 < Db + d = idx / Db; + + // Remove d part, then extract r + r = (idx % Db) / Rb; + + c = (idx % Db) % Rb; + + cout << d << " " << r << " " << c << "\n"; + } + + return 0; +} + diff --git a/18-Programming-4kids/12_homework_6_answer.cpp b/18-Programming-4kids/12_homework_6_answer.cpp new file mode 100644 index 0000000..6fe7238 --- /dev/null +++ b/18-Programming-4kids/12_homework_6_answer.cpp @@ -0,0 +1,40 @@ +#include +using namespace std; + +int main() { + int arr1[100][100]; + int arr2[100][100]; + int n, m; + + cin >> n >> m; + for (int i = 0; i < n; ++i) + for (int j = 0; j < m; ++j) + cin >> arr1[i][j]; + + for (int i = 0; i < n; ++i) + for (int j = 0; j < m; ++j) + arr2[j][i] = arr1[i][j]; + + for (int i = 0; i < m; ++i) { + for (int j = 0; j < n; ++j) + cout << arr2[i][j] << " "; + cout << "\n"; + } + + return 0; +} +/** + +3 4 +8 16 9 52 +3 15 27 6 +14 25 29 10 + +output +8 3 14 +16 15 25 +9 27 29 +52 6 10 + + + */ diff --git a/18-Programming-4kids/12_homework_7_answer.cpp b/18-Programming-4kids/12_homework_7_answer.cpp new file mode 100644 index 0000000..a15319c --- /dev/null +++ b/18-Programming-4kids/12_homework_7_answer.cpp @@ -0,0 +1,31 @@ +#include +using namespace std; + +int main() { + int n, m, k, r = 0, c = 0; + + cin >> n >> m >> k; + + // Direction from 1 to 4: up, right, down, left + int rd[4] = { -1, 0, 1, 0 }; + int cd[4] = { 0, 1, 0, -1 }; + + while (k--) { + int dir, steps; + cin >> dir >> steps; + --dir; + + r = (r + rd[dir] * steps) % n; + c = (c + cd[dir] * steps) % m; + + if (r < 0) + r += n; + if (c < 0) + c += m; + + cout << r << " " << c << "\n"; + } + + return 0; +} + diff --git a/18-Programming-4kids/12_homework_8_answer.cpp b/18-Programming-4kids/12_homework_8_answer.cpp new file mode 100644 index 0000000..3f38ecc --- /dev/null +++ b/18-Programming-4kids/12_homework_8_answer.cpp @@ -0,0 +1,56 @@ +#include +using namespace std; + +int main() { + bool is_prime[100][100] = { 0 }; + int n, m, val; + + cin >> n >> m; + for (int i = 0; i < n; ++i) + for (int j = 0; j < m; ++j) { + cin >> val; + + // let's compute is prime once NOT with every query. Also no need for main array + if (val <= 1) + continue; + + is_prime[i][j] = 1; + for (int k = 2; k < val; ++k) { + if (val % k == 0) { + is_prime[i][j] = 0; + break; + } + } + } + + int q, si, sj, rs, cls; + cin >> q; + + while (q--) { + cin >> si >> sj >> rs >> cls; + int cnt = 0; + + for (int i = si; i <= si + rs - 1; ++i) + for (int j = sj; j <= sj + cls - 1; ++j) + cnt += is_prime[i][j]; + + cout << cnt << "\n"; + } + + return 0; +} +/** + + 3 4 + 8 16 9 52 + 3 15 27 6 + 14 25 29 10 + + output + 8 3 14 + 16 15 25 + 9 27 29 + 52 6 10 + + + */ diff --git a/18-Programming-4kids/13_1.cpp b/18-Programming-4kids/13_1.cpp new file mode 100644 index 0000000..5687a31 --- /dev/null +++ b/18-Programming-4kids/13_1.cpp @@ -0,0 +1,16 @@ +#include +using namespace std; + +int main() { + int n; + cin >> n; + + int sum = 0; + + for (int i = 1; i <= n; ++i) + sum += i; + + cout << sum << "\n"; + + return 0; +} diff --git a/18-Programming-4kids/13_10.cpp b/18-Programming-4kids/13_10.cpp new file mode 100644 index 0000000..f3f2f3e --- /dev/null +++ b/18-Programming-4kids/13_10.cpp @@ -0,0 +1,39 @@ +#include +#include +#include +using namespace std; + +int main() { + cout< +#include +using namespace std; + +bool is_lower(const string &str) { + for (int i = 0; i < (int) str.size(); ++i) + if (!islower(str[i])) + return false; + + return true; +} + +int main() { + cout << is_lower("abc") << "\n"; + cout << is_lower("aBC") << "\n"; + + return 0; +} diff --git a/18-Programming-4kids/13_12.cpp b/18-Programming-4kids/13_12.cpp new file mode 100644 index 0000000..734fd09 --- /dev/null +++ b/18-Programming-4kids/13_12.cpp @@ -0,0 +1,15 @@ +#include +#include +using namespace std; + +int add(int a, int b) +{ + return a+b; +} + +int main() { + cout << add(2, 3) << "\n"; + cout << add(2, 3.5) << "\n"; + + return 0; +} diff --git a/18-Programming-4kids/13_13.cpp b/18-Programming-4kids/13_13.cpp new file mode 100644 index 0000000..6d57a50 --- /dev/null +++ b/18-Programming-4kids/13_13.cpp @@ -0,0 +1,20 @@ +#include +using namespace std; + +int add(int a, int b) { + return a + b; +} + +double add(double a, double b) { + return a + b; +} + +int add(int a, int b, int c) { + return a + b + c; +} + +int main() { + cout << add(2, 3) << "\n"; + cout << add(2.0, 3.5) << "\n"; + return 0; +} diff --git a/18-Programming-4kids/13_14.cpp b/18-Programming-4kids/13_14.cpp new file mode 100644 index 0000000..6287eb5 --- /dev/null +++ b/18-Programming-4kids/13_14.cpp @@ -0,0 +1,17 @@ +#include +using namespace std; + +int sum_array(int arr[], int len) { + int sum = 0; + for (int i = 0; i < len; ++i) + sum += arr[i]; + return sum; +} + +int main() { + int arr[6] = {1, 2, 3, 4, 5, 6}; + cout << sum_array(arr, 3) << "\n"; + cout << sum_array(arr, 6) << "\n"; + + return 0; +} diff --git a/18-Programming-4kids/13_16_employees_v2.cpp b/18-Programming-4kids/13_16_employees_v2.cpp new file mode 100644 index 0000000..0ff5728 --- /dev/null +++ b/18-Programming-4kids/13_16_employees_v2.cpp @@ -0,0 +1,108 @@ +#include +using namespace std; + +// Global variables +const int MAX = 10000; + +string names[MAX]; +int ages[MAX]; +double salaries[MAX]; +char genders[MAX]; +int added = 0; // Number of employees + +int menu() { + int choice = -1; + while (choice == -1) { + cout << "\nEnter your choice:\n"; + cout << "1) Add new employee\n"; + cout << "2) Print all employees\n"; + cout << "3) Delete by age\n"; + cout << "4) Update Salary by name\n"; + cout << "5) Exit\n"; + + cin >> choice; + + if (!(1 <= choice && choice <= 5)) { + cout << "Invalid choice. Try again\n"; + choice = -1; // loop keep working + } + } + return choice; +} + +void read_employee() { + cout << "Enter name: "; + cin >> names[added]; + + cout << "Enter age: "; + cin >> ages[added]; + + cout << "Enter salary: "; + cin >> salaries[added]; + + cout << "Enter gender (M/F): "; + cin >> genders[added]; + ++added; +} + +void print_employees() { + cout << "****************************\n"; + for (int i = 0; i < added; ++i) { + if (ages[i] != -1) + cout << names[i] << " " << ages[i] << " " << salaries[i] << " " + << genders[i] << "\n"; + } +} + +void delete_by_age() { + cout << "Enter start and end age: "; + int start, end; + cin >> start >> end; + + for (int i = 0; i < added; ++i) { + if (start <= ages[i] && ages[i] <= end) + ages[i] = -1; // Let's mark a removed entry with -1 (lazy delete) + } +} + +void update_salary_by_name() { + cout << "Enter the name and salary: "; + string name; + int salary; + cin >> name >> salary; + + bool is_found = false; + for (int i = 0; i < added; ++i) { + if (ages[i] != -1 && names[i] == name) { + is_found = true; + salaries[i] = salary; + break; + } + } + if (!is_found) + cout << "No employee with this name!\n"; +} + +void employee_system() { + while (true) { + int choice = menu(); + + if (choice == 1) + read_employee(); + else if (choice == 2) + print_employees(); + else if (choice == 3) + delete_by_age(); + else if (choice == 4) + update_salary_by_name(); + else + break; + } +} + +int main() { + //freopen("c.in", "rt", stdin); + employee_system(); + return 0; +} + diff --git a/18-Programming-4kids/13_2.cpp b/18-Programming-4kids/13_2.cpp new file mode 100644 index 0000000..9f6bce3 --- /dev/null +++ b/18-Programming-4kids/13_2.cpp @@ -0,0 +1,23 @@ +#include +using namespace std; + +int sum1_to_n(int n) { + int sum = 0; + + for (int i = 1; i <= n; ++i) + sum += i; + + return sum; +} + +int main() { + int n; + cin >> n; + int result = sum1_to_n(n); + + cout << result << "\n"; + + return 0; +} + + diff --git a/18-Programming-4kids/13_3.cpp b/18-Programming-4kids/13_3.cpp new file mode 100644 index 0000000..0069dc5 --- /dev/null +++ b/18-Programming-4kids/13_3.cpp @@ -0,0 +1,16 @@ +#include +using namespace std; + +int our_abs(int n) { + if (n >= 0) + return n; + return -n; +} + +int main() { + cout << our_abs(5) << "\n"; + cout << our_abs(-5) << "\n"; + + return 0; +} + diff --git a/18-Programming-4kids/13_4.cpp b/18-Programming-4kids/13_4.cpp new file mode 100644 index 0000000..e7b143c --- /dev/null +++ b/18-Programming-4kids/13_4.cpp @@ -0,0 +1,16 @@ +#include +using namespace std; + +int our_max(int a, int b) { + if (a >= b) + return a; + return b; +} + +int main() { + cout << our_max(2, 5) << "\n"; + cout << our_max(2, -5) << "\n"; + + return 0; +} + diff --git a/18-Programming-4kids/13_5.cpp b/18-Programming-4kids/13_5.cpp new file mode 100644 index 0000000..d476ecd --- /dev/null +++ b/18-Programming-4kids/13_5.cpp @@ -0,0 +1,25 @@ +#include +using namespace std; + +int our_abs(int n) { + if (n >= 0) + return n; + return -n; +} + +int our_max2(int a, int b) { + a = our_abs(a); + b = our_abs(b); + + if (a >= b) + return a; + return b; +} + +int main() { + cout << our_max2(2, 5) << "\n"; + cout << our_max2(2, -5) << "\n"; + + return 0; +} + diff --git a/18-Programming-4kids/13_6.cpp b/18-Programming-4kids/13_6.cpp new file mode 100644 index 0000000..ea0f175 --- /dev/null +++ b/18-Programming-4kids/13_6.cpp @@ -0,0 +1,22 @@ +#include +using namespace std; + +int lucky_number() { + return 13; +} + +int main2() { + return 0; +} + +void print_sum(int a, int b) { + cout << a + b << "\n"; +} + +int main() { + cout << lucky_number() << "\n"; + print_sum(2, -5); + + return 0; +} + diff --git a/18-Programming-4kids/13_7.cpp b/18-Programming-4kids/13_7.cpp new file mode 100644 index 0000000..398188f --- /dev/null +++ b/18-Programming-4kids/13_7.cpp @@ -0,0 +1,20 @@ +#include +using namespace std; + +bool is_lower(string str) { + for (int i = 0; i < (int)str.size(); ++i) { + bool lower = 'a' <= str[i] && str[i] <= 'z'; + + if (!lower) + return false; + } + return true; +} + +int main() { + cout << is_lower("abc") << "\n"; + cout << is_lower("aBC") << "\n"; + + return 0; +} + diff --git a/18-Programming-4kids/13_8.cpp b/18-Programming-4kids/13_8.cpp new file mode 100644 index 0000000..2e9cfc8 --- /dev/null +++ b/18-Programming-4kids/13_8.cpp @@ -0,0 +1,20 @@ +#include +using namespace std; + +int our_pow(int n, int p = 3) { + int result = 1; + + while (p--) + result *= n; + + return result; +} + +int main() { + cout << our_pow(2) << "\n"; + cout << our_pow(2, 3) << "\n"; + cout << our_pow(2, 4) << "\n"; + + return 0; +} + diff --git a/18-Programming-4kids/13_9.cpp b/18-Programming-4kids/13_9.cpp new file mode 100644 index 0000000..4233a91 --- /dev/null +++ b/18-Programming-4kids/13_9.cpp @@ -0,0 +1,24 @@ +#include +using namespace std; + +void change(int a, int &b) { + a++; + b++; +} + +void read(int x, int &y, string &str) { + cin >> x >> y >> str; +} + +int main() { + int a = 1, b = 1; + change(a, b); + cout << a << " " << b << "\n"; + + string name; + read(a, b, name); + cout << a << " " << b << " " << name << "\n"; + + return 0; +} + diff --git a/18-Programming-4kids/13_homework_1_answer.cpp b/18-Programming-4kids/13_homework_1_answer.cpp new file mode 100644 index 0000000..e060ee2 --- /dev/null +++ b/18-Programming-4kids/13_homework_1_answer.cpp @@ -0,0 +1,23 @@ +#include +using namespace std; + +int max(int a, int b, int c) { + return max(a, max(b, c)); +} + +int max(int a, int b, int c, int d) { + return max(a, max(b, c, d)); +} +int max(int a, int b, int c, int d, int e) { + return max(a, max(b, c, d, e)); +} +int max(int a, int b, int c, int d, int e, int f) { + return max(max(a, b, c, d, e), f); + //return max(a, max(b, c, d, e, f)); // or this way +} + +int main() { + cout< +using namespace std; + +string reverse_str(const string & str) +{ + string ret = str; + int st = 0, en = (int)str.size()-1; + while(st < en) { + // swap + char tmp = ret[en]; + ret[en] = ret[st]; + ret[st] = tmp; + + st++, en--; + } + return ret; +} + +int main() { + cout< +using namespace std; + +int menu() { + int choice = -1; + while (choice == -1) { + if (true) { + cout << "\nMenu;\n"; + cout << "1) Add 2 numbers\n"; + cout << "2) Subtract 2 numbers\n"; + cout << "3) Multiply 2 numbers\n"; + cout << "4) Divide 2 numbers\n"; + cout << "5) Exit\n"; + } + + cout << "\nEnter your menu choice [1 - 5]: "; + cin >> choice; + + if (!(1 <= choice && choice <= 5)) { + cout << "Invalid choice. Try again\n"; + choice = -1; // loop keep working + } + } + return choice; +} + +void read_2_num(double &a, double &b) { + cout << "Enter 2 numbers: "; + cin >> a >> b; +} + +void add(double a, double b) { + cout << "a + b = " << a + b << "\n"; +} + +void subtract(double a, double b) { + cout << "a - b = " << a - b << "\n"; +} + +void multiply(double a, double b) { + cout << "a * b = " << a * b << "\n"; +} + +void divide(double a, double b) { + if (b != 0) + cout << "a / b = " << a / b << "\n"; + else + cout << "can't divide by zero\n"; +} + +int main() { + int total_operations = 0; + double a, b; + + while (true) { + int choice = menu(); + + if (choice == 5) + break; + + total_operations++; + + read_2_num(a, b); + + if (choice == 1) + add(a, b); + else if (choice == 2) + subtract(a, b); + else if (choice == 3) + multiply(a, b); + else if (choice == 4) + divide(a, b); + } + cout << "Total operations: " << total_operations; + + return 0; +} diff --git a/18-Programming-4kids/13_homework_4_answer.cpp b/18-Programming-4kids/13_homework_4_answer.cpp new file mode 100644 index 0000000..93444ab --- /dev/null +++ b/18-Programming-4kids/13_homework_4_answer.cpp @@ -0,0 +1,28 @@ +#include +using namespace std; + +int read_array(int arr[]) { + int len; + cin >> len; + for (int i = 0; i < len; ++i) + cin >> arr[i]; + + return len; +} + +bool is_palindrome(int arr[], int n) { + int st = 0, en = n - 1; + while (st < en) { + if (arr[st] != arr[en]) + return false; + st++, en--; + } + return true; +} + +int main() { + int arr[100]; + int len = read_array(arr); + cout< +using namespace std; + +void set_powers(int arr[], int len = 5, int m = 2) { + arr[0] = 1; + + for (int i = 1; i < len; ++i) { + arr[i] = arr[i - 1] * m; + } +} + +int main() { + int arr[100]; + int len, m; + cin >> len >> m; + + set_powers(arr, len, m); + + for (int i = 0; i < len; ++i) + cout << arr[i] << " "; + return 0; +} diff --git a/18-Programming-4kids/13_homework_6_answer.cpp b/18-Programming-4kids/13_homework_6_answer.cpp new file mode 100644 index 0000000..dbe2eaa --- /dev/null +++ b/18-Programming-4kids/13_homework_6_answer.cpp @@ -0,0 +1,34 @@ +#include +using namespace std; + +bool is_prime(int num) +{ + if(num <= 1) + return false; + + for (int i = 2; i < num; ++i) { + if(num % i == 0) + return false; + } + return true; +} + +int nth_prime(int n) +{ + for (int i = 2; ; ++i) { + if(is_prime(i)) { + --n; + if(n == 0) + return i; + } + } + return -1; +} + +int main() { + for (int i = 1; i < 20; ++i) { + cout< +using namespace std; + +bool starts_with(string input, string pattern, int pos) { + if (pos + pattern.size() > input.size()) + return false; + + for (int i = 0; i < (int) pattern.size(); ++i) { + if (pattern[i] != input[i + pos]) + return false; + } + return true; +} + +string replace_str(string input, string pattern, string to) { + string res = ""; + for (int pos = 0; pos < (int) input.size(); ++pos) { + if (starts_with(input, pattern, pos)) { + res += to; + pos += (int) pattern.size() - 1; // Move to next right position + } else + res += input[pos]; + } + + return res; +} + +int main() { + cout << starts_with("aabcabaaad", "aa", 0) << "\n"; + cout << starts_with("aabcabaaad", "aa", 1) << "\n"; + cout << starts_with("aabcabaaad", "aabcabaaad", 0) << "\n"; + cout << starts_with("aabcabaaad", "baaad", 5) << "\n"; + cout << starts_with("aabcabaaad", "baaad", 4) << "\n"; + + cout << replace_str("aabcabaaad", "aa", "x") << "\n"; + cout << replace_str("aabcabaaad", "aa", "aaaa") << "\n"; + cout << replace_str("aabcabaaad", "aa", "") << "\n"; + + return 0; +} + diff --git a/18-Programming-4kids/13_homework_8_hospital_v1_miniproject.cpp b/18-Programming-4kids/13_homework_8_hospital_v1_miniproject.cpp new file mode 100644 index 0000000..1bd85da --- /dev/null +++ b/18-Programming-4kids/13_homework_8_hospital_v1_miniproject.cpp @@ -0,0 +1,191 @@ +#include +using namespace std; + +// Global variables +const int MAX_SPECIALIZATION = 20; +const int MAX_QUEUE = 5; + +string names[MAX_SPECIALIZATION+1][MAX_QUEUE+1]; +int status[MAX_SPECIALIZATION+1][MAX_QUEUE+1]; // 0 regular, 1 urgent +int queue_length[MAX_SPECIALIZATION+1]; // for each specialization: how many patients so far + +int menu() { + int choice = -1; + while (choice == -1) { + cout << "\nEnter your choice:\n"; + cout << "1) Add new patient\n"; + cout << "2) Print all patients\n"; + cout << "3) Get next patient\n"; + cout << "4) Exit\n"; + + cin >> choice; + + if (!(1 <= choice && choice <= 4)) { + cout << "Invalid choice. Try again\n"; + choice = -1; // loop keep working + } + } + return choice; +} + +// Move each patient to the left. E.g if patient in position 5, it will be in 4 +// Help in removing patient +void shift_left(int spec, string names_sp[], int status_sp[]) +{ + int len = queue_length[spec]; + for (int i = 1; i < len; ++i) { + names_sp[i-1] = names_sp[i]; + status_sp[i-1] = status_sp[i]; + } + queue_length[spec]--; +} + +// Move each patient to the right. E.g if patient in position 5, it will be in 6 +// Help in adding patient +void shift_right(int spec, string names_sp[], int status_sp[]) +{ + int len = queue_length[spec]; + for (int i = len-1; i >= 0; --i) { // critical to start from END + names_sp[i+1] = names_sp[i]; + status_sp[i+1] = status_sp[i]; + } + queue_length[spec]++; +} + +bool add_patient() { + int spec; + string name; + int st; + + cout << "Enter specialization, name, statis: "; + cin >> spec >> name >> st; + + int pos = queue_length[spec]; + if (pos >= MAX_QUEUE) { + cout << "Sorry we can't add more patients for this specialization\n"; + return false; + } + + if (st == 0) // regular, add to end + { + names[spec][pos] = name; + status[spec][pos] = st; + queue_length[spec]++; + } + else { + // urgent, add to begin. Shift, then add + shift_right(spec, names[spec], status[spec]); + names[spec][0] = name; + status[spec][0] = st; + } + + + return true; +} + +void print_patient(int spec, string names_sp[], int status_sp[]) { + int len = queue_length[spec]; + if (len == 0) + return; + + cout << "There are " << len << " patients in specialization " << spec << "\n"; + for (int i = 0; i < len; ++i) { + cout << names_sp[i] << " "; + if (status_sp[i]) + cout << "urgent\n"; + else + cout << "regular\n"; + } + cout << "\n"; +} + +void print_patients() { + cout << "****************************\n"; + for (int spec = 0; spec < MAX_SPECIALIZATION; ++spec) { + print_patient(spec, names[spec], status[spec]); + } +} + +void get_next_patients() { + int spec; + cout << "Enter specialization: "; + cin >> spec; + + int len = queue_length[spec]; + + if(len == 0) { + cout<<"No patients at the moment. Have rest, Dr\n"; + return; + } + + // Let patient goes to dr + cout< +using namespace std; + +struct emplyee { + string name; + int age; + double salary; + char gender; +}; + +const int MAX = 10000; + +emplyee emplyees_arr[MAX]; +int added = 0; // Number of employees + +void read_employee() { + cout<<"Enter employee 4 entries: "; + cin >> emplyees_arr[added].name >> emplyees_arr[added].age; + cin >> emplyees_arr[added].salary >> emplyees_arr[added].gender; + added++; +} + +void print_employees() { + for (int i = 0; i < added; ++i) { + emplyee e = emplyees_arr[i]; + cout << e.name << " has salary " << e.salary << "\n"; + } +} + +int main() { + emplyee first = { "mostafa", 10, 1200.5, 'M' }; + emplyees_arr[added++] = first; + + emplyees_arr[added].name = "hani"; + emplyees_arr[added].age = 55; + emplyees_arr[added].salary = 750; + emplyees_arr[added].gender = 'M'; + added++; + + read_employee(); + print_employees(); + return 0; +} + diff --git a/18-Programming-4kids/14_2.cpp b/18-Programming-4kids/14_2.cpp new file mode 100644 index 0000000..0c0c3b4 --- /dev/null +++ b/18-Programming-4kids/14_2.cpp @@ -0,0 +1,36 @@ +#include +using namespace std; + +struct emplyee { + string name; + int age; + double salary; + char gender; +}; + +const int MAX = 10000; + +emplyee emplyees_arr[MAX]; +int added = 0; // Number of employees + +void read_employee(emplyee & e) { + cout << "Enter employee 4 entries: "; + cin >> e.name >> e.age; + cin >> e.salary >> e.gender; +} + +void print_employee(emplyee & e) { + cout << e.name << " has salary " << e.salary << "\n"; +} +void print_employees() { + for (int i = 0; i < added; ++i) + print_employee(emplyees_arr[i]); +} + +int main() { + read_employee(emplyees_arr[added++]); + read_employee(emplyees_arr[added++]); + print_employees(); + return 0; +} + diff --git a/18-Programming-4kids/14_3.cpp b/18-Programming-4kids/14_3.cpp new file mode 100644 index 0000000..af8e350 --- /dev/null +++ b/18-Programming-4kids/14_3.cpp @@ -0,0 +1,44 @@ +#include +using namespace std; + +struct emplyee { + string name; + int age; + double salary; + char gender; + + void read_employee() { + cout << "Enter employee 4 entries: "; + cin >> name >> age; + cin >> salary >> gender; + } + + void print_employee() { + cout << name << " has salary " << salary << "\n"; + } + + int get_age() { + return age; + } + void set_age(int new_age) { + age = new_age; + } +}; + +const int MAX = 10000; + +emplyee emplyees_arr[MAX]; +int added = 0; // Number of employees + +void print_employees() { + for (int i = 0; i < added; ++i) + emplyees_arr[i].print_employee(); +} + +int main() { + emplyees_arr[added++].read_employee(); + emplyees_arr[added++].read_employee(); + print_employees(); + return 0; +} + diff --git a/18-Programming-4kids/14_4.cpp b/18-Programming-4kids/14_4.cpp new file mode 100644 index 0000000..235e182 --- /dev/null +++ b/18-Programming-4kids/14_4.cpp @@ -0,0 +1,77 @@ +#include +#include +using namespace std; + +struct emplyee { + string name; + int age; + double salary; + char gender; + + void read_employee() { + cout << "Enter employee 4 entries: "; + cin >> name >> age; + cin >> salary >> gender; + } + + void print_employee() { + cout << name << " has salary " << salary << "\n"; + } + + int get_age() { + return age; + } + void set_age(int new_age) { + age = new_age; + } +}; + +const int MAX = 10000; + +emplyee emplyees_arr[MAX]; +int added = 0; // Number of employees + +void print_employees() { + cout << "******************\n"; + for (int i = 0; i < added; ++i) + emplyees_arr[i].print_employee(); +} + +bool compare_name(emplyee &a, emplyee &b) { + return a.name < b.name; // smaller name first +} + +bool compare_salary(emplyee &a, emplyee &b) { + return a.salary > b.salary; // bigger salary salary +} + +bool compare_name_salary(emplyee &a, emplyee &b) { + // smaller name first, if tie smaller salary + if (a.name != b.name) + return a.name < b.name; + return a.salary < b.salary; +} + +int main() { + int arr[5] = { 5, 1, 3, 2, 4 }; + sort(arr, arr + 5); // #include + for (int i = 0; i < 5; ++i) + cout << arr[i] << " "; + cout << "\n"; + + emplyees_arr[added++].read_employee(); + emplyees_arr[added++].read_employee(); + emplyees_arr[added++].read_employee(); + + sort(emplyees_arr, emplyees_arr + added, compare_name); + print_employees(); + + sort(emplyees_arr, emplyees_arr + added, compare_salary); + print_employees(); + + sort(emplyees_arr, emplyees_arr + added, compare_name_salary); + print_employees(); + + return 0; +} + diff --git a/18-Programming-4kids/14_5.cpp b/18-Programming-4kids/14_5.cpp new file mode 100644 index 0000000..200ae85 --- /dev/null +++ b/18-Programming-4kids/14_5.cpp @@ -0,0 +1,35 @@ +#include +using namespace std; + +struct full_name { + string first, middle, last; + + void read() { + cout << "Enter first middle last names: "; + cin >> first >> middle >> last; + } +}; + +struct emplyee { + full_name emp_name; + int age; + double salary; + + void read() { + emp_name.read(); + cout << "Enter employee age & salary: "; + cin >> age >> salary; + } + + void print() { + cout << emp_name.first << " has salary " << salary << "\n"; + } +}; + +int main() { + emplyee emp; + emp.read(); + emp.print(); + return 0; +} + diff --git a/18-Programming-4kids/14_6.cpp b/18-Programming-4kids/14_6.cpp new file mode 100644 index 0000000..eb77167 --- /dev/null +++ b/18-Programming-4kids/14_6.cpp @@ -0,0 +1,23 @@ +#include +using namespace std; + +struct full_name { + string first, middle, last; + + full_name(string _first, string _last = "") { // constructor + first = _first; + last = _last; + middle = ""; + } +}; + + +int main() { + full_name my_name("ali"); + cout< +using namespace std; + +struct queue { + int arr[100]; + int len; + + queue() { + len = 0; + } + + void add_end(int value) { + arr[len++] = value; + } + void add_front(int value) { + // Shift right + for (int i = len-1; i >= 0; --i) + arr[i+1] = arr[i]; + arr[0] = value; + len++; + } + + int remove_front() { + int ret = arr[0]; + // Shift left + for (int i = 1; i < len; ++i) + arr[i-1] = arr[i]; + --len; + return ret; + } + + void print() { + for (int i = 0; i < len; ++i) + cout< +using namespace std; + +// Global variables +const int MAX_SPECIALIZATION = 20; +const int MAX_QUEUE = 5; + +struct hospital_queue { + string names[MAX_QUEUE]; + int status[MAX_QUEUE]; + int len; + int spec; + + hospital_queue() { + len = 0; + spec = -1; + } + + hospital_queue(int _spec) { + len = 0; + spec = _spec; + } + + bool add_end(string name, int st) { + if (len == MAX_QUEUE) + return false; + names[len] = name, status[len] = st, ++len; + return true; + } + bool add_front(string name, int st) { + if (len == MAX_QUEUE) + return false; + // Shift right + for (int i = len - 1; i >= 0; --i) { + names[i + 1] = names[i]; + status[i + 1] = status[i]; + } + names[0] = name, status[0] = st, len++; + return true; + } + + void remove_front() { + if (len == 0) { + cout << "No patients at the moment. Have rest, Dr\n"; + return; + } + cout << names[0] << " please go with the Dr\n"; + + // Shift left + for (int i = 1; i < len; ++i) { + names[i - 1] = names[i]; + status[i - 1] = status[i]; + } + --len; + } + + void print() { + if (len == 0) + return; + + cout << "There are " << len << " patients in specialization " << spec << "\n"; + for (int i = 0; i < len; ++i) { + cout << names[i] << " "; + if (status[i]) + cout << "urgent\n"; + else + cout << "regular\n"; + } + cout << "\n"; + } +}; + +struct hospital_system { + hospital_queue queues[MAX_SPECIALIZATION+1]; + + hospital_system() { + for (int i = 0; i < MAX_SPECIALIZATION; ++i) + queues[i] = hospital_queue(i); + } + + void run() { + while (true) { + int choice = menu(); + + if (choice == 1) + add_patient(); + else if (choice == 2) + print_patients(); + else if (choice == 3) + get_next_patients(); + else + break; + } + } + + int menu() { + int choice = -1; + while (choice == -1) { + cout << "\nEnter your choice:\n"; + cout << "1) Add new patient\n"; + cout << "2) Print all patients\n"; + cout << "3) Get next patient\n"; + cout << "4) Exit\n"; + + cin >> choice; + + if (!(1 <= choice && choice <= 4)) { + cout << "Invalid choice. Try again\n"; + choice = -1; // loop keep working + } + } + return choice; + } + + bool add_patient() { + int spec, st; + string name; + + cout << "Enter specialization, name, status: "; + cin >> spec >> name >> st; + + bool status; + if (st == 0) + status = queues[spec].add_end(name, st); + else + status = queues[spec].add_front(name, st); + + if (status == false) { + cout<< "Sorry we can't add more patients for this specialization\n"; + return false; + } + + return true; + } + + void print_patients() { + cout << "****************************\n"; + for (int spec = 0; spec < MAX_SPECIALIZATION; ++spec) + queues[spec].print(); + } + + void get_next_patients() { + int spec; + cout << "Enter specialization: "; + cin >> spec; + + queues[spec].remove_front(); + } +}; + +int main() { + freopen("c.in", "rt", stdin); + hospital_system hospital = hospital_system(); + hospital.run(); + return 0; +} + diff --git a/18-Programming-4kids/14_homework_1_library_v1_miniproject.cpp b/18-Programming-4kids/14_homework_1_library_v1_miniproject.cpp new file mode 100644 index 0000000..6d18c5b --- /dev/null +++ b/18-Programming-4kids/14_homework_1_library_v1_miniproject.cpp @@ -0,0 +1,383 @@ +#include +#include +#include +using namespace std; + +const int MAX_BOOKS = 10; +const int MAX_USERS = 10; + +struct book { + int id; + string name; + int total_quantity; + int total_borrowed; + + book() { + total_quantity = total_borrowed = 0; + id = -1; + name = ""; + } + + void read() { + cout << "Enter book info: id & name & total quantity: "; + cin >> id >> name >> total_quantity; + total_borrowed = 0; + } + + bool borrow(int user_id) { + if (total_quantity - total_borrowed == 0) + return false; + ++total_borrowed; + return true; + } + + void return_copy() { + assert(total_borrowed > 0); + --total_borrowed; + } + + bool has_prefix(string prefix) { + if (name.size() < prefix.size()) + return false; + + for (int i = 0; i < (int) prefix.size(); ++i) { + if (prefix[i] != name[i]) + return false; + } + return true; + } + void print() { + cout << "id = " << id << " name = " << name << " total_quantity " + << total_quantity << " total_borrowed " << total_borrowed + << "\n"; + } +}; + +bool cmp_book_by_name(book &a, book& b) { + return a.name < b.name; +} + +bool cmp_book_by_id(book &a, book& b) { + return a.id < b.id; +} + +struct user { + int id; + string name; + int borrowed_books_ids[MAX_BOOKS]; + int len; + + user() { + name = ""; + len = 0; + id = -1; + } + + void read() { + cout << "Enter user name & national id: "; + cin >> name >> id; + } + + void borrow(int book_id) { + borrowed_books_ids[len++] = book_id; + } + void return_copy(int book_id) { + bool removed = false; + for (int i = 0; i < len; ++i) { + if (borrowed_books_ids[i] == book_id) { + // Let's shift the array to the right to remove this entry + for (int j = i + 1; j < len; ++j) + borrowed_books_ids[j - 1] = borrowed_books_ids[j]; + removed = true; + --len; + break; + } + } + if (!removed) + cout << "User " << name << " never borrowed book id " << book_id + << "\n"; + } + + bool is_borrowed(int book_id) { + for (int i = 0; i < len; ++i) { + if (book_id == borrowed_books_ids[i]) + return true; + } + return false; + } + + void print() { + // sort what he borrowed + sort(borrowed_books_ids, borrowed_books_ids + len); + + cout << "user " << name << " id " << id << " borrowed books ids: "; + for (int i = 0; i < len; ++i) + cout << borrowed_books_ids[i] << " "; + cout << "\n"; + } +}; + +struct library_system { + int total_books; + book books[MAX_BOOKS]; + int total_users; + user users[MAX_USERS]; + + library_system() { + total_books = total_users = 0; + } + + void run() { + while (true) { + int choice = menu(); + + if (choice == 1) + add_book(); + else if (choice == 2) + search_books_by_prefix(); + else if (choice == 3) + print_who_borrowed_book_by_name(); + else if (choice == 4) + print_library_by_id(); + else if (choice == 5) + print_library_by_name(); + else if (choice == 6) + add_user(); + else if (choice == 7) + user_borrow_book(); + else if (choice == 8) + user_return_book(); + else if (choice == 9) + print_users(); + else + break; + } + } + + int menu() { + int choice = -1; + while (choice == -1) { + if (false) { + cout << "\nLibrary Menu;\n"; + cout << "1) add_book\n"; + cout << "2) search_books_by_prefix\n"; + cout << "3) print_who_borrowed_book_by_name\n"; + cout << "4) print_library_by_id\n"; + cout << "5) print_library_by_name\n"; + cout << "6) add_user\n"; + cout << "7) user_borrow_book\n"; + cout << "8) user_return_book\n"; + cout << "9) print_users\n"; + cout << "10) Exit\n"; + } + + cout << "\nEnter your menu choice [1 - 10]: "; + cin >> choice; + + if (!(1 <= choice && choice <= 10)) { + cout << "Invalid choice. Try again\n"; + choice = -1; // loop keep working + } + } + return choice; + } + + void add_book() { + books[total_books++].read(); + } + + void search_books_by_prefix() { + cout << "Enter book name prefix: "; + string prefix; + cin >> prefix; + + int cnt = 0; + for (int i = 0; i < total_books; ++i) { + if (books[i].has_prefix(prefix)){ + cout << books[i].name << "\n"; + ++cnt; + } + } + + if(!cnt) + cout<<"No books with such prefix\n"; + } + + void add_user() { + users[total_users++].read(); + } + + int find_book_idx_by_name(string name) { + for (int i = 0; i < total_books; ++i) { + if (name == books[i].name) + return i; + } + return -1; + } + + int find_user_idx_by_name(string name) { + for (int i = 0; i < total_users; ++i) { + if (name == users[i].name) + return i; + } + return -1; + } + + bool read_user_name_and_book_name(int &user_idx, int &book_idx, int trials = + 3) { + string user_name; + string book_name; + + while (trials--) { + cout << "Enter user name and book name: "; + cin >> user_name >> book_name; + + user_idx = find_user_idx_by_name(user_name); + + if (user_idx == -1) { + cout << "Invalid user name. Try again\n"; + continue; + } + book_idx = find_book_idx_by_name(book_name); + + if (book_idx == -1) { + cout << "Invalid book name. Try again\n"; + continue; + } + return true; + } + cout << "You did several trials! Try later."; + return false; + } + + void user_borrow_book() { + int user_idx, book_idx; + + if (!read_user_name_and_book_name(user_idx, book_idx)) + return; + + int user_id = users[user_idx].id; + int book_id = books[book_idx].id; + + if (!books[book_idx].borrow(user_id)) + cout << "No more copies available right now\n"; + else + users[user_idx].borrow(book_id); + } + + void user_return_book() { + int user_idx, book_idx; + + if (!read_user_name_and_book_name(user_idx, book_idx)) + return; + + int book_id = books[book_idx].id; + books[book_idx].return_copy(); + users[user_idx].return_copy(book_id); + } + + void print_library_by_id() { + sort(books, books + total_books, cmp_book_by_id); + + cout << "\n"; + for (int i = 0; i < total_books; ++i) + books[i].print(); + } + + void print_library_by_name() { + sort(books, books + total_books, cmp_book_by_name); + + cout << "\n"; + for (int i = 0; i < total_books; ++i) + books[i].print(); + } + + void print_users() { + cout << "\n"; + for (int i = 0; i < total_users; ++i) + users[i].print(); + } + + void print_who_borrowed_book_by_name() { + string book_name; + cout << "Enter book name: "; + cin >> book_name; + + int book_idx = find_book_idx_by_name(book_name); + + if (book_idx == -1) { + cout << "Invalid book name.\n"; + return; + } + int book_id = books[book_idx].id; + + if (books[book_idx].total_borrowed == 0) { + cout << "No borrowed copies\n"; + return; + } + + for (int i = 0; i < total_users; ++i) { + if (users[i].is_borrowed(book_id)) + cout << users[i].name << "\n"; + } + } +}; + +int main() { + library_system library; + + library.run(); + + return 0; +} + +/* + +1 100 math4 3 +1 101 math2 5 +1 102 math1 4 +1 103 math3 2 +1 201 prog1 5 +1 201 prog2 3 + +4 +5 + +6 mostafa 30301 +6 ali 50501 +6 noha 70701 +6 ashraf 90901 + +7 mostafa math1 +7 mostafa math2 +7 mostafa math3 +7 ali math1 +7 ali math2 +7 noha math1 +7 noha math3 +7 noha prog2 + +4 +9 + +2 ma +2 pro +2 machine + +3 math1 +3 math2 +3 machine + +4 +9 +8 mostafa math1 +4 +9 + + + +10 + + + + */ diff --git a/18-Programming-4kids/15_1.cpp b/18-Programming-4kids/15_1.cpp new file mode 100644 index 0000000..482f107 --- /dev/null +++ b/18-Programming-4kids/15_1.cpp @@ -0,0 +1,27 @@ +#include +using namespace std; + +int factorial(int n) { + int res = 1; + + for (int i = 2; i <= n; ++i) + res *= i; + + return res; +} + +int main() { + cout << factorial(3) << "\n"; // 1 * 2 * 3 + cout << factorial(4) << "\n"; // 1 * 2 * 3 * 4 + + cout << factorial(5) << "\n"; // 1 * 2 * 3 * 4 * 5 = 120 + // factorial(4) * 5 = 120 + + cout << factorial(6) << "\n"; // 1 * 2 * 3 * 4 * 5 * 6 = 720 + // factorial(5) * 6 = 720 + // factorial(4) * 5 * 6 = 720 + // factorial(3)*4* 5 * 6 = 720 + + return 0; +} + diff --git a/18-Programming-4kids/15_2.cpp b/18-Programming-4kids/15_2.cpp new file mode 100644 index 0000000..2d40deb --- /dev/null +++ b/18-Programming-4kids/15_2.cpp @@ -0,0 +1,32 @@ +#include +using namespace std; + +int factorial1() { + return 1; // base case. No subproblems +} + +int factorial2() { + return factorial1() * 2; +} + +int factorial3() { + return factorial2() * 3; +} + +int factorial4() { + return factorial3() * 4; +} + +int factorial5() { + return factorial4() * 5; +} + +int factorial6() { + return factorial5() * 6; +} + +int main() { + cout << factorial6() << "\n"; + return 0; +} + diff --git a/18-Programming-4kids/15_3.cpp b/18-Programming-4kids/15_3.cpp new file mode 100644 index 0000000..b7b02bf --- /dev/null +++ b/18-Programming-4kids/15_3.cpp @@ -0,0 +1,16 @@ +#include +using namespace std; + +int factorial(int n) { + cout<<"Function Call: factorial: n="< +using namespace std; + +void print_triangle(int levels) { + if (levels == 0) + return; + + for (int i = 0; i < levels; ++i) + cout << "*"; + cout << "\n"; + + print_triangle(levels - 1); +} + +int main() { + print_triangle(5); + return 0; +} + diff --git a/18-Programming-4kids/15_5.cpp b/18-Programming-4kids/15_5.cpp new file mode 100644 index 0000000..9af27b0 --- /dev/null +++ b/18-Programming-4kids/15_5.cpp @@ -0,0 +1,19 @@ +#include +using namespace std; + +void print_triangle(int levels) { + if (levels == 0) + return; + + print_triangle(levels - 1); + + for (int i = 0; i < levels; ++i) + cout << "*"; + cout << "\n"; +} + +int main() { + print_triangle(5); + return 0; +} + diff --git a/18-Programming-4kids/15_6.cpp b/18-Programming-4kids/15_6.cpp new file mode 100644 index 0000000..c43ce1f --- /dev/null +++ b/18-Programming-4kids/15_6.cpp @@ -0,0 +1,20 @@ +#include +using namespace std; + +void print_3n_plus_1(int n) { + cout << n << " "; + if (n == 1) + return; + + if (n % 2 == 0) + print_3n_plus_1(n / 2); + else + print_3n_plus_1(3 * n + 1); +} + +int main() { + print_3n_plus_1(6); + + return 0; +} + diff --git a/18-Programming-4kids/15_homework_01_answer.cpp b/18-Programming-4kids/15_homework_01_answer.cpp new file mode 100644 index 0000000..d3fe7d4 --- /dev/null +++ b/18-Programming-4kids/15_homework_01_answer.cpp @@ -0,0 +1,19 @@ +#include +using namespace std; + +int length_3n_plus_1(int n) { + if (n == 1) + return 1; + + if (n % 2 == 0) + return 1 + length_3n_plus_1(n / 2); + + return 1 + length_3n_plus_1(3 * n + 1); +} + +int main() { + cout< +using namespace std; + +int my_pow(int value, int p = 2) { + if (p == 0) + return 1; + + return value * my_pow(value, p - 1); +} + +int main() { + cout << my_pow(7) << "\n"; + cout << my_pow(7, 0) << "\n"; + cout << my_pow(7, 3) << "\n"; + + return 0; +} + diff --git a/18-Programming-4kids/15_homework_03_answer.cpp b/18-Programming-4kids/15_homework_03_answer.cpp new file mode 100644 index 0000000..2a245ae --- /dev/null +++ b/18-Programming-4kids/15_homework_03_answer.cpp @@ -0,0 +1,19 @@ +#include +using namespace std; + +int arr_max(int arr[], int len) { + if (len == 1) + return arr[0]; + + int sub_result = arr_max(arr, len - 1); + return max(sub_result, arr[len - 1]); +} + +int main() { + int arr[] = { 1, 8, 2, 10, 3 }; + + cout << arr_max(arr, 5); + + return 0; +} + diff --git a/18-Programming-4kids/15_homework_04_answer.cpp b/18-Programming-4kids/15_homework_04_answer.cpp new file mode 100644 index 0000000..c1e1d3f --- /dev/null +++ b/18-Programming-4kids/15_homework_04_answer.cpp @@ -0,0 +1,19 @@ +#include +using namespace std; + +int arr_sum(int arr[], int len) { + if (len == 1) + return arr[0]; + + int sub_result = arr_sum(arr, len - 1); + return sub_result + arr[len - 1]; +} + +int main() { + int arr[] = { 1, 8, 2, 10, 3 }; + + cout << arr_sum(arr, 5); + + return 0; +} + diff --git a/18-Programming-4kids/15_homework_05_answer.cpp b/18-Programming-4kids/15_homework_05_answer.cpp new file mode 100644 index 0000000..aac4091 --- /dev/null +++ b/18-Programming-4kids/15_homework_05_answer.cpp @@ -0,0 +1,22 @@ +#include +using namespace std; + +double arr_average(double arr[], int len) { + if (len == 1) + return arr[0]; + + double sub_result = arr_average(arr, len - 1); + // Now this was average of len-1. So sum / (len-1) + sub_result = sub_result * (len-1); + + return (sub_result + arr[len - 1] ) / len; +} + +int main() { + double arr[] = { 1, 8, 2, 10, 3 }; + + cout << arr_average(arr, 5); + + return 0; +} + diff --git a/18-Programming-4kids/15_homework_06_answer.cpp b/18-Programming-4kids/15_homework_06_answer.cpp new file mode 100644 index 0000000..656b553 --- /dev/null +++ b/18-Programming-4kids/15_homework_06_answer.cpp @@ -0,0 +1,23 @@ +#include +using namespace std; + +void array_increment(int arr[], int len) { + if (len == 0) + return; + + array_increment(arr, len - 1); + arr[len-1] += len-1; +} + +int main() { + int arr[] = { 1, 8, 2, 10, 3 }; + + array_increment(arr, 5); + + for (int i = 0; i < 5; ++i) { + cout< +using namespace std; + +void accumulate_arr(int arr[], int len) { + if (len == 1) + return; + + accumulate_arr(arr, len - 1); + arr[len-1] += arr[len-2]; +} + +int main() { + int arr[] = { 1, 8, 2, 10, 3 }; + + accumulate_arr(arr, 5); + + for (int i = 0; i < 5; ++i) { + cout< +using namespace std; + +void left_max(int arr[], int len) { + if (len == 1) + return; + + left_max(arr, len - 1); + arr[len-1] = max(arr[len-1], arr[len-2]); +} + +int main() { + int arr[] = { 1, 8, 2, 10, 3 }; + + left_max(arr, 5); + + for (int i = 0; i < 5; ++i) { + cout< +using namespace std; + +void right_max_v1(int arr[], int len, int start_pos = 0) { + if (start_pos == len - 1) + return; + + right_max_v1(arr, len, start_pos + 1); + arr[start_pos] = max(arr[start_pos], arr[start_pos + 1]); +} + +void right_max_v2(int arr[], int len) { + if (len == 1) + return; + + right_max_v2(arr + 1, len-1); // arr+1 is the a new array shifted. E.g. { 1, 8, 2, 10, 3 } => {8, 2, 10, 3 } + arr[0] = max(arr[0], arr[1]); // Then we only need to think about arr (0) +} + +int main() { + int arr[] = { 1, 8, 2, 10, 3 }; + + right_max_v1(arr, 5); + + for (int i = 0; i < 5; ++i) { + cout< +using namespace std; + +int sufix_sum(int arr[], int len, int cnt) { + if (cnt == 0) + return 0; + + return arr[len - 1] + sufix_sum(arr, len - 1, cnt - 1); +} + +int main() { + int arr[] = { 1, 8, 2, 10, 3 }; + + cout << sufix_sum(arr, 5, 3); + + return 0; +} + diff --git a/18-Programming-4kids/15_homework_11_answer.cpp b/18-Programming-4kids/15_homework_11_answer.cpp new file mode 100644 index 0000000..19aa5d5 --- /dev/null +++ b/18-Programming-4kids/15_homework_11_answer.cpp @@ -0,0 +1,26 @@ +#include +using namespace std; + +int prefix_sum_v1(int arr[], int len, int cnt) { + if (cnt == 0) + return 0; + + return arr[cnt - 1] + prefix_sum_v1(arr, len - 1, cnt - 1); +} + +int prefix_sum_v2(int arr[], int cnt) { + if (cnt == 0) + return 0; + + return arr[0] + prefix_sum_v2(arr+1, cnt - 1); +} + +int main() { + int arr[] = { 1, 8, 2, 10, 3 }; + + cout << prefix_sum_v1(arr, 5, 3)<<"\n"; + cout << prefix_sum_v2(arr, 3)<<"\n"; + + return 0; +} + diff --git a/18-Programming-4kids/15_homework_12_answer.cpp b/18-Programming-4kids/15_homework_12_answer.cpp new file mode 100644 index 0000000..844acef --- /dev/null +++ b/18-Programming-4kids/15_homework_12_answer.cpp @@ -0,0 +1,34 @@ +#include +using namespace std; + +// start & end are indices + +bool is_palindrome_v1(int arr[], int start, int end) { + if (start >= end) + return true; + + if(arr[start] != arr[end]) + return false; + + return is_palindrome_v1(arr, start+1, end-1); +} + +bool is_palindrome_v2(int arr[], int end) { + if (end <= 0) + return true; + + if(arr[0] != arr[end]) + return false; + + return is_palindrome_v2(arr + 1, end-2); +} + +int main() { + int arr[] = { 1, 8, 2, 8, 1 }; + + cout << is_palindrome_v1(arr, 0, 4)<<"\n"; + cout << is_palindrome_v2(arr, 4)<<"\n"; + + return 0; +} + diff --git a/18-Programming-4kids/15_homework_13_answer.cpp b/18-Programming-4kids/15_homework_13_answer.cpp new file mode 100644 index 0000000..eaf56f1 --- /dev/null +++ b/18-Programming-4kids/15_homework_13_answer.cpp @@ -0,0 +1,23 @@ +#include +using namespace std; + +bool is_prefix(string main, string prefix, int start_pos = 0) +{ + if(start_pos == prefix.size()) + return true; + + if(main[start_pos] != prefix[start_pos]) + return false; + + return is_prefix(main, prefix, start_pos + 1); +} + +int main() { + + cout << is_prefix("abcdefg", "abcd", 3)<<"\n"; + cout << is_prefix("abcdefg", "", 3)<<"\n"; + cout << is_prefix("abcdefg", "abd", 3)<<"\n"; + + return 0; +} + diff --git a/18-Programming-4kids/15_homework_14_answer.cpp b/18-Programming-4kids/15_homework_14_answer.cpp new file mode 100644 index 0000000..abf33f3 --- /dev/null +++ b/18-Programming-4kids/15_homework_14_answer.cpp @@ -0,0 +1,25 @@ +#include +using namespace std; + +void do_something1(int n) { // print number digit by digit reversed + if (n) { + cout << n % 10; + do_something1(n / 10); + } +} + +void do_something2(int n) { + if (n) { + do_something2(n / 10); + cout << n % 10; + } +} + +int main() { + do_something1(123456); + cout << "\n"; + do_something2(123456); + + return 0; +} + diff --git a/18-Programming-4kids/15_homework_15_answer.cpp b/18-Programming-4kids/15_homework_15_answer.cpp new file mode 100644 index 0000000..c6722f5 --- /dev/null +++ b/18-Programming-4kids/15_homework_15_answer.cpp @@ -0,0 +1,37 @@ +#include +using namespace std; + +bool is_prime(int m, int cur_test_number = 3) { + if (m == 2) + return true; + + if (m <= 1 || m % 2 == 0) + return false; + + if (m == cur_test_number) + return true; + + if (m % cur_test_number == 0) + return false; + + return is_prime(m, cur_test_number + 1); +} + +int count_primes(int start, int end) { + if (start > end) + return 0; + + int result = count_primes(start + 1, end); + if (is_prime(start)) + result += 1; + + return result; +} + +int main() { + cout< +using namespace std; + +int di[] = { 1, 0, 1 }; +int dj[] = { 0, 1, 1 }; + +int path_sum(int grid[100][100], int ROWS, int COLS, int row = 0, int col = 0) { + int sum = grid[row][col]; + + if (row == ROWS - 1 && col == COLS - 1) + return sum; + + int max_idx = -1, max_value; + + for (int d = 0; d < 3; ++d) { + int new_row = row + di[d]; + int new_col = col + dj[d]; + + if (new_row >= ROWS || new_col >= COLS) + continue; + + if (max_value < grid[new_row][new_col]) + max_value = grid[new_row][new_col], max_idx = d; + } + int new_row = row + di[max_idx]; + int new_col = col + dj[max_idx]; + + return sum + path_sum(grid, ROWS, COLS, new_row, new_col); +} + +int main() { + //freopen("c.in", "rt", stdin); + + int grid[100][100]; + int n, m; + + cin >> n >> m; + + for (int i = 0; i < n; ++i) { + for (int j = 0; j < m; ++j) { + cin >> grid[i][j]; + } + } + + cout << path_sum(grid, n, m); + + return 0; +} + + +/* + +3 3 +1 0 0 +0 2 0 +0 0 3 + +5 1 +1 2 3 4 5 + +1 5 +1 2 3 4 5 + +1 1 +5 + +3 3 +1 7 8 +2 10 11 +20 5 9 + + + */ diff --git a/18-Programming-4kids/15_homework_17_answer.cpp b/18-Programming-4kids/15_homework_17_answer.cpp new file mode 100644 index 0000000..8451586 --- /dev/null +++ b/18-Programming-4kids/15_homework_17_answer.cpp @@ -0,0 +1,17 @@ +#include +using namespace std; + +int fib(int n) { + if (n <= 1) + return 1; + + return fib(n - 1) + fib(n - 2); +} + +int main() { + cout << fib(6) << "\n"; + cout << fib(40) << "\n"; + //cout << fib(50) << "\n"; + + return 0; +} diff --git a/18-Programming-4kids/16_01.cpp b/18-Programming-4kids/16_01.cpp new file mode 100644 index 0000000..3933846 --- /dev/null +++ b/18-Programming-4kids/16_01.cpp @@ -0,0 +1,25 @@ +#include +#include +using namespace std; + +int main() { + queue q; + q.push(10); + q.push(20); + q.push(30); + + cout << "Last element in Queue: " << q.back() << "\n"; + + cout << "Queue elements: "; + while (!q.empty()) { + cout << q.front() << " "; + q.pop(); + } + cout << "\n"; + + queue q_names; + q_names.push("mostafa"); + string name = q_names.front(); + + return 0; +} diff --git a/18-Programming-4kids/16_02.cpp b/18-Programming-4kids/16_02.cpp new file mode 100644 index 0000000..abf6a93 --- /dev/null +++ b/18-Programming-4kids/16_02.cpp @@ -0,0 +1,37 @@ +#include +#include +using namespace std; + +void print_back(deque q) { + cout << "Queue elements (back): "; + while (!q.empty()) { + cout << q.back() << " "; + q.pop_back(); + } + cout << "\n"; +} + +void print_front(deque &q) { + cout << "Queue elements (front): "; + while (!q.empty()) { + cout << q.front() << " "; + q.pop_front(); + } + cout << "\n"; +} + +int main() { + deque q; + q.push_back(20); // q: 20 + q.push_back(30); // q: 20 30 + q.push_back(40); // q: 20 30 40 + q.push_front(10); // q: 10 20 30 40 + q.push_back(50); // q: 10 20 30 40 50 + q.push_front(0); // q: 0 10 20 30 40 50 + + print_back(q); // 50 40 30 20 10 0 + print_front(q); // 0 10 20 30 40 50 + print_front(q); // NONE + + return 0; +} diff --git a/18-Programming-4kids/16_03.cpp b/18-Programming-4kids/16_03.cpp new file mode 100644 index 0000000..438b1a3 --- /dev/null +++ b/18-Programming-4kids/16_03.cpp @@ -0,0 +1,25 @@ +#include +#include +using namespace std; + +void print(priority_queue &pq) { + cout << "Priority Queue elements: "; + while (!pq.empty()) { + cout << pq.top() << " "; + pq.pop(); + } + cout << "\n"; +} +int main() { + // order from big to small + priority_queue pq; + pq.push(3); // 3 + pq.push(5); // 5 3 + pq.push(1); // 5 3 1 + pq.push(7); // 7 5 3 1 + pq.push(0); // 7 5 3 1 0 + + print(pq); + // use -ve number to sort small to large + return 0; +} diff --git a/18-Programming-4kids/16_04.cpp b/18-Programming-4kids/16_04.cpp new file mode 100644 index 0000000..eed349a --- /dev/null +++ b/18-Programming-4kids/16_04.cpp @@ -0,0 +1,21 @@ +#include +#include +using namespace std; + +void print(stack &s) { + cout << "Stack elements: "; + while (!s.empty()) { + cout << s.top() << " "; + s.pop(); + } + cout << "\n"; +} +int main() { + stack s; + s.push("ibrahim"); + s.push("saad"); + s.push("mostafa"); + + print(s); // mostafa saad ibrahim + return 0; +} diff --git a/18-Programming-4kids/16_05.cpp b/18-Programming-4kids/16_05.cpp new file mode 100644 index 0000000..fa01603 --- /dev/null +++ b/18-Programming-4kids/16_05.cpp @@ -0,0 +1,23 @@ +#include +#include +using namespace std; + +struct triple { + int first; + string second; + double third; +}; + +int main() { + pair p = make_pair(10, "mostafa"); + cout< > s; + s.push(p); + s.push(p); + + pair > my_p = make_pair(10, make_pair(20, "ali")); + my_p = make_pair(10, p); + + return 0; +} diff --git a/18-Programming-4kids/16_06.cpp b/18-Programming-4kids/16_06.cpp new file mode 100644 index 0000000..9c90dd3 --- /dev/null +++ b/18-Programming-4kids/16_06.cpp @@ -0,0 +1,29 @@ +#include +#include +using namespace std; + +int main() { + vector v1; // Array that can be expanded + + v1.push_back(30); + v1.push_back(10); + v1.push_back(20); + // Now we have 3 elements only + + for (int i = 0; i < (int)v1.size(); ++i) { + cout< v2(5, 7); + // Like an array with 5 numbers all initialized with 7 + + v2.push_back(13); // Now add extra num = 13 + + for (int i = 0; i < (int)v2.size(); ++i) { + cout< +#include +using namespace std; + +void print(vector &v) +{ + vector::iterator it; + + it = v.begin(); + + while (it != v.end() ) { + cout<<*it<<" "; + ++it; + } + // No value at v.end() + cout<<"\n"; +} + +int main() { + vector v(5); + + for (int i = 0; i < (int)v.size(); ++i) + v[i] = i; + + print(v); + + v.erase(v.begin() + 3); // remove v[3] + print(v); + + v.insert(v.begin() + 1, 17); // insert before v[1] + print(v); + + return 0; +} diff --git a/18-Programming-4kids/16_08.cpp b/18-Programming-4kids/16_08.cpp new file mode 100644 index 0000000..0895838 --- /dev/null +++ b/18-Programming-4kids/16_08.cpp @@ -0,0 +1,34 @@ +#include +#include +#include // sort algo +using namespace std; + +void print(vector &v) +{ + int a = v[0]; + auto b = v[0]; + + for (auto x : v) + cout< v(5); + + for (int i = 0; i < (int)v.size(); ++i) + v[i] = 10 - i; + + print(v); // 10 9 8 7 6 + + sort(v.begin() + 1, v.end()); // sort from v[1] to v[size-1] + print(v); // 10 6 7 8 9 + + sort(v.begin(), v.end()); // sort from v[0] to v[size-1] + print(v); // 6 7 8 9 10 + + sort(v.rbegin(), v.rend()); // sort from v[0] to v[size-1] + print(v); // 10 9 8 7 6 + + return 0; +} diff --git a/18-Programming-4kids/16_09.cpp b/18-Programming-4kids/16_09.cpp new file mode 100644 index 0000000..760d3a3 --- /dev/null +++ b/18-Programming-4kids/16_09.cpp @@ -0,0 +1,30 @@ +#include +#include +#include // sort algo +using namespace std; + +void print(vector &v) +{ + for (int x : v) + cout< v(5); + + for (int i = 0; i < (int)v.size(); ++i) + v[i] = 10 - i; + + print(v); // 10 9 8 7 6 + + reverse(v.begin(), v.end()); + print(v); // 6 7 8 9 10 + + v.clear(); + print(v); + + + + return 0; +} diff --git a/18-Programming-4kids/16_10.cpp b/18-Programming-4kids/16_10.cpp new file mode 100644 index 0000000..9ee2a5e --- /dev/null +++ b/18-Programming-4kids/16_10.cpp @@ -0,0 +1,34 @@ +#include +#include +#include +using namespace std; + +void print(set &v) { + for (string x : v) + cout << x << " "; + cout << "\n"; +} + +int main() { + set strSet; // Sorted & unique + strSet.insert("ziad"); + strSet.insert("mostafa"); + strSet.insert("mostafa"); + strSet.insert("mostafa"); + strSet.insert("ali"); + + print(strSet); // ali mostafa ziad + + if (strSet.count("mostafa")) + cout << "YES\n"; + + set::iterator it = strSet.find("mostafa"); + //auto it = strSet.find("mostafa"); // or shorter using auto + + if (it != strSet.end()) + strSet.erase(it); + + print(strSet); // ali ziad + + return 0; +} diff --git a/18-Programming-4kids/16_11.cpp b/18-Programming-4kids/16_11.cpp new file mode 100644 index 0000000..718331a --- /dev/null +++ b/18-Programming-4kids/16_11.cpp @@ -0,0 +1,34 @@ +#include +#include +#include +using namespace std; + +void print(multiset &v) { + for (string x : v) + cout << x << " "; + cout << "\n"; +} + +int main() { + multiset strSet; // Sorted & can repeat + strSet.insert("ziad"); + strSet.insert("mostafa"); + strSet.insert("mostafa"); + strSet.insert("mostafa"); + strSet.insert("ali"); + + print(strSet); // ali mostafa mostafa mostafa ziad + + if (strSet.count("mostafa")) + cout << "YES\n"; + + multiset::iterator it = strSet.find("mostafa"); + //auto it = strSet.find("mostafa"); // or shorter using auto + + if (it != strSet.end()) + strSet.erase(it); + + print(strSet); // ali mostafa mostafa ziad + + return 0; +} diff --git a/18-Programming-4kids/16_12.cpp b/18-Programming-4kids/16_12.cpp new file mode 100644 index 0000000..175eaea --- /dev/null +++ b/18-Programming-4kids/16_12.cpp @@ -0,0 +1,31 @@ +#include +#include +#include +using namespace std; + +void print(map &mp) { + // You could iterate on map and set normally like vector. Never to change keys while iterating + for (pair item: mp) + cout << item.first<<"-"< mp; // Array with index not integer + mp["Mostafa"] = 10; + mp["Saad"] = 20; + + print(mp); // Mostafa-10 | Saad-20 | + + map > my_data; + + vector x; + x.push_back(1); + x.push_back(2); + x.push_back(3); + + my_data['A'] = x; + cout< +#include +#include +using namespace std; + +void print(vector< vector > &v2d) { + for (auto row : v2d) // auto = vector > v2d(5, vector(7, 3)); + + cout< +#include // Covers all you need typically +using namespace std; + +int main() { + string test = "hi abc abc abc abc"; + + cout << test.substr(3) << "\n"; // abc abc abc abc + cout << test.substr(3, 5) << "\n"; // abc + + cout << test.find("abc") << "\n"; // 3 + + // starting the search at 6th character + cout << test.find("abc", 5) << "\n"; // 7 + + cout << "Mostafa at: " << test.find("Mostafa") << "\n"; // 18446744073709551615 + cout << "Mostafa at: " << (int) test.find("Mostafa") << "\n"; // -1 + + //Functions that searches for a CHARACTER from a given string + cout << test.find_last_of("cab") << "\n"; // 17 + cout << test.find_first_of("aic") << "\n"; // 1 + cout << test.find_first_of("aic", 4) << "\n"; // 5 + cout << test.find_first_not_of("aic") << "\n"; // 0 + + // replace from 4, 3 chars with x + test.replace(4, 3, "x"); + cout< +#include +using namespace std; + +struct employee { + int num1, num2; + string str; + + employee(int a, int b, string name) { + num1 = a, num2 = b, str = name; + } + + bool operator <(const employee& rhs) const { + // compare as we did before + if (false) { + if (num1 != rhs.num1) + return num1 < rhs.num1; + + if (str != rhs.str) + return str < rhs.str; + + return num2 < rhs.num2; + } + + if (false) { + // Or use pair + return make_pair(num1, make_pair(str, num2)) + < make_pair(rhs.num1, make_pair(rhs.str, rhs.num2)); + } + + // To use tie: must be variables + return std::tie(num1, str, num2) < + std::tie(rhs.num1, rhs.str, rhs.num2); + } +}; + +int main() { + set s; + s.insert(employee(10, 35, "mostafa")); + s.insert(employee(7, 15, "ali")); + s.insert(employee(10, 17, "ziad")); + s.insert(employee(10, 20, "mostafa")); + + for (auto emp : s) + cout << emp.num1 << " " << emp.str << " " << emp.num2 << "\n"; + + return 0; +} + diff --git a/18-Programming-4kids/16_16_hospital_v3_miniproject.cpp b/18-Programming-4kids/16_16_hospital_v3_miniproject.cpp new file mode 100644 index 0000000..95cb036 --- /dev/null +++ b/18-Programming-4kids/16_16_hospital_v3_miniproject.cpp @@ -0,0 +1,194 @@ +#include +#include +using namespace std; + +// Global variables +const int MAX_SPECIALIZATION = 20; + +// I just ignored this condition in this code +const int MAX_QUEUE = 5; + +struct hospital_queue { + // We might use priority_queue< pair > que; + // for direct insert front/back + // But it is slower + won't allow printing + + deque< pair > que; + int spec; + + hospital_queue() { + spec = -1; + } + + hospital_queue(int _spec) { + spec = _spec; + } + + bool add_end(string name, int st) { + auto item = make_pair(name, st); + que.push_back(item); + return true; + } + bool add_front(string name, int st) { + auto item = make_pair(name, st); + que.push_front(item); + return true; + } + + void remove_front() { + if (que.size() == 0) { + cout << "No patients at the moment. Have rest, Dr\n"; + return; + } + auto item = que.front(); + que.pop_front(); + cout << item.first << " please go with the Dr\n"; + } + + void print() { + if (que.size() == 0) + return; + + cout << "There are " << que.size() << " patients in specialization " << spec << "\n"; + for(auto item : que) { + cout << item.first << " "; + if (item.second) + cout << "urgent\n"; + else + cout << "regular\n"; + } + cout << "\n"; + } +}; + +struct hospital_system { + vector queues; + + hospital_system() { + queues = vector(MAX_SPECIALIZATION); + + for (int i = 0; i < MAX_SPECIALIZATION; ++i) + queues[i] = hospital_queue(i); + } + + void run() { + while (true) { + int choice = menu(); + + if (choice == 1) + add_patient(); + else if (choice == 2) + print_patients(); + else if (choice == 3) + get_next_patients(); + else + break; + } + } + + int menu() { + int choice = -1; + while (choice == -1) { + cout << "\nEnter your choice:\n"; + cout << "1) Add new patient\n"; + cout << "2) Print all patients\n"; + cout << "3) Get next patient\n"; + cout << "4) Exit\n"; + + cin >> choice; + + if (!(1 <= choice && choice <= 4)) { + cout << "Invalid choice. Try again\n"; + choice = -1; // loop keep working + } + } + return choice; + } + + bool add_patient() { + int spec, st; + string name; + + cout << "Enter specialization, name, status: "; + cin >> spec >> name >> st; + + bool status; + if (st == 0) + status = queues[spec].add_end(name, st); + else + status = queues[spec].add_front(name, st); + + if (status == false) { + cout<< "Sorry we can't add more patients for this specialization\n"; + return false; + } + + return true; + } + + void print_patients() { + cout << "****************************\n"; + for (int spec = 0; spec < MAX_SPECIALIZATION; ++spec) + queues[spec].print(); + } + + void get_next_patients() { + int spec; + cout << "Enter specialization: "; + cin >> spec; + + queues[spec].remove_front(); + } +}; + +int main() { + //freopen("c.in", "rt", stdin); + hospital_system hospital = hospital_system(); + hospital.run(); + return 0; +} + + +/* + +1 +15 mostafa 0 +1 +15 asmaa 0 +1 +15 belal 1 + +2 + +1 +15 ziad 1 +2 + +1 +15 safaa 0 + +1 15 ashraf +2 + +3 +10 + +3 +15 + +2 + +1 +7 soha 1 + +2 + +1 +15 amal 1 + +3 +7 + +2 + +*/ diff --git a/18-Programming-4kids/16_17_library_v2_miniproject.cpp b/18-Programming-4kids/16_17_library_v2_miniproject.cpp new file mode 100644 index 0000000..a382ff7 --- /dev/null +++ b/18-Programming-4kids/16_17_library_v2_miniproject.cpp @@ -0,0 +1,369 @@ +#include +#include +using namespace std; + +const int MAX_BOOKS = 10; +const int MAX_USERS = 10; + +struct book { + int id; + string name; + int total_quantity; + int total_borrowed; + + book() { + total_quantity = total_borrowed = 0; + id = -1; + name = ""; + } + + void read() { + cout << "Enter book info: id & name & total quantity: "; + cin >> id >> name >> total_quantity; + total_borrowed = 0; + } + + bool borrow(int user_id) { + if (total_quantity - total_borrowed == 0) + return false; + ++total_borrowed; + return true; + } + + void return_copy() { + assert(total_borrowed > 0); + --total_borrowed; + } + + bool has_prefix(string prefix) { + if (name.size() < prefix.size()) + return false; + + for (int i = 0; i < (int) prefix.size(); ++i) { + if (prefix[i] != name[i]) + return false; + } + return true; + } + void print() { + cout << "id = " << id << " name = " << name << " total_quantity " + << total_quantity << " total_borrowed " << total_borrowed + << "\n"; + } +}; + +bool cmp_book_by_name(book &a, book& b) { + return a.name < b.name; +} + +bool cmp_book_by_id(book &a, book& b) { + return a.id < b.id; +} + +struct user { + int id; + string name; + + // set will allow remove & sort easily + set borrowed_books_ids; + + user() { + name = ""; + id = -1; + } + + void read() { + cout << "Enter user name & national id: "; + cin >> name >> id; + } + + void borrow(int book_id) { + borrowed_books_ids.insert(book_id); + } + void return_copy(int book_id) { + auto it = borrowed_books_ids.find(book_id); + + if (it != borrowed_books_ids.end()) + borrowed_books_ids.erase(it); + else + cout << "User " << name << " never borrowed book id " << book_id + << "\n"; + } + + bool is_borrowed(int book_id) { + auto it = borrowed_books_ids.find(book_id); + return it != borrowed_books_ids.end(); + } + + void print() { + cout << "user " << name << " id " << id << " borrowed books ids: "; + for (int book_id : borrowed_books_ids) + cout << book_id << " "; + cout << "\n"; + } +}; + +struct library_system { + vector books; + vector users; + + library_system() { + } + + void run() { + while (true) { + int choice = menu(); + + if (choice == 1) + add_book(); + else if (choice == 2) + search_books_by_prefix(); + else if (choice == 3) + print_who_borrowed_book_by_name(); + else if (choice == 4) + print_library_by_id(); + else if (choice == 5) + print_library_by_name(); + else if (choice == 6) + add_user(); + else if (choice == 7) + user_borrow_book(); + else if (choice == 8) + user_return_book(); + else if (choice == 9) + print_users(); + else + break; + } + } + + int menu() { + int choice = -1; + while (choice == -1) { + cout << "\nLibrary Menu;\n"; + cout << "1) add_book\n"; + cout << "2) search_books_by_prefix\n"; + cout << "3) print_who_borrowed_book_by_name\n"; + cout << "4) print_library_by_id\n"; + cout << "5) print_library_by_name\n"; + cout << "6) add_user\n"; + cout << "7) user_borrow_book\n"; + cout << "8) user_return_book\n"; + cout << "9) print_users\n"; + cout << "10) Exit\n"; + + cout << "\nEnter your menu choice [1 - 10]: "; + cin >> choice; + + if (!(1 <= choice && choice <= 10)) { + cout << "Invalid choice. Try again\n"; + choice = -1; // loop keep working + } + } + return choice; + } + + void add_book() { + book b; + b.read(); + books.push_back(b); + } + + void search_books_by_prefix() { + cout << "Enter book name prefix: "; + string prefix; + cin >> prefix; + + int cnt = 0; + for (book &b : books) { + if (b.has_prefix(prefix)) { + cout << b.name << "\n"; + ++cnt; + } + } + + if (!cnt) + cout << "No books with such prefix\n"; + } + + void add_user() { + user u; + u.read(); + users.push_back(u); + } + + int find_book_idx_by_name(string name) { + for (int i = 0; i < (int) books.size(); ++i) { + if (name == books[i].name) + return i; + } + return -1; + } + + int find_user_idx_by_name(string name) { + for (int i = 0; i < (int) users.size(); ++i) { + if (name == users[i].name) + return i; + } + return -1; + } + + bool read_user_name_and_book_name(int &user_idx, int &book_idx, int trials = + 3) { + string user_name; + string book_name; + + while (trials--) { + cout << "Enter user name and book name: "; + cin >> user_name >> book_name; + + user_idx = find_user_idx_by_name(user_name); + + if (user_idx == -1) { + cout << "Invalid user name. Try again\n"; + continue; + } + book_idx = find_book_idx_by_name(book_name); + + if (book_idx == -1) { + cout << "Invalid book name. Try again\n"; + continue; + } + return true; + } + cout << "You did several trials! Try later."; + return false; + } + + void user_borrow_book() { + int user_idx, book_idx; + + if (!read_user_name_and_book_name(user_idx, book_idx)) + return; + + int user_id = users[user_idx].id; + int book_id = books[book_idx].id; + + if (!books[book_idx].borrow(user_id)) + cout << "No more copies available right now\n"; + else + users[user_idx].borrow(book_id); + } + + void user_return_book() { + int user_idx, book_idx; + + if (!read_user_name_and_book_name(user_idx, book_idx)) + return; + + int book_id = books[book_idx].id; + books[book_idx].return_copy(); + users[user_idx].return_copy(book_id); + } + + void print_library_by_id() { + sort(books.begin(), books.end(), cmp_book_by_id); + + cout << "\n"; + for (book &b : books) + b.print(); + } + + void print_library_by_name() { + sort(books.begin(), books.end(), cmp_book_by_name); + + cout << "\n"; + for (book &b : books) + b.print(); + } + + void print_users() { + cout << "\n"; + for (user &u : users) + u.print(); + } + + void print_who_borrowed_book_by_name() { + string book_name; + cout << "Enter book name: "; + cin >> book_name; + + int book_idx = find_book_idx_by_name(book_name); + + if (book_idx == -1) { + cout << "Invalid book name.\n"; + return; + } + int book_id = books[book_idx].id; + + if (books[book_idx].total_borrowed == 0) { + cout << "No borrowed copies\n"; + return; + } + + for (user &u : users) { + if (u.is_borrowed(book_id)) + cout << u.name << "\n"; + } + } +}; + +int main() { + //freopen("c.in", "rt", stdin); + + library_system library; + + library.run(); + + return 0; +} + +/* + + 1 100 math4 3 + 1 101 math2 5 + 1 102 math1 4 + 1 103 math3 2 + 1 201 prog1 5 + 1 201 prog2 3 + + 4 + 5 + + 6 mostafa 30301 + 6 ali 50501 + 6 noha 70701 + 6 ashraf 90901 + + 7 mostafa math1 + 7 mostafa math2 + 7 mostafa math3 + 7 ali math1 + 7 ali math2 + 7 noha math1 + 7 noha math2 + + 4 + 9 + + 2 ma + 2 pro + 2 machine + + 3 math1 + 3 math2 + 3 machine + + 4 + 9 + 8 mostafa math1 + 4 + 9 + + + + 10 + + + + */ diff --git a/18-Programming-4kids/16_18.cpp b/18-Programming-4kids/16_18.cpp new file mode 100644 index 0000000..dec5304 --- /dev/null +++ b/18-Programming-4kids/16_18.cpp @@ -0,0 +1,38 @@ +#include +#include +using namespace std; + +struct last_k_numbers_sum_stream { + int k; + + int sum = 0; + queue q; + + last_k_numbers_sum_stream(int _k) { + k = _k; + } + + int next(int new_num) { + // Compute and return sum of last K numbers sent so far + q.push(new_num); + sum += new_num; + + if((int)q.size() > k) { + sum -= q.front(); + q.pop(); + } + + return sum; + } +}; + + +int main() { + last_k_numbers_sum_stream processor(4); + + int num; + while(cin>>num) + cout< +#include +using namespace std; + +// https://leetcode.com/problems/valid-parentheses/ + +bool isValid(string string) { + map mp; // mp the close of each + mp[')'] = '('; + mp[']'] = '['; + mp['}'] = '{'; + + stack parentheses; + + for (char ch: string) { + if (mp.count(ch)) { + // A close one. It must match open one + if (parentheses.empty()) + return false; + + char open = mp[ch]; + char cur_open = parentheses.top(); + + if (open != cur_open) + return false; + parentheses.pop(); + } + else + parentheses.push(ch); + } + return parentheses.empty(); +} + + +int main() { + cout< +#include +using namespace std; + +int sum_vec(vector &a) { + int sum = 0; + for (auto x : a) + sum += x; + return sum; +} + +int max_3stack_sum(vector &a, vector &b, vector &c) { + int sa = sum_vec(a), sb = sum_vec(b), sc = sum_vec(c); + + while(!a.empty() && !b.empty() && !c.empty()) + { + if(sa == sb && sb == sc) + return sa; // as all +ve, this is tha max possible + + // Remove top element from max-sum stack + if (sa >= sb && sa >= sc) + sa -= a.back(), a.pop_back(); + else if (sb >= sa && sb >= sc) + sb -= b.back(), b.pop_back(); + else + sc -= c.back(), c.pop_back(); + } + return 0; +} + +int main() { + + vector a = {1, 2, 3, 4}; + vector b = {2, 2, 2, 4, 0}; + vector c = {0, 3, 3, 5}; + + cout< +#include +using namespace std; + +vector maxSlidingWindow1(vector& nums, int k) { + vector ret; + + if ((int)nums.size() < k) + return ret; + + multiset st; + for (int i = 0; i < k; ++i) { + st.insert(-nums[i]); + } + ret.push_back(-*st.begin()); + + for (int i = k; i < (int)nums.size(); ++i) { + st.erase(st.find(-nums[i-k])); + st.insert(-nums[i]); + ret.push_back(-*st.begin()); + } + return ret; +} + +// https://github.com/kamyu104/LeetCode-Solutions/blob/master/C++/sliding-window-maximum.cpp +// Very elegant faster solution, but harder to understand +// Key idea is to make always front of deque is index of current maximum +// Any time u add number, remove any previous number can't be the answer +// let's say [1 7 3 2 5] +// We enter 1, so fine +// Enter 7. Now, 1 never be an answer. so remove it +// Enter 3: notice when 7 removed, maybe 3 is answer +// Enter 2: notice when 7 & 3 removed, maybe 2 is answer +// Enter 5: now 3 2 never be answer, so remove them ==> [7, 5] +vector maxSlidingWindow2(vector& nums, int k) { + vector ret; + deque dq; // of indices for current window + for (int i = 0; i < (int)nums.size(); ++i) { + // Make sure ONLY k items in the deque + if (!dq.empty() && i - dq.front() == k) + dq.pop_front(); + + // Remove any number that never to be the answer + // Any number lower than current number can't be answer + while (!dq.empty() && nums[dq.back()] <= nums[i]) + dq.pop_back(); + + dq.push_back(i); + if (i >= k - 1) // answer always in front + ret.push_back(nums[dq.front()]); + } + return ret; +} + +int main() { + + vector a = {1,3,-1,-3,5,3,6,7}; + a = maxSlidingWindow1(a, 3); + + for (int x : a) + cout< +#include +using namespace std; + + +int main() { + // Create a 3D array using vectors + vector< vector>> v1; + vector< vector>> v2(3, vector>(4, vector(5, 100))); + cout<> > mp; + mp[10][20][-70] = 1; // remember that map is very slow compare to 3d vector + + return 0; +} diff --git a/18-Programming-4kids/16_homework_01_answer.cpp b/18-Programming-4kids/16_homework_01_answer.cpp new file mode 100644 index 0000000..65603fb --- /dev/null +++ b/18-Programming-4kids/16_homework_01_answer.cpp @@ -0,0 +1,28 @@ +#include +#include +using namespace std; + +void reverse_queue(queue& q) { + stack s; + + while(!q.empty()) + s.push(q.front()), q.pop(); + + while(!s.empty()) + q.push(s.top()), s.pop(); +} + +int main() { + + queue q; + q.push(1); + q.push(2); + q.push(3); + + reverse_queue(q); + + while(!q.empty()) + cout< +#include +using namespace std; + +// https://www.geeksforgeeks.org/implement-a-stack-using-single-queue/ + +struct OurStack { + queue q; + + /** + * To work properly, we need q always represents a stack at its front + * E.g. for pushes {1, 2, 3}, q should be {3, 2, 1} + * + * Assume a new value is 7, so we need q to be: 7, 3, 2, 1? + * But how can we put 4 at its front without using extra data structures? + * + * Let's add 7 normally: so now we have 3, 2, 1, 7 + * Now remove from the front 3 and add it to queue => 2, 1, 7, 3 + * Do same for 2, 1 + */ + void push(int val) { + int s = q.size(); + q.push(val); + + while (s--) + q.push(q.front()), q.pop(); + + } + void pop() { + if (!q.empty()) + q.pop(); + } + int top() { + return q.front(); + } + bool empty() { + return q.empty(); + } +}; + +int main() { + + OurStack s; + s.push(1); + s.push(2); + s.push(3); + + while (!s.empty()) + cout << s.top() << " ", s.pop(); + + return 0; +} diff --git a/18-Programming-4kids/16_homework_03_answer.cpp b/18-Programming-4kids/16_homework_03_answer.cpp new file mode 100644 index 0000000..820161c --- /dev/null +++ b/18-Programming-4kids/16_homework_03_answer.cpp @@ -0,0 +1,25 @@ +#include +#include +using namespace std; + +int reverse_num(int num) { + if (num == 0) + return 0; + + stack s; + while (num) + s.push(num % 10), num /= 10; + + int tens = 1; + while(!s.empty()) + num = s.top() * tens + num, tens *= 10, s.pop(); + + return num; +} + +int main() { + + cout< +#include +using namespace std; + +int main() { + map > mp; + + int n; + cin >> n; + + while (n--) { + string str; + cin >> str; + + // add all prefixes to the map + string cur = ""; + for (auto c : str) + cur += c, mp[cur].push_back(str); + } + + cin >> n; + + while (n--) { + string str; + cin >> str; + + for (auto cur : mp[str]) + cout << cur << " "; + cout << "\n"; + } + + return 0; +} diff --git a/18-Programming-4kids/16_homework_05_answer.cpp b/18-Programming-4kids/16_homework_05_answer.cpp new file mode 100644 index 0000000..7e1112d --- /dev/null +++ b/18-Programming-4kids/16_homework_05_answer.cpp @@ -0,0 +1,33 @@ +#include +#include +using namespace std; + +int main() { + map > mp; + + int n; + cin >> n; + + while (n--) { + string str; + cin >> str; + + // add all prefixes to the map + string cur = ""; + for (auto c : str) + cur += c, mp[cur].insert(str); + } + + cin >> n; + + while (n--) { + string str; + cin >> str; + + for (auto cur : mp[str]) + cout << cur << " "; + cout << "\n"; + } + + return 0; +} diff --git a/18-Programming-4kids/16_homework_06_answer.cpp b/18-Programming-4kids/16_homework_06_answer.cpp new file mode 100644 index 0000000..9c2bfef --- /dev/null +++ b/18-Programming-4kids/16_homework_06_answer.cpp @@ -0,0 +1,24 @@ +#include +#include +using namespace std; + +string removeDuplicates(string str) { + stack s; + + for (auto ch : str) { + if (!s.empty() && s.top() == ch) + s.pop(); + else + s.push(ch); + } + str = ""; + while (!s.empty()) + str = s.top() + str, s.pop(); + + return str; +} + +int main() { + cout << removeDuplicates("abbacaac") << "\n"; + return 0; +} diff --git a/18-Programming-4kids/16_homework_07_answer.cpp b/18-Programming-4kids/16_homework_07_answer.cpp new file mode 100644 index 0000000..15548e1 --- /dev/null +++ b/18-Programming-4kids/16_homework_07_answer.cpp @@ -0,0 +1,36 @@ +#include +#include +using namespace std; + +int scoreOfParentheses(string str) { + // Each integer represents total sum added to this parent Parenthes + stack st; + + // temp value to help us + st.push(0); + + for (auto c : str) { + if (c == '(') { + st.push(0); // new parent: current sum = 0 + } else { + int last = st.top(); + st.pop(); + + if (last == 0) + last = 1; // case () + else + last *= 2; // case (A). Get current sum and multiply + + // accumulate to current PARENT Parenthes + int parent_par = st.top() + last; // new total sum + st.pop(); + st.push(parent_par); + } + } + return st.top(); +} + +int main() { + cout< +#include +using namespace std; + +// https://github.com/kamyu104/LeetCode-Solutions/blob/master/C++/asteroid-collision.cpp + +vector asteroidCollision(vector& asteroids) { + vector result; + + for (auto& asteroid : asteroids) { + // For every new asteroid, remove all what will explode + // Only may happens when asteroid going backword and something coming forward + bool is_exploded = false; + while (!result.empty() && asteroid < 0 && 0 < result.back()) { + // last will explode. + if (result.back() < -asteroid) { + result.pop_back(); + continue; // See if more explode + } else if (result.back() == -asteroid) // both exploded + result.pop_back(); + is_exploded = true; // only asteroid explode + break; + } + if (!is_exploded) + result.push_back(asteroid); + } + return result; +} + +int main() { + + return 0; +} diff --git a/18-Programming-4kids/16_homework_09_answer.cpp b/18-Programming-4kids/16_homework_09_answer.cpp new file mode 100644 index 0000000..6c39f0c --- /dev/null +++ b/18-Programming-4kids/16_homework_09_answer.cpp @@ -0,0 +1,25 @@ +#include +#include +using namespace std; + +// https://www.geeksforgeeks.org/next-greater-element/ +vector next_greater_num(vector& v) { + vector result(v.size(), -1); + stack pos; + + for (int i = 0; i < (int) v.size(); ++i) { + while (!pos.empty() && v[i] > v[pos.top()]) + result[pos.top()] = v[i], pos.pop(); + pos.push(i); + } + return result; +} + +int main() { + vector v = { 73, 74, 75, 71, 69, 72, 76, 73 }; + v = next_greater_num(v); + + for (auto x : v) + cout << x << " "; + return 0; +} diff --git a/18-Programming-4kids/17_01.cpp b/18-Programming-4kids/17_01.cpp new file mode 100644 index 0000000..a1c1ee4 --- /dev/null +++ b/18-Programming-4kids/17_01.cpp @@ -0,0 +1,13 @@ +#include +#include +using namespace std; + + +int main() +{ + freopen("read_file.txt", "rt", stdin); + + freopen("my_output.txt", "wt", stdout); + + return 0; +} diff --git a/18-Programming-4kids/17_02.cpp b/18-Programming-4kids/17_02.cpp new file mode 100644 index 0000000..f135046 --- /dev/null +++ b/18-Programming-4kids/17_02.cpp @@ -0,0 +1,14 @@ +#include +#include +using namespace std; + +int main() { + freopen("read_file.txt", "rt", stdin); + + int x, y; + cin >> x >> y; + + cout << x + y; + + return 0; +} diff --git a/18-Programming-4kids/17_03.cpp b/18-Programming-4kids/17_03.cpp new file mode 100644 index 0000000..cbb242b --- /dev/null +++ b/18-Programming-4kids/17_03.cpp @@ -0,0 +1,23 @@ +#include +#include // for ifstream and ofstream +using namespace std; + +int main() { + ifstream fin("read_file.txt"); + + if(fin.fail()) + { + cout<<"Can't open the file\n"; + return 0; + } + int x, y; + fin >> x >> y; + + cout << x + y; + + fin.close(); + + // you can read from several files + + return 0; +} diff --git a/18-Programming-4kids/17_04.cpp b/18-Programming-4kids/17_04.cpp new file mode 100644 index 0000000..e66352b --- /dev/null +++ b/18-Programming-4kids/17_04.cpp @@ -0,0 +1,33 @@ +#include +#include // for ifstream and ofstream +using namespace std; + +int main() { + ifstream fin("read_file.txt"); + + if(fin.fail()) + { + cout<<"Can't open the file\n"; + return 0; + } + int x, y; + fin >> x >> y; + fin.close(); + + ofstream fout("my_output.txt"); + + if(fout.fail()) + { + cout<<"Can't open the output file\n"; + return 0; + } + + fout << x + y; + fout.close(); + + + + // you can read from several files + + return 0; +} diff --git a/18-Programming-4kids/17_05.cpp b/18-Programming-4kids/17_05.cpp new file mode 100644 index 0000000..de170e5 --- /dev/null +++ b/18-Programming-4kids/17_05.cpp @@ -0,0 +1,25 @@ +#include +#include // for ifstream and ofstream +using namespace std; + +int main() { + string path = "names.txt"; + fstream file_handler(path.c_str(), ios::in | ios::out | ios::app); + + if (file_handler.fail()) { + cout << "Can't open the file\n"; + return 0; + } + string first, second; + file_handler >> first >> second; + + cout << first << " " << second << "\n"; + + file_handler.clear(); // if any internal errors, before writing + + file_handler << "\nibrahim\n"; + + file_handler.close(); + + return 0; +} diff --git a/18-Programming-4kids/17_06.cpp b/18-Programming-4kids/17_06.cpp new file mode 100644 index 0000000..28f17e4 --- /dev/null +++ b/18-Programming-4kids/17_06.cpp @@ -0,0 +1,21 @@ +#include +#include // for ifstream and ofstream +using namespace std; + +int main() { + string path = "names.txt"; + fstream file_handler(path.c_str()); + + if (file_handler.fail()) { + cout << "Can't open the file\n"; + return 0; + } + string line; + + while (getline(file_handler, line)) + cout << line << "\n"; + + file_handler.close(); + + return 0; +} diff --git a/18-Programming-4kids/17_07.cpp b/18-Programming-4kids/17_07.cpp new file mode 100644 index 0000000..919bab9 --- /dev/null +++ b/18-Programming-4kids/17_07.cpp @@ -0,0 +1,16 @@ +#include +#include // istringstream +using namespace std; + +int main() { + string str = "Mostafa 23 years"; + istringstream iss(str); + + string name; + int age; + iss>>name>>age; + + cout< +#include // istringstream +using namespace std; + +int main() { + ostringstream oss; + + oss<<"Mostafa "; + oss<<50; + oss<<" years old\n"; + + cout< +using namespace std; + +/////////////////////////////// Helper Methods /////////////////////////////// +vector ReadFileLines(string path) { + vector lines; + + fstream file_handler(path.c_str()); + + if (file_handler.fail()) { + cout << "\n\nERROR: Can't open the file\n\n"; + return lines; + } + string line; + + while (getline(file_handler, line)) { + if (line.size() == 0) + continue; + lines.push_back(line); + } + + file_handler.close(); + return lines; +} + +void WriteFileLines(string path, vector lines, bool append = true) { + auto status = ios::in | ios::out | ios::app; + + if (!append) + status = ios::in | ios::out | ios::trunc; // overwrite + + fstream file_handler(path.c_str(), status); + + if (file_handler.fail()) { + cout << "\n\nERROR: Can't open the file\n\n"; + return; + } + for (auto line : lines) + file_handler << line << "\n"; + + file_handler.close(); +} + +vector SplitString(string s, string delimiter = ",") { + vector strs; + + int pos = 0; + string substr; + while ((pos = (int) s.find(delimiter)) != -1) { + substr = s.substr(0, pos); + strs.push_back(substr); + s.erase(0, pos + delimiter.length()); + } + strs.push_back(s); + return strs; +} + +int ToInt(string str) { + istringstream iss(str); + int num; + iss >> num; + + return num; +} + +int ReadInt(int low, int high) { + cout << "\nEnter number in range " << low << " - " << high << ": "; + int value; + + cin >> value; + + if (low <= value && value <= high) + return value; + + cout << "ERROR: invalid number...Try again\n"; + return ReadInt(low, high); +} + +int ShowReadMenu(vector choices) { + cout << "\nMenu:\n"; + for (int ch = 0; ch < (int) choices.size(); ++ch) { + cout << "\t" << ch + 1 << ": " << choices[ch] << "\n"; + } + return ReadInt(1, choices.size()); +} +////////////////////////////////////////////////////////////// + +struct Question { + int question_id; + // To support thread. Each question look to a parent question + // -1 No parent (first question in the thread) + int parent_question_id; + int from_user_id; + int to_user_id; + int is_anonymous_questions; // 0 or 1 + string question_text; + string answer_text; // empty = not answered + + Question() { + question_id = parent_question_id = from_user_id = to_user_id = -1; + is_anonymous_questions = 1; + } + + Question(string line) { + vector substrs = SplitString(line); + assert(substrs.size() == 7); + + question_id = ToInt(substrs[0]); + parent_question_id = ToInt(substrs[1]); + from_user_id = ToInt(substrs[2]); + to_user_id = ToInt(substrs[3]); + is_anonymous_questions = ToInt(substrs[4]); + question_text = substrs[5]; + answer_text = substrs[6]; + } + + string ToString() { + ostringstream oss; + oss << question_id << "," << parent_question_id << "," << from_user_id << "," << to_user_id << "," << is_anonymous_questions << "," << question_text << "," << answer_text; + + return oss.str(); + } + + void PrintToQuestion() { + string prefix = ""; + + if (parent_question_id != -1) + prefix = "\tThread: "; + + cout << prefix << "Question Id (" << question_id << ")"; + if (!is_anonymous_questions) + cout << " from user id(" << from_user_id << ")"; + cout << "\t Question: " << question_text << "\n"; + + if (answer_text != "") + cout << prefix << "\tAnswer: " << answer_text << "\n"; + cout << "\n"; + } + + void PrintFromQuestion() { + cout << "Question Id (" << question_id << ")"; + if (!is_anonymous_questions) + cout << " !AQ"; + + cout << " to user id(" << to_user_id << ")"; + cout << "\t Question: " << question_text; + + if (answer_text != "") + cout << "\tAnswer: " << answer_text << "\n"; + else + cout << "\tNOT Answered YET\n"; + } + + void PrintFeedQuestion() { + if (parent_question_id != -1) + cout << "Thread Parent Question ID (" << parent_question_id << ") "; + + cout << "Question Id (" << question_id << ")"; + if (!is_anonymous_questions) + cout << " from user id(" << from_user_id << ")"; + + cout << " To user id(" << to_user_id << ")"; + + cout << "\t Question: " << question_text << "\n"; + if (answer_text != "") + cout << "\tAnswer: " << answer_text <<"\n"; + } + +}; + +struct User { + int user_id; // internal system ID + string user_name; + string password; + string name; + string email; + int allow_anonymous_questions; // 0 or 1 + + vector questions_id_from_me; + // From question id to list of questions IDS on this question (thread questions) - For this user + map> questionid_questionidsThead_to_map; + + User() { + user_id = allow_anonymous_questions = -1; + } + + User(string line) { + vector substrs = SplitString(line); + assert(substrs.size() == 6); + + user_id = ToInt(substrs[0]); + user_name = substrs[1]; + password = substrs[2]; + name = substrs[3]; + email = substrs[4]; + allow_anonymous_questions = ToInt(substrs[5]); + } + + string ToString() { + ostringstream oss; + oss << user_id << "," << user_name << "," << password << "," << name << "," << email << "," << allow_anonymous_questions; + + return oss.str(); + } + + void Print() { + cout << "User " << user_id << ", " << user_name << " " << password << ", " << name << ", " << email << "\n"; + } +}; + +struct QuestionsManager { + // From question id to list of questions IDS on this question (thread questions) - All users + map> questionid_questionidsThead_to_map; + + // Map the question id to question object. Let's keep one place ONLY with the object + // When you study pointers, easier handling + map questionid_questionobject_map; + + int last_id; + + QuestionsManager() { + last_id = 0; + } + + void LoadDatabase() { + last_id = 0; + questionid_questionidsThead_to_map.clear(); + questionid_questionobject_map.clear(); + + vector lines = ReadFileLines("18_questions.txt"); + for (auto &line : lines) { + Question question(line); + last_id = max(last_id, question.question_id); + + questionid_questionobject_map[question.question_id] = question; + + if (question.parent_question_id == -1) + questionid_questionidsThead_to_map[question.question_id].push_back(question.question_id); + else + questionid_questionidsThead_to_map[question.parent_question_id].push_back(question.question_id); + } + } + + void FillUserQuestions(User &user) { + user.questions_id_from_me.clear(); + user.questionid_questionidsThead_to_map.clear(); + + for (auto &pair : questionid_questionidsThead_to_map) { // pair> + for (auto &question_id : pair.second) { // vector + + // Get the question from the map. & means same in memory, DON'T COPY + Question &question = questionid_questionobject_map[question_id]; + + if (question.from_user_id == user.user_id) + user.questions_id_from_me.push_back(question.question_id); + + if (question.to_user_id == user.user_id) { + if (question.parent_question_id == -1) + user.questionid_questionidsThead_to_map[question.question_id].push_back(question.question_id); + else + user.questionid_questionidsThead_to_map[question.parent_question_id].push_back(question.question_id); + } + } + } + } + + void PrintUserToQuestions(User &user) { + cout << "\n"; + + if (user.questionid_questionidsThead_to_map.size() == 0) + cout << "No Questions"; + + for (auto &pair : user.questionid_questionidsThead_to_map) { // pair> + for (auto &question_id : pair.second) { // vector + + // Get the question from the map. & means same in memory, DON'T COPY + Question &question = questionid_questionobject_map[question_id]; + question.PrintToQuestion(); + } + } + cout << "\n"; + } + + void PrintUserFromQuestions(User &user) { + cout << "\n"; + if (user.questions_id_from_me.size() == 0) + cout << "No Questions"; + + for (auto &question_id : user.questions_id_from_me) { // vector + + // Get the question from the map. & means same in memory, DON'T COPY + Question &question = questionid_questionobject_map[question_id]; + question.PrintFromQuestion(); + } + cout << "\n"; + } + + // Used in Answering a question for YOU. + // It can be any of your questions (thread or not) + int ReadQuestionIdAny(User &user) { + int question_id; + cout << "Enter Question id or -1 to cancel: "; + cin >> question_id; + + if (question_id == -1) + return -1; + + if (!questionid_questionobject_map.count(question_id)) { + cout << "\nERROR: No question with such ID. Try again\n\n"; + return ReadQuestionIdAny(user); + } + Question &question = questionid_questionobject_map[question_id]; + + if (question.to_user_id != user.user_id) { + cout << "\nERROR: Invalid question ID. Try again\n\n"; + return ReadQuestionIdAny(user); + } + return question_id; + } + + // Used to ask a question on a specific thread for whatever user + int ReadQuestionIdThread(User &user) { + int question_id; + cout << "For thread question: Enter Question id or -1 for new question: "; + cin >> question_id; + + if (question_id == -1) + return -1; + + if (!questionid_questionidsThead_to_map.count(question_id)) { + cout << "No thread question with such ID. Try again\n"; + return ReadQuestionIdThread(user); + } + return question_id; + } + + void AnswerQuestion(User &user) { + int question_id = ReadQuestionIdAny(user); + + if (question_id == -1) + return; + + Question &question = questionid_questionobject_map[question_id]; + + question.PrintToQuestion(); + + if (question.answer_text != "") + cout << "\nWarning: Already answered. Answer will be updated\n"; + + cout << "Enter answer: "; // if user entered comma, system fails :) + getline(cin, question.answer_text); // read last enter + getline(cin, question.answer_text); + } + + void DeleteQuestion(User &user) { + int question_id = ReadQuestionIdAny(user); + + if (question_id == -1) + return; + + vector ids_to_remove; // to remove from questionid_questionobject_map + + // Let's see if thread or not. If thread, remove all of it + if (questionid_questionidsThead_to_map.count(question_id)) { // thread + ids_to_remove = questionid_questionidsThead_to_map[question_id]; + questionid_questionidsThead_to_map.erase(question_id); + } else { + ids_to_remove.push_back(question_id); + + // let's find in which thread to remove. Consistency is important when have multi-view + for (auto &pair : questionid_questionidsThead_to_map) { + vector &vec = pair.second; + for (int pos = 0; pos < (int) vec.size(); ++pos) { + if (question_id == vec[pos]) { + vec.erase(vec.begin() + pos); + break; + } + } + } + + } + + for (auto id : ids_to_remove) { + questionid_questionobject_map.erase(id); + } + } + + void AskQuestion(User &user, pair to_user_pair) { + Question question; + + if (!to_user_pair.second) { + cout << "Note: Anonymous questions are not allowed for this user\n"; + question.is_anonymous_questions = 0; + } else { + cout << "Is anonymous questions?: (0 or 1): "; + cin >> question.is_anonymous_questions; + } + + question.parent_question_id = ReadQuestionIdThread(user); + + cout << "Enter question text: "; // if user entered comma, system fails :) + getline(cin, question.question_text); + getline(cin, question.question_text); + + question.from_user_id = user.user_id; + question.to_user_id = to_user_pair.first; + + // What happens in 2 parallel sessions who asked question? + // They are given same id. This is wrong handling :) + question.question_id = ++last_id; + + questionid_questionobject_map[question.question_id] = question; + + if (question.parent_question_id == -1) + questionid_questionidsThead_to_map[question.question_id].push_back(question.question_id); + else + questionid_questionidsThead_to_map[question.parent_question_id].push_back(question.question_id); + } + + void ListFeed() { + for (auto &pair : questionid_questionobject_map) { + Question &question = pair.second; + + if (question.answer_text == "") + continue; + + question.PrintFeedQuestion(); + } + } + + void UpdateDatabase() { + vector lines; + + for (auto &pair : questionid_questionobject_map) + lines.push_back(pair.second.ToString()); + + WriteFileLines("18_questions.txt", lines, false); + } +}; + +struct UsersManager { + map userame_userobject_map; + User current_user; + int last_id; + + UsersManager() { + last_id = 0; + } + + void LoadDatabase() { + last_id = 0; + userame_userobject_map.clear(); + + vector lines = ReadFileLines("18_users.txt"); + for (auto &line : lines) { + User user(line); + userame_userobject_map[user.user_name] = user; + last_id = max(last_id, user.user_id); + } + } + + void AccessSystem() { + int choice = ShowReadMenu( { "Login", "Sign Up" }); + if (choice == 1) + DoLogin(); + else + DoSignUp(); + } + + void DoLogin() { + LoadDatabase(); // in case user added from other parallel run + + while (true) { + cout << "Enter user name & password: "; + cin >> current_user.user_name >> current_user.password; + + if (!userame_userobject_map.count(current_user.user_name)) { + cout << "\nInvalid user name or password. Try again\n\n"; + continue; + } + User user_exist = userame_userobject_map[current_user.user_name]; + + if (current_user.password != user_exist.password) { + cout << "\nInvalid user name or password. Try again\n\n"; + continue; + } + current_user = user_exist; + break; + } + } + + void DoSignUp() { + while (true) { + cout << "Enter user name. (No spaces): "; + cin >> current_user.user_name; + + if (userame_userobject_map.count(current_user.user_name)) + cout << "Already used. Try again\n"; + else + break; + } + cout << "Enter password: "; + cin >> current_user.password; + + cout << "Enter name: "; + cin >> current_user.name; + + cout << "Enter email: "; + cin >> current_user.email; + + cout << "Allow anonymous questions? (0 or 1): "; + cin >> current_user.allow_anonymous_questions; + + // What happens in 2 parallel sessions if they signed up? + // They are given same id. This is wrong handling :) + current_user.user_id = ++last_id; + userame_userobject_map[current_user.user_name] = current_user; + + UpdateDatabase(current_user); + } + + void ListUsersNamesIds() { + for (auto &pair : userame_userobject_map) + cout << "ID: " << pair.second.user_id << "\t\tName: " << pair.second.name << "\n"; + } + + pair ReadUserId() { + int user_id; + cout << "Enter User id or -1 to cancel: "; + cin >> user_id; + + if (user_id == -1) + return make_pair(-1, -1); + + for (auto &pair : userame_userobject_map) { + if (pair.second.user_id == user_id) + return make_pair(user_id, pair.second.allow_anonymous_questions); + } + + cout << "Invalid User ID. Try again\n"; + return ReadUserId(); + } + + void UpdateDatabase(User &user) { + string line = user.ToString(); + vector lines(1, line); + WriteFileLines("18_users.txt", lines); + } +}; + +struct AskMeSystem { + UsersManager users_manager; + QuestionsManager questions_manager; + + void LoadDatabase(bool fill_user_questions = false) { + users_manager.LoadDatabase(); + questions_manager.LoadDatabase(); + + if (fill_user_questions) // first time, waiting for login + questions_manager.FillUserQuestions(users_manager.current_user); + } + + void run() { + LoadDatabase(); + users_manager.AccessSystem(); + questions_manager.FillUserQuestions(users_manager.current_user); + + vector menu; + menu.push_back("Print Questions To Me"); + menu.push_back("Print Questions From Me"); + menu.push_back("Answer Question"); + menu.push_back("Delete Question"); + menu.push_back("Ask Question"); + menu.push_back("List System Users"); + menu.push_back("Feed"); + menu.push_back("Logout"); + + while (true) { + int choice = ShowReadMenu(menu); + LoadDatabase(true); + + if (choice == 1) + questions_manager.PrintUserToQuestions(users_manager.current_user); + else if (choice == 2) + questions_manager.PrintUserFromQuestions(users_manager.current_user); + else if (choice == 3) { + questions_manager.AnswerQuestion(users_manager.current_user); + questions_manager.UpdateDatabase(); + } else if (choice == 4) { + questions_manager.DeleteQuestion(users_manager.current_user); + // Let's build again (just easier, but slow) + questions_manager.FillUserQuestions(users_manager.current_user); + questions_manager.UpdateDatabase(); + } else if (choice == 5) { + pair to_user_pair = users_manager.ReadUserId(); + if (to_user_pair.first != -1) { + questions_manager.AskQuestion(users_manager.current_user, to_user_pair); + questions_manager.UpdateDatabase(); + } + } else if (choice == 6) + users_manager.ListUsersNamesIds(); + else if (choice == 7) + questions_manager.ListFeed(); + else + break; + } + run(); // Restart again + } +}; + +int main() { + AskMeSystem service; + service.run(); + + return 0; +} + + +/* +101,-1,11,13,0,Should I learn C++ first or Java,I think C++ is a better Start +203,101,11,13,0,Why do you think so!,Just Google. There is an answer on Quora. +205,101,45,13,0,What about python?, +211,-1,13,11,1,It was nice to chat to you,For my pleasure Dr Mostafa +212,-1,13,45,0,Please search archive before asking, +300,101,11,13,1,Is it ok to learn Java for OOP?,Good choice +301,-1,11,13,0,Free to meet?, +302,101,11,13,1,Why so late in reply?, + +13,mostafa,111,mostafa_saad_ibrahim,mostafa@gmail.com,1 +11,noha,222,noha_salah,nono171@gmail.com,0 +45,ali,333,ali_wael,wael@gmail.com,0 + + */ diff --git a/18-Programming-4kids/18_questions.txt b/18-Programming-4kids/18_questions.txt new file mode 100644 index 0000000..bcaa2a7 --- /dev/null +++ b/18-Programming-4kids/18_questions.txt @@ -0,0 +1,3 @@ +211,-1,13,11,1,It was nice to chat to you,For my pleasure Dr Mostafa +212,-1,13,45,0,Please search archive before asking, +301,-1,11,13,0,Free to meet?, diff --git a/18-Programming-4kids/18_users.txt b/18-Programming-4kids/18_users.txt new file mode 100644 index 0000000..d16de1b --- /dev/null +++ b/18-Programming-4kids/18_users.txt @@ -0,0 +1,4 @@ +13,mostafa,111,mostafa_saad_ibrahim,mostafa@gmail.com,1 +11,noha,222,noha_salah,nono171@gmail.com,0 +45,ali,333,ali_wael,wael@gmail.com,0 + diff --git a/19-object-oriented-programming/02_homework_01_answer.cpp b/19-object-oriented-programming/02_homework_01_answer.cpp new file mode 100644 index 0000000..b0cf748 --- /dev/null +++ b/19-object-oriented-programming/02_homework_01_answer.cpp @@ -0,0 +1,60 @@ +#include +using namespace std; + +struct Date { + int day; + int month; + int year; + + // Returns the length of the month represented by this date. + int LengthOfMonth(); + + // Returns the length of the year represented by this date. + int LengthOfYear(); + + // Returns a copy of this LocalDate with the specified number of days subtracted. + Date MinusDays(int DaysToSubtract); + Date MinusMonths(int MonthsToSubtract); + Date MinusYears(int YearsToSubtract); + Date MinusWeeks(int WeeksToSubtract); + + // Similarly, we can add Days. E.g. PlusDays(int DaysToAdd) + + // To allow flexible strings, user provide format, + // e.g. yyyy.mm.dd returns (2014-07-26) and dd.mm returns (26-07) + string ToString(string format); + + bool isEqual(Date d); + bool isBefore(Date d); + bool isAfter(Date d); + + bool IsLeapYear(); // google if don't know + + // These are just some methods. In reality, much more complex. +}; + +//////////////////////////////////////////////////////////// + +// We can describe time struct in 2 ways: +// Normal way: 3 integers for hours, minutes and seconds +// Another way is 1 variable only: total number of seconds. Which can be converted to the other way + +// Although using 1 variable only saves memory, but it complicates the code. +// Clarity should be preferred than minor efficiency improvements + + +// In a debate with a college: +// Be open for different views (e.g, 2 ways for the data members) +// Defend your choices with logical reasons +// Also understand your college choices & reasons +// A lot of areas are just vague. We may not know which direction is definitely the right way +// Minor design concerns are not like big ones. System design is more risker than a class design +// Find someone with more experience to help you make decisions +// Or put time limit: discuss for an hour, then vote. +// Red flag if discussions are very lengthy with a few "action items" + + +int main() { + + return 0; +} diff --git a/19-object-oriented-programming/02_homework_02_answer.cpp b/19-object-oriented-programming/02_homework_02_answer.cpp new file mode 100644 index 0000000..faa002b --- /dev/null +++ b/19-object-oriented-programming/02_homework_02_answer.cpp @@ -0,0 +1,69 @@ +#include +using namespace std; + +/* +struct DateTime { + int day; + int month; + int year; + int hours; + int minutes; + int seconds; + + // Constructor + DateTime(int day, int month, int year, + int hours, int minutes, int seconds) { + } + + + + // A bunch of Time functions + // ... +}; +*/ + + +// The problem with above class it is responsible for 2 things +// Date and all its complications +// Time and all its complications +// Always focus a struct on a specific functionality (single responsibility) +// Then, each struct is easier to code +// Easy to give different developers different tasks + +struct Date { + int day; + int month; + int year; + + // A bunch of Data functions + // ... +}; + +struct Time { + int hours; + int minutes; + int seconds; + + // A bunch of Time functions + // ... +}; + +struct DateTime { + Date date; + Time time; + + // Constructor + DateTime(Date date, Time time) { + + } +}; + +// Design seperate Date & time structs +// Datetime is "composed" of Date and Time + + + +int main() { + + return 0; +} diff --git a/19-object-oriented-programming/02_homework_03_answer.cpp b/19-object-oriented-programming/02_homework_03_answer.cpp new file mode 100644 index 0000000..2a92ec6 --- /dev/null +++ b/19-object-oriented-programming/02_homework_03_answer.cpp @@ -0,0 +1,50 @@ +#include +using namespace std; + +const int MAX = 500; +string employee_first_name[MAX]; +string employee_middle_name[MAX]; +string employee_last_name[MAX]; +int employee_age[MAX]; +double employee_salary[MAX]; + + + + +struct BankCustomer { + string name; + string address; + string mobile; + string birth_of_date; + int rectangle_width; + string favourite_movie; + string favourite_color; + string favourite_actor; + string favourite_car_model; + string favourite_food; + + + // Potential several functions related to birth date +}; +/* + * Code Review comments from Mostafa to Mohamed: + * 1- rectangle_width; + * I can't think in a reason why this attribute is used. Probably copy/paste mistake. Be careful or clarify. + * + * 2- string favourite_* + * What is the value of all of these favourite attributes. In OOP, only "relevant" attributes are used + * Although a person could have favourite_food, but this is not relevant in our context (banking app) + * + * 3- string birth_of_date; + * As you know, we may have several functions related to birth date + * This data type(string) will be painful. Every time we will have to extract day/month/year + * You better add 3 integers for them. + * Even better, use the struct Date that we already built for the birth date. The class has a lot of functionalities + * This way we reduce the 'RESPONSIBILITY' of our class. RESUABILITY is critical concern in OO. + * Think in more COMPOSITION of other objects (e.g. BankCustomer has a Date, where Date is another object). + */ + +int main() { + + return 0; +} diff --git a/19-object-oriented-programming/02_homework_04_answer.txt b/19-object-oriented-programming/02_homework_04_answer.txt new file mode 100644 index 0000000..ee145ab --- /dev/null +++ b/19-object-oriented-programming/02_homework_04_answer.txt @@ -0,0 +1,8 @@ +So we have different shapes to draw + +Common: + Data: Color + Functions: Draw & Compute area, but each one has different behaviour + +Special: + Triangle need 3 sides (or points). Rectangle needs 4. Circle needs center and radius diff --git a/19-object-oriented-programming/02_homework_05_answer.txt b/19-object-oriented-programming/02_homework_05_answer.txt new file mode 100644 index 0000000..1856776 --- /dev/null +++ b/19-object-oriented-programming/02_homework_05_answer.txt @@ -0,0 +1,33 @@ +struct QueueInt { + int arr[100]; + + // some functionalities using type integer +}; + +struct QueueDouble { + double arr[100]; + + // exactly same as above, but replace integer with double +}; + +struct QueueString { + string arr[100]; + + // exactly same as above, but replace integer with string +}; + + + + + + + + +The clear problem is the code duplication. DRY (Don’t Repeat Yourself) + +In Stl we used something called template, a C++ mechanism +queue +queue +queue + +we write the queue one, but somehow we work on general type instead of a specific type diff --git a/19-object-oriented-programming/02_homework_06_answer.txt b/19-object-oriented-programming/02_homework_06_answer.txt new file mode 100644 index 0000000..f99ea30 --- /dev/null +++ b/19-object-oriented-programming/02_homework_06_answer.txt @@ -0,0 +1,3 @@ +Google, and any service, hide all its codebase. You are only given minor access to what you need + One advantage of that is making system usage simpler and cleaner + If you don't need anything, why you should be annoyed with its details! diff --git a/19-object-oriented-programming/02_homework_07_answer.txt b/19-object-oriented-programming/02_homework_07_answer.txt new file mode 100644 index 0000000..06b695b --- /dev/null +++ b/19-object-oriented-programming/02_homework_07_answer.txt @@ -0,0 +1,33 @@ + +1) We can sum from 1 to N in 2 ways +A) Loop to sum from 1 to N. Easy to code, but slow. E.g. for N = 10^10 +B) Use formula (N * (N+1))/2. Now this is very efficient + +In many cases, the same task can be done in several ways +- Some are clearly written and some are not +- Fast or slow +- Memory hungry or reasonable +- Heavy computations (you mobile become hot) or more efficient +- Consume your mobile data package (video call) or save it! + +It is not easy to build efficient software! + + +//////////////////////////////////////////////// + + +2) Like most of the provided systems, we know what the service provides us NOT how it works + E.g. you use messenger to chat. You care what are the possible things to do +  You don't care about how it is done or scaled to support 1 Billion user +   + Same logic in your TV & Car.  + + +As we provide support for Android, IOS, IPAD, we should be very careful from code duplication. +- Most of the system will be actually common code, e.g. fill rectangle color +- Some functionality will be more system dependency, e.g. loading an image from the storage + +- DRY (Don’t Repeat Yourself) + - Whatever common, design the system to reuse it + - E.g. Has a library class of handling shapes that is common + - A separate one for functions with the SAME NAME but DIFFERENT BEHAVIOUR, such as load image diff --git a/19-object-oriented-programming/03_01.cpp b/19-object-oriented-programming/03_01.cpp new file mode 100644 index 0000000..09d8b38 --- /dev/null +++ b/19-object-oriented-programming/03_01.cpp @@ -0,0 +1,36 @@ +#include +using namespace std; + +class Quote { +private: + int internal; + + string GetQuote() { + return "The way to get started is to " + "quit talking and begin doing"; + } + +public: + int external; + + Quote() { + internal = 3, external = 7; + } + + void print() { + cout< +using namespace std; + +class Result { + // Link, Short Summary, Rank +}; + +class Setting { + // E.g. Start-End Date + Type (text/image/video) +}; + +class Google { +private: + /* + * Huge amount of internal data & methods + * Huge amount of internal used classes + * + * User don't need to know about them + * User shouldn't access them! + */ + +public: + vector Search(string query, Setting setting) { + return vector(); + } +}; + +int main() { + // User care with WHAT not HOW (and its details) + Google engine; + vector results = + engine.Search("Resource for OOP", Setting()); + + return 0; +} diff --git a/19-object-oriented-programming/04_01.cpp b/19-object-oriented-programming/04_01.cpp new file mode 100644 index 0000000..8aa1456 --- /dev/null +++ b/19-object-oriented-programming/04_01.cpp @@ -0,0 +1,36 @@ +#include +using namespace std; + +struct Rectangle { + double width; + double height; + + Rectangle() { + width = height = 0; + } + + Rectangle(double width_, double height_) { + width = width_, height = height_; + } + + double ComputeArea() { + return width * height; + } + double ComputePerimeter() { + return 2 * (width + height); + } +}; + +int main() { + Rectangle r1; + r1.width = 5; + r1.height = 10; + cout << r1.ComputeArea() << "\n"; // 50 + + Rectangle r2(10, 3); + cout << r2.ComputeArea() << "\n"; // 30 + r2.width = 0; + cout << r2.ComputeArea() << "\n"; // 0 + + return 0; +} diff --git a/19-object-oriented-programming/04_02.cpp b/19-object-oriented-programming/04_02.cpp new file mode 100644 index 0000000..586d5b5 --- /dev/null +++ b/19-object-oriented-programming/04_02.cpp @@ -0,0 +1,49 @@ +#include +using namespace std; + +class Rectangle { +private: + double width; + double height; + +public: + Rectangle() { + width = height = 0; + } + Rectangle(double width_, double height_) { + width = width_, height = height_; + } + double ComputeArea() { + return width * height; + } + double ComputePerimeter() { + return 2 * (width + height); + } + // Setters & Getters + double GetHeight() { + return height; + } + void SetHeight(double height) { + this->height = height; + } + double GetWidth() { + return width; + } + void SetWidth(double width) { + this->width = width; + } +}; + +int main() { + Rectangle r1; + r1.SetWidth(5); + r1.SetHeight(10); + cout << r1.ComputeArea() << "\n"; // 50 + + Rectangle r2(10, 3); + cout << r2.ComputeArea() << "\n"; // 30 + r2.SetWidth(0); + cout << r2.ComputeArea() << "\n"; // 0 + + return 0; +} diff --git a/19-object-oriented-programming/04_03.cpp b/19-object-oriented-programming/04_03.cpp new file mode 100644 index 0000000..5ca3107 --- /dev/null +++ b/19-object-oriented-programming/04_03.cpp @@ -0,0 +1,59 @@ +#include +using namespace std; + +class Rectangle { +private: + double width; + double height; + +public: + Rectangle(); + Rectangle(double width_, double height_); + double ComputeArea(); + double ComputePerimeter(); + double GetHeight() ; + void SetHeight(double height); + double GetWidth() ; + void SetWidth(double width); +}; + +Rectangle::Rectangle() { + width = height = 0; +} +Rectangle::Rectangle(double width_, double height_) { + width = width_, height = height_; +} +double Rectangle::ComputeArea() { + return width * height; +} +double Rectangle::ComputePerimeter() { + return 2 * (width + height); +} +// Setters & Getters +double Rectangle::GetHeight() { + return height; +} +void Rectangle::SetHeight(double height) { + this->height = height; +} +double Rectangle::GetWidth() { + return width; +} +void Rectangle::SetWidth(double width) { + this->width = width; +} + +int main() { + cout< + +#include "04_04_rectangle.h" +using namespace std; + +int main() { + Rectangle r1; + r1.SetWidth(5); + r1.SetHeight(10); + cout << r1.ComputeArea() << "\n"; // 50 + + Rectangle r2(10, 3); + cout << r2.ComputeArea() << "\n"; // 30 + r2.SetWidth(0); + cout << r2.ComputeArea() << "\n"; // 0 + + return 0; +} diff --git a/19-object-oriented-programming/04_04_rectangle.cpp b/19-object-oriented-programming/04_04_rectangle.cpp new file mode 100644 index 0000000..d21f872 --- /dev/null +++ b/19-object-oriented-programming/04_04_rectangle.cpp @@ -0,0 +1,27 @@ +#include "04_04_rectangle.h" + +Rectangle::Rectangle() { + width = height = 0; +} +Rectangle::Rectangle(double width_, double height_) { + width = width_, height = height_; +} +double Rectangle::ComputeArea() { + return width * height; +} +double Rectangle::ComputePerimeter() { + return 2 * (width + height); +} +// Setters & Getters +double Rectangle::GetHeight() { + return height; +} +void Rectangle::SetHeight(double height) { + this->height = height; +} +double Rectangle::GetWidth() { + return width; +} +void Rectangle::SetWidth(double width) { + this->width = width; +} diff --git a/19-object-oriented-programming/04_04_rectangle.h b/19-object-oriented-programming/04_04_rectangle.h new file mode 100644 index 0000000..1807d15 --- /dev/null +++ b/19-object-oriented-programming/04_04_rectangle.h @@ -0,0 +1,20 @@ +#ifndef NUMBER_04_04_RECTANGLE_H_ +#define NUMBER_04_04_RECTANGLE_H_ + +class Rectangle { +private: + double width; + double height; + +public: + Rectangle(); + Rectangle(double width_, double height_); + double ComputeArea(); + double ComputePerimeter(); + double GetHeight() ; + void SetHeight(double height); + double GetWidth() ; + void SetWidth(double width); +}; + +#endif /* NUMBER_04_04_RECTANGLE_H_ */ diff --git a/19-object-oriented-programming/04_homework_01_answer.txt b/19-object-oriented-programming/04_homework_01_answer.txt new file mode 100644 index 0000000..8b1fa48 --- /dev/null +++ b/19-object-oriented-programming/04_homework_01_answer.txt @@ -0,0 +1,16 @@ +Real life analogy to explain Encapsulation, Data Hiding and Abstraction +=================== +A house can be thought of as an application. Drawing room, Bed room, Store room, Kitchen, Bath room etc can be thought of as its classes. + +According to the functionality, we put different items (data) in different part (classes) of the house such as Bed in bedroom, +sofa and TV in drawing room, utensils and stove in kitchen, soap, shampoo, buckets in bathroom etc. This is encapsulation. + +Most of the items are accessible to all the members of the house but some +valuables such as money and jewelery are kept hidden in the closet i.e. neither all the members of the house nor outsiders have access to them. +This is data hiding. + +In our house we use various appliances such as TV, Fridge, Fan, AC etc. +Neither we create them nor we have any interest in their internal workings. +We simply operate them i.e. their internal working is abstracted from us. This is abstraction. + +Src: https://www.quora.com/What-is-the-difference-between-abstraction-and-encapsulation-2 diff --git a/19-object-oriented-programming/04_homework_02_answer.txt b/19-object-oriented-programming/04_homework_02_answer.txt new file mode 100644 index 0000000..a5a279f --- /dev/null +++ b/19-object-oriented-programming/04_homework_02_answer.txt @@ -0,0 +1,3 @@ +Common between all: Name, Address, Gender, Birthdate +Common between last 2: Email Address, National ID +Unique: Preferred Snack, GPA, T-shirt size diff --git a/19-object-oriented-programming/04_homework_03_answer.cpp b/19-object-oriented-programming/04_homework_03_answer.cpp new file mode 100644 index 0000000..e7e6ecb --- /dev/null +++ b/19-object-oriented-programming/04_homework_03_answer.cpp @@ -0,0 +1,130 @@ +#include +using namespace std; + +class Room { +private: + int width; + int height; + string color; + +public: + const string& GetColor() { + return color; + } + + void SetColor(const string& color) { + this->color = color; + } + + int GetHeight() { + return height; + } + + void SetHeight(int height) { + this->height = height; + } + + int GetWidth() { + return width; + } + + void SetWidth(int width) { + this->width = width; + } +}; + +class Apartment { +private: + vector rooms; + vector bathroom; + int floor_number; + int apartment_number; + +public: + int GetApartmentNumber() { + return apartment_number; + } + + void SetApartmentNumber(int apartmentNumber) { + apartment_number = apartmentNumber; + } + + int GetFloorNumber() { + return floor_number; + } + + void SetFloorNumber(int floorNumber) { + floor_number = floorNumber; + } + + const vector& GetRooms() { + return rooms; + } + + void SetRooms(const vector& rooms) { + this->rooms = rooms; + } + + const vector& GetBathroom() { + return bathroom; + } + + void SetBathroom(const vector& bathroom) { + this->bathroom = bathroom; + } +}; + +class Elevator { +private: + int width; + int height; + int max_people; + int max_weight; + // Date: installation date, last maintenance date, manufacture + +public: + int GetHeight() { + return height; + } + + void SetHeight(int height) { + this->height = height; + } + + int GetMaxPeople() { + return max_people; + } + + void SetMaxPeople(int maxPeople) { + max_people = maxPeople; + } + + int GetMaxWeight() { + return max_weight; + } + + void SetMaxWeight(int maxWeight) { + max_weight = maxWeight; + } + + int GetWidth() { + return width; + } + + void SetWidth(int width) { + this->width = width; + } +}; + +class Building { +private: + vector apartments; + vector elevators; +}; + +int main() { + + __gcd(2, 8); + + return 0; +} diff --git a/19-object-oriented-programming/04_homework_04_answer.cpp b/19-object-oriented-programming/04_homework_04_answer.cpp new file mode 100644 index 0000000..35b701a --- /dev/null +++ b/19-object-oriented-programming/04_homework_04_answer.cpp @@ -0,0 +1,87 @@ +#include +using namespace std; + +class Invoice { +private: + int item_number; + string name; + double price; + int quantity; + +public: + Invoice(const int &item_number, const string &name, const double &price, const int &quantity = 1); + + int GetItemNumber(); + void SetItemNumber(int itemNumber); + string& GetName(); + void SetName(string& name); + double GetPrice(); + void SetPrice(double price); + int GetQuantity(); + void SetQuantity(int quantity); + + double GetTotalPrice(); + void Print(); + string ToString(); +}; + +Invoice::Invoice(const int &item_number, const string &name, const double &price, const int &quantity) : + item_number(item_number), name(name), price(price), quantity(quantity) { + +} + +int Invoice::GetItemNumber() { + return item_number; +} + +void Invoice::SetItemNumber(int itemNumber) { + item_number = itemNumber; +} + +string& Invoice::GetName() { + return name; +} + +void Invoice::SetName(string& name) { + this->name = name; +} + +double Invoice::GetPrice() { + return price; +} + +void Invoice::SetPrice(double price) { + this->price = price; +} + +int Invoice::GetQuantity() { + return quantity; +} + +void Invoice::SetQuantity(int quantity) { + this->quantity = quantity; +} + +double Invoice::GetTotalPrice() { + return GetPrice() * GetQuantity(); +} + +void Invoice::Print() { + cout << "Item Name: " << GetName() << "\n"; + cout << "Item Price: " << GetPrice() << "\n"; + cout << "Item Quantity: " << GetQuantity() << "\n"; + cout << "Item item number: " << GetItemNumber() << "\n"; + cout << "Item Total Price: " << GetTotalPrice() << "\n"; +} + +string Invoice::ToString() { + ostringstream oss; + oss << GetName() << "," << GetPrice() << "," << GetQuantity() << "," << GetItemNumber(); + return oss.str(); +} + +// In proper class, there will be more verifications in the class and better coding + +int main() { + return 0; +} diff --git a/19-object-oriented-programming/04_homework_05_answer.cpp b/19-object-oriented-programming/04_homework_05_answer.cpp new file mode 100644 index 0000000..33b2e6d --- /dev/null +++ b/19-object-oriented-programming/04_homework_05_answer.cpp @@ -0,0 +1,52 @@ +#include +using namespace std; + +class MyClass { +private: + int x; + int y; + int z; + +public: + void set(int x) { + cout << "A\n"; + } + void set(double x) { + cout << "B\n"; + } + void set(int x, int y) { + cout << "C\n"; + } + void set(int x, int y, int z) { + cout << "D\n"; + } + void get(int &a) { + a = x; + cout << "E\n"; + } + void get(int &a, int &b) { + a = x, b = y; + cout << "F\n"; + } +}; + +int main() { + MyClass m; + m.set(1); + m.set(1.5); + m.set(1, 2); + m.set(1, 2, 3); + + return 0; +} + +/* + +A +B +C +D + +This is called function overloading + https://beginnersbook.com/2017/08/cpp-function-overloading/ +*/ diff --git a/19-object-oriented-programming/04_homework_06_answer.cpp b/19-object-oriented-programming/04_homework_06_answer.cpp new file mode 100644 index 0000000..1065273 --- /dev/null +++ b/19-object-oriented-programming/04_homework_06_answer.cpp @@ -0,0 +1,31 @@ +#include +using namespace std; + +class LuckyNum { +private: + int num = 13; +public: + + void PrintAddress() { + printf("Function address :%p\n", &LuckyNum::PrintAddress); + printf("Data address :%p\n", &num); + } +}; + +int main() { + LuckyNum r1; + r1.PrintAddress(); + + + LuckyNum r2; + r2.PrintAddress(); + + /* + * Each object variables will have different address in memory! + * + * However, function are common procedures + * So only one function is loaded in memory with common address + */ + + return 0; +} diff --git a/19-object-oriented-programming/05_01.cpp b/19-object-oriented-programming/05_01.cpp new file mode 100644 index 0000000..d2a663c --- /dev/null +++ b/19-object-oriented-programming/05_01.cpp @@ -0,0 +1,51 @@ +#include +using namespace std; + +class Rectangle { +private: + double width; + double height; + +public: + Rectangle() { + width = height = 0; + } + Rectangle(double width_, double height_) { + width = width_; + height = height_; + } + + double ComputeArea() { + return width * height; + } + double ComputePerimeter() { + return 2 * (width + height); + } + // Setters & Getters + double GetHeight() { + return height; + } + void SetHeight(double height) { + this->height = height; + } + double GetWidth() { + return width; + } + void SetWidth(double width) { + this->width = width; + } +}; + +int main() { + Rectangle r1; + r1.SetWidth(5); + r1.SetHeight(10); + cout << r1.ComputeArea() << "\n"; // 50 + + Rectangle r2(10, 3); + cout << r2.ComputeArea() << "\n"; // 30 + r2.SetWidth(0); + cout << r2.ComputeArea() << "\n"; // 0 + + return 0; +} diff --git a/19-object-oriented-programming/05_02.cpp b/19-object-oriented-programming/05_02.cpp new file mode 100644 index 0000000..e286685 --- /dev/null +++ b/19-object-oriented-programming/05_02.cpp @@ -0,0 +1,58 @@ +#include +using namespace std; + +class Rectangle { +private: + double width; + double height; + +public: + Rectangle() : Rectangle(0.0, 0.0) { + // Delegating ructor + // Off-topic: Google power of delegation in workplace + } + Rectangle(double width, double height) : + width(width), height(height) { + // It is called member initializer list + } + + Rectangle(double width) : + width(width), height(0) { + // Function Overloading + } + + + double ComputeArea() { + return width * height; + } + double ComputePerimeter() { + return 2 * (width + height); + } + // Setters & Getters + double GetHeight() { + return height; + } + void SetHeight(double height) { + this->height = height; + } + double GetWidth() { + return width; + } + void SetWidth(double width) { + this->width = width; + } +}; + +int main() { + Rectangle r1; + r1.SetWidth(5); + r1.SetHeight(10); + cout << r1.ComputeArea() << "\n"; // 50 + + Rectangle r2(10, 3); + cout << r2.ComputeArea() << "\n"; // 30 + r2.SetWidth(0); + cout << r2.ComputeArea() << "\n"; // 0 + + return 0; +} diff --git a/19-object-oriented-programming/05_03.cpp b/19-object-oriented-programming/05_03.cpp new file mode 100644 index 0000000..f0d7e5b --- /dev/null +++ b/19-object-oriented-programming/05_03.cpp @@ -0,0 +1,46 @@ +#include +using namespace std; + +class Rectangle { +private: + double width; + double height; + +public: + Rectangle() : width(0), height(0) { + // No arguments + } + + Rectangle(int width = 0, int height = 0) : width(0), height(0) { + // default values + } + + // This code won't compile, as both are same overloaded + + double ComputeArea() { + return width * height; + } + double ComputePerimeter() { + return 2 * (width + height); + } + // Setters & Getters + double GetHeight() { + return height; + } + void SetHeight(double height) { + this->height = height; + } + double GetWidth() { + return width; + } + void SetWidth(double width) { + this->width = width; + } +}; + +int main() { + Rectangle r1; + cout << r1.ComputeArea() << "\n"; // 50 + + return 0; +} diff --git a/19-object-oriented-programming/05_04.cpp b/19-object-oriented-programming/05_04.cpp new file mode 100644 index 0000000..5707d68 --- /dev/null +++ b/19-object-oriented-programming/05_04.cpp @@ -0,0 +1,37 @@ +#include +using namespace std; + +class Rectangle { +private: + double width = 10; + double height = 20; + +public: + + double ComputeArea() { + return width * height; + } + double ComputePerimeter() { + return 2 * (width + height); + } + // Setters & Getters + double GetHeight() { + return height; + } + void SetHeight(double height) { + this->height = height; + } + double GetWidth() { + return width; + } + void SetWidth(double width) { + this->width = width; + } +}; + +int main() { + Rectangle r1; + cout << r1.ComputeArea() << "\n"; // 200 + + return 0; +} diff --git a/19-object-oriented-programming/05_05.cpp b/19-object-oriented-programming/05_05.cpp new file mode 100644 index 0000000..e19b4ee --- /dev/null +++ b/19-object-oriented-programming/05_05.cpp @@ -0,0 +1,42 @@ +#include +using namespace std; + +class Rectangle { +private: + double width; + double height; + +public: + Rectangle(int width, int height) : width(0), height(0) { + } + + // This code won't compile. + // You must provide default if have other ructors + + double ComputeArea() { + return width * height; + } + double ComputePerimeter() { + return 2 * (width + height); + } + // Setters & Getters + double GetHeight() { + return height; + } + void SetHeight(double height) { + this->height = height; + } + double GetWidth() { + return width; + } + void SetWidth(double width) { + this->width = width; + } +}; + +int main() { + Rectangle r1; + cout << r1.ComputeArea() << "\n"; // 50 + + return 0; +} diff --git a/19-object-oriented-programming/05_06.cpp b/19-object-oriented-programming/05_06.cpp new file mode 100644 index 0000000..450e4bf --- /dev/null +++ b/19-object-oriented-programming/05_06.cpp @@ -0,0 +1,45 @@ +#include +using namespace std; + +class Rectangle { +private: + double width; + double height; + +public: + Rectangle() : width(0), height(0) { + } + + ~Rectangle() { + cout<<"Destructor\n"; + } + + double ComputeArea() { + return width * height; + } + double ComputePerimeter() { + return 2 * (width + height); + } + // Setters & Getters + double GetHeight() { + return height; + } + void SetHeight(double height) { + this->height = height; + } + double GetWidth() { + return width; + } + void SetWidth(double width) { + this->width = width; + } +}; + +int main() { + Rectangle r1; + r1.SetWidth(5); + r1.SetHeight(10); + cout << r1.ComputeArea() << "\n"; // 50 + + return 0; +} diff --git a/19-object-oriented-programming/05_07.cpp b/19-object-oriented-programming/05_07.cpp new file mode 100644 index 0000000..74c25f5 --- /dev/null +++ b/19-object-oriented-programming/05_07.cpp @@ -0,0 +1,33 @@ +#include +using namespace std; + +class MyVector { +private: + int *arr; + int len = 100; + +public: + MyVector(int len_, int default_value = 0) { + len = len_; + arr = new int[len_]; + + for (int i = 0; i < len; ++i) { + arr[i] = default_value; + } + } + ~MyVector() { + delete[] arr; + } + int get(int pos) { + return arr[pos]; + } +}; + +int main() { + MyVector v(10, 12345); + + cout< +using namespace std; + +class MyVector { +private: + int *arr; + int len = 100; + +public: + MyVector(int len, int default_value = 0) { + this->len = len; + this->arr = new int[len]; + + for (int i = 0; i < len; ++i) { + this->arr[i] = default_value; + } + } + ~MyVector() { + delete[] this->arr; + } + int get(int pos) { + return this->arr[pos]; + } +}; + +int main() { + MyVector v(10, 12345); + + cout< +using namespace std; + +class A { +private: +public: + A() { + cout<<"A Constructor\n"; + } + ~A() { + cout<<"A Destructor\n"; + } +}; + +class B { +private: +public: + B() { + cout<<"B Constructor\n"; + } + ~B() { + cout<<"B Destructor\n"; + } +}; + +class C { +private: +public: + C() { + cout<<"C Constructor\n"; + } + ~C() { + cout<<"C Destructor\n"; + } +}; + +class D { +private: + A aa; + B bb; + C cc; + +public: + D() : bb(B()), aa(A()), cc(C()){ + cout<<"D Constructor\n"; + } + ~D() { + cout<<"D Destructor\n"; + } +}; + +int main() { + D d; + + return 0; +} +/* +A Constructor +B Constructor +C Constructor +D Constructor +D Destructor +C Destructor +B Destructor +A Destructor + + +From results: Constructors are called based on Class data members order NOT initalizer list order + */ diff --git a/19-object-oriented-programming/05_homework_02.cpp b/19-object-oriented-programming/05_homework_02.cpp new file mode 100644 index 0000000..f9151f8 --- /dev/null +++ b/19-object-oriented-programming/05_homework_02.cpp @@ -0,0 +1,38 @@ +#include +using namespace std; + +class ClassA { +public: + ClassA() { + cout<<"ClassA Constructor\n"; + } +}; + +class ClassB { +private: + ClassA aa; + int x; +public: + ClassB(int x) { + this->aa = ClassA(); + this->x = x; + } +}; + +class ClassC { +private: + int &y; + ClassB bb; + +public: + ClassC(int &y, const ClassB &bb){ + } +}; + + +int main() { + int hello = 10; + ClassB b(5); + ClassC cc(hello, b); + return 0; +} diff --git a/19-object-oriented-programming/05_homework_02_answer.cpp b/19-object-oriented-programming/05_homework_02_answer.cpp new file mode 100644 index 0000000..fd692df --- /dev/null +++ b/19-object-oriented-programming/05_homework_02_answer.cpp @@ -0,0 +1,50 @@ +#include +using namespace std; + +class ClassA { +public: + ClassA() { + cout << "ClassA Constructor\n"; + } +}; + +class ClassB { +private: + ClassA aa; // originally this line needs to call constructor to default in begin + int x; +public: + ClassB(int x) : + aa(ClassA()), x(x) { + // Originally the constructor of classA called twice + // Once to be default Initialized + // Once inside the constructor + + // Moving to Initializer list, then we Initialize it before construction only once + + // Tip: Always use Initializer list + // Note: If a member object is not initialized through a member initializer, the member object’s default constructor will be called "implicitly". + // Avoid duplicate initlaization! + } +}; + +class ClassC { +private: + int &y; + ClassB bb; + +public: + ClassC(int &y, const ClassB &bb) : + y(y), bb(bb) { + // 1- The only way to initialize a reference is intializer list + // 1- The only way to initialize a class that doesn't have default constructor (e.g. Class B) is intializer list + } +}; + +// Tip: please use initalizer list as much as possible! + +int main() { + int hello = 10; + ClassB b(5); + ClassC cc(hello, b); + return 0; +} diff --git a/19-object-oriented-programming/05_homework_03_answer.cpp b/19-object-oriented-programming/05_homework_03_answer.cpp new file mode 100644 index 0000000..9d5fe5f --- /dev/null +++ b/19-object-oriented-programming/05_homework_03_answer.cpp @@ -0,0 +1,53 @@ +#include +using namespace std; + +class A { +private: +public: + A() { + cout<<"A Constructor\n"; + } + ~A() { + cout<<"A Destructor\n"; + } +}; + +class B { +private: +public: + B() { + cout<<"B Constructor\n"; + } + ~B() { + cout<<"B Destructor\n"; + } +}; + +class C { +private: +public: + C() { + cout<<"C Constructor\n"; + } + ~C() { + cout<<"C Destructor\n"; + } +}; + +class D { +private: + A aa; + B bb; + C cc; + +public: + D(const A &a, const B &b, const C &c) : aa(a), bb(b), cc(c){ + // By using & => we use same memory object hence faster and low memory + // By using const => we remember developers you shouldn't try to change this parameter + } +}; + +int main() { + + return 0; +} diff --git a/19-object-oriented-programming/05_homework_04_answer.cpp b/19-object-oriented-programming/05_homework_04_answer.cpp new file mode 100644 index 0000000..f19a1d4 --- /dev/null +++ b/19-object-oriented-programming/05_homework_04_answer.cpp @@ -0,0 +1,55 @@ +#include +using namespace std; + +class OurPrice { +private: + int price; + +public: + OurPrice(int price){ + SetPrice(price); + } + + int GetPrice() const { + return price; + } + + void SetPrice(int price) { + if (price < 10) + price = 0; + this->price = price; + } + + int SomeFun() { + int price = 10; + int price2 = 20; + int price3 = 20; + + // Is below price variable the local price with value 10 or the class class? + // For a clear and maintainable code, avoid local variable names with same name as data members. + return price + price2 + price3; + } +}; + +int main() { + return 0; +} + + +/* +OurPrice constructor should be public to use it + +Notice that SetPrice involves some checks and changes for the input parameter. The constructor forget that + +One way to fix it, to do the same in the constructor. But this duplicate the code! +One fix is to call SetPrice from the constructor or move common code to a function + +The tip: Be careful when your setter has more logic (verification, throw an exception, change parameter's value) + +=== + +A constructor can call other member functions of the class, such as set or get functions, +but because the constructor is initializing the object, the data members may not yet be initialized. +Using data members before they have been properly initialized can cause logic errors. + C++ how to program (9.1) +*/ diff --git a/19-object-oriented-programming/05_homework_05.cpp b/19-object-oriented-programming/05_homework_05.cpp new file mode 100644 index 0000000..c698820 --- /dev/null +++ b/19-object-oriented-programming/05_homework_05.cpp @@ -0,0 +1,62 @@ +#include +using namespace std; + +class Time { +private: + int hours, minutes, seconds; + +public: + Time(int hours, int minutes, int seconds) : + hours(hours), minutes(minutes), seconds(seconds) { + } + void SetTime(int hours, int minutes, int seconds) { + // Put on separate lines for code clarity + // Still there is a missing point her. + // We better use setters as they validate/change input + this->hours = hours; + this->minutes = minutes; + this->seconds = seconds; + } + int GetTotalSeconds() { + return hours * 60 * 60 + minutes * 60 + seconds; + } + int GetTotalMinutes() { + return hours * 60 + minutes; + } + void PrintHHMMSS() { + cout << hours << ":" << minutes << ":" << seconds << "\n"; + } + string ToSring(string seperator = "-") { + ostringstream oss; + oss << hours << seperator << minutes << seperator << seconds; + return oss.str(); + } + int GetHours() { + return hours; + } + void SetHours(int hours) { + this->hours = hours; + } + int GetMinutes() { + return minutes; + } + void SetMinutes(int minutes) { + if (minutes < 0) + minutes = 0; + this->minutes = minutes; + } + int GetSeconds() { + return seconds; + } + void SetSeconds(int seconds) { + if (seconds < 0) + seconds = 0; + this->seconds = seconds; + } +}; + +int main() { + Time t(0, 1, 1); + t.PrintHHMMSS(); + return 0; +} diff --git a/19-object-oriented-programming/05_homework_05_answer.cpp b/19-object-oriented-programming/05_homework_05_answer.cpp new file mode 100644 index 0000000..f090c5f --- /dev/null +++ b/19-object-oriented-programming/05_homework_05_answer.cpp @@ -0,0 +1,72 @@ +#include +using namespace std; + +class Time { +private: + // Put on separate lines for code clarity + int hours; + int minutes; + int seconds; + +public: + Time(int hours, int minutes, int seconds) { + // There is member function doing the same task + // Avoid code duplication + SetTime(hours, minutes, seconds); + } + void SetTime(int hours, int minutes, int seconds) { + // Put on separate lines for code clarity + // Still there is a missing point her. + // We better use setters as they validate/change input + this->hours = hours; + this->minutes = minutes; + this->seconds = seconds; + } + int GetTotalSeconds() { + return hours * 60 * 60 + minutes * 60 + seconds; + } + int GetTotalMinutes() { + return hours * 60 + minutes; + } + void PrintHHMMSS() { + // Code duplication! + cout<hours = hours; + } + int GetMinutes() { + return minutes; + } + void SetMinutes(int minutes) { + if (minutes < 0) + minutes = 0; + this->minutes = minutes; + } + int GetSeconds() { + return seconds; + } + void SetSeconds(int seconds) { + if (seconds < 0) + seconds = 0; + this->seconds = seconds; + } +}; + +int main() { + // This will print wrongly. E.g. every 60 second should be added as a minute. Every 60 minutes should be added as an hour + Time t(0, 120, 120); + t.PrintHHMMSS(); // proper printing: 2:2:0 + return 0; +} diff --git a/19-object-oriented-programming/05_homework_06_answer.cpp b/19-object-oriented-programming/05_homework_06_answer.cpp new file mode 100644 index 0000000..81e1269 --- /dev/null +++ b/19-object-oriented-programming/05_homework_06_answer.cpp @@ -0,0 +1,102 @@ +#include +using namespace std; + +class Time { +private: + int hours; + int minutes; + int seconds; + +public: + Time(int hours, int minutes, int seconds) { + SetTime(hours, minutes, seconds); + } + void SetTime(int hours, int minutes, int seconds) { + this->hours = hours; + this->minutes = minutes; + this->seconds = seconds; + } + int GetTotalSeconds() { + return hours * 60 * 60 + minutes * 60 + seconds; + } + int GetTotalMinutes() { + return hours * 60 + minutes; + } + void PrintHHMMSS() { + cout<hours = hours; + + return *this; + } + int GetMinutes() { + return minutes; + } + Time& SetMinutes(int minutes) { + if (minutes < 0) + minutes = 0; + this->minutes = minutes; + + return *this; + } + int GetSeconds() { + return seconds; + } + Time& SetSeconds(int seconds) { + if (seconds < 0) + seconds = 0; + this->seconds = seconds; + + return *this; + } +}; + +/* +what does it mean to do + 1) t.SetHours(5).Something? + .Something is a function, then it needs object + then t.SetHours(5) must return object of type time NOT void + + So we need to return object from these setters + + 2) Now each object has pointer to itself this + *this is the object + We can return this but there is a problem + It will be a copy, so NOT same + This means we are modifying some temporary object NOT t itself! + + To solve that, return the object by reference: Time&T + + So overall + Time& SomeSetter + return *this + + + +Q: Was it possible / More OOP to add const to return?: + + const Time& SetMinutes(int minutes) + + */ + +int main() { + + Time t(3, 1, 2); + t.PrintHHMMSS(); // 3:1:2 + + t.SetHours(5).SetMinutes(45).SetSeconds(13); + t.PrintHHMMSS(); // 5:45:13 + + return 0; +} diff --git a/19-object-oriented-programming/05_homework_07_answer.cpp b/19-object-oriented-programming/05_homework_07_answer.cpp new file mode 100644 index 0000000..3137438 --- /dev/null +++ b/19-object-oriented-programming/05_homework_07_answer.cpp @@ -0,0 +1,77 @@ +#include +using namespace std; + +class Time { +private: + int total_seconds; + +public: + Time(int hours, int minutes, int seconds) { + // Delegation: give another object/function the task to do it for you + SetTime(hours, minutes, seconds); + } + void SetTime(int hours, int minutes, int seconds) { + total_seconds = 0; + SetHours(hours); + SetMinutes(minutes); + SetSeconds(seconds); + } + int GetTotalSeconds() { + return total_seconds; + } + int GetTotalMinutes() { + return GetHours() * 60 + GetMinutes(); + } + void PrintHHMMSS() { + cout << ToSring(":") << "\n"; + } + string ToSring(string seperator = "-") { + ostringstream oss; + oss << GetHours() << seperator << GetMinutes() << seperator << GetSeconds(); + return oss.str(); + } + int GetHours() { + return total_seconds / (60 * 60); + } + void SetHours(int hours) { + if (hours < 0) + hours = 0; + total_seconds += (hours - GetHours()) * 60 * 60; + + } + int GetMinutes() { + return (total_seconds % (60 * 60)) / 60; + } + void SetMinutes(int minutes) { + if (minutes < 0) + minutes = 0; + total_seconds += (minutes - GetMinutes()) * 60; + } + int GetSeconds() { + return total_seconds % 60; + } + void SetSeconds(int seconds) { + if (seconds < 0) + seconds = 0; + total_seconds += (seconds - GetSeconds()); + } +}; + + +// In previous code, all functions use directly the 3 integers +// It might be a good practice to depend on the available setters and getters +// Imagine a real Time class with 20 functions that use minutes, which now doesn't exist +// If they all use GetMinutes, no one of them will be changed +// Be careful with data members that might change or keep depending on setters/getters +// As you see, we could even provide setters & getters for variables that doesn't exist + +// Code "flexibility" is important + +int main() { + Time t(0, 0, 0); + t.SetMinutes(1); + t.SetSeconds(60); + t.SetHours(2); + cout << t.GetTotalSeconds(); + return 0; +} diff --git a/19-object-oriented-programming/05_homework_08_answer.cpp b/19-object-oriented-programming/05_homework_08_answer.cpp new file mode 100644 index 0000000..cc13349 --- /dev/null +++ b/19-object-oriented-programming/05_homework_08_answer.cpp @@ -0,0 +1,76 @@ +#include +using namespace std; + +class CarSpecs { +private: + string trim; + string engine_type; + pair horsepower; + string steering_ratio; + // and more +public: + string& GetEngineType() { + return engine_type; + } + void SetEngineType( string& engineType) { + engine_type = engineType; + } + pair GetHorsepower() { + return horsepower; + } + void SetHorsepower(pair horsepower) { + this->horsepower = horsepower; + } + string& GetSteeringRatio() { + return steering_ratio; + } + void SetSteeringRatio( string& steeringRatio) { + steering_ratio = steeringRatio; + } + string& GetTrim() { + return trim; + } + void SetTrim( string& trim) { + this->trim = trim; + } +}; + +class AutoTrader { +private: + vector current_cars_vec; +public: + void LoadDatabase() { + // Fill current_cars_vec + } + + bool search_match( CarSpecs &query_car) { + for(auto available_car : current_cars_vec) { + if(available_car.GetEngineType() != query_car.GetEngineType()) continue; + if(available_car.GetHorsepower() != query_car.GetHorsepower()) continue; + if(available_car.GetSteeringRatio() != query_car.GetSteeringRatio()) continue; + if(available_car.GetTrim() != query_car.GetTrim()) continue; + return true; + } + return false; + } +}; + +/* + +1- Above code violates encapsulation concept by forcing others to think how to compare to objects + The right way, CarSpecs provides is_equal functionality + +2- Also from code change perspective, every time we change the data members in CarSpecs (e.g. details of exterior shape) + We will have to change AutoTrader class (2 classes changed). + If CarSpecs provides is_equal functionality, other users won't need to do/care about the changes + as they are still handled + +3- On the other side, the code did not follow this nice tip: + “Don’t ask for the information you need to do the work; ask the object that has the information to do the work for you.” Allen Holub + + We asked for all the gets to do the comparison! This should be the class responsibility + */ + +int main() { + return 0; +} diff --git a/19-object-oriented-programming/05_homework_09.cpp b/19-object-oriented-programming/05_homework_09.cpp new file mode 100644 index 0000000..b064bd8 --- /dev/null +++ b/19-object-oriented-programming/05_homework_09.cpp @@ -0,0 +1,24 @@ +#include +using namespace std; + + +class A { +private: + int *x = nullptr; +public: + A() { + cout<<"A constructor\n"; + x = new int; + *x = 10; + } + ~A() { + cout<<"A destructor\n"; + } + +}; + +int main() { + A *a = new A(); + + return 0; +} diff --git a/19-object-oriented-programming/05_homework_09_answer.cpp b/19-object-oriented-programming/05_homework_09_answer.cpp new file mode 100644 index 0000000..740b661 --- /dev/null +++ b/19-object-oriented-programming/05_homework_09_answer.cpp @@ -0,0 +1,36 @@ +#include +using namespace std; + + +class A { +private: + int *x = nullptr; +public: + A() { + cout<<"A constructor\n"; + x = new int; + *x = 10; + } + ~A() { + // We need to free x as we created it + if (x != nullptr) { + delete x; + x = nullptr; + } + cout<<"A destructor\n"; + } + +}; + +int main() { + // Whoever creates a pointer is responsible for destructing it + // If it is created as member variable, we destroy it in destructor + + // Now, we created this from outside, we must delete it from outside (e.g. delete a) + // Now an interesting object, when this *a goes out of scope, what is destroyed? + // The answer is the variable a itself that points to the pointer, NOT the pointer content (object of class a) + A *a = new A(); + delete a; + + return 0; +} diff --git a/19-object-oriented-programming/06_01.cpp b/19-object-oriented-programming/06_01.cpp new file mode 100644 index 0000000..870024f --- /dev/null +++ b/19-object-oriented-programming/06_01.cpp @@ -0,0 +1,35 @@ +#include +using namespace std; + +class MyNumber { +private: + int *val1; + int val2; + +public: + MyNumber(int x = 3, int y = 5) { + val1 = new int; + *val1 = x; + val2 = y; + } + + ~MyNumber() { + //delete val1; + } + void PrintValueAndAddress() { + cout << "val1: " << *val1 << " " << val1 << "\n"; + cout << "val2: " << val2 << " " << &val2 << "\n\n"; + } +}; + +int main() { + MyNumber a; + MyNumber b(10, 20); + + a.PrintValueAndAddress(); + b.PrintValueAndAddress(); + b = a; + b.PrintValueAndAddress(); + + return 0; +} diff --git a/19-object-oriented-programming/06_02.cpp b/19-object-oriented-programming/06_02.cpp new file mode 100644 index 0000000..1a2f153 --- /dev/null +++ b/19-object-oriented-programming/06_02.cpp @@ -0,0 +1,51 @@ +#include +using namespace std; + +class MyNumber { +private: + int *val1; + int val2; + +public: + MyNumber(int x = 3, int y = 5) { + val1 = new int; + *val1 = x; + val2 = y; + } + + ~MyNumber() { + //delete val1; + } + + void PrintValueAndAddress() { + cout << "val1: " << *val1 << " " << val1 << "\n"; + cout << "val2: " << val2 << " " << &val2 << "\n\n"; + } +}; + +void fun1(MyNumber x) { +} + +MyNumber fun2() { + MyNumber e(1, 2); + return e; +} + +int main() { + MyNumber a; // normal ructor + MyNumber b(10, 20); // normal ructor + + MyNumber c(b); // copy ructor to build c + MyNumber d = b; // copy ructor to initialize in declaration + fun1(c); // copy ructor to pass object + fun2(); // copy ructor to return object + + a = b; // assignment NOT copy ructor + + a.PrintValueAndAddress(); + b.PrintValueAndAddress(); + c.PrintValueAndAddress(); + d.PrintValueAndAddress(); + + return 0; +} diff --git a/19-object-oriented-programming/06_03.cpp b/19-object-oriented-programming/06_03.cpp new file mode 100644 index 0000000..98fbc64 --- /dev/null +++ b/19-object-oriented-programming/06_03.cpp @@ -0,0 +1,41 @@ +#include +using namespace std; + +class MyNumber { +private: + int *val1; + int val2; + +public: + MyNumber(int x = 3, int y = 5) { + cout << "Normal ructor\n"; + val1 = new int; + *val1 = x; + val2 = y; + } + + MyNumber( MyNumber &another) { + cout << "Copy ructor\n"; + val1 = new int; + *val1 = *another.val1; + val2 = another.val2; + } + ~MyNumber() { + delete val1; + } + void PrintValueAndAddress() { + cout << "val1: " << *val1 << " " << val1 << "\n"; + cout << "val2: " << val2 << " " << &val2 << "\n\n"; + } +}; + + +int main() { + MyNumber a; // normal ructor + MyNumber b(a); // copy ructor + + a.PrintValueAndAddress(); + b.PrintValueAndAddress(); + + return 0; +} diff --git a/19-object-oriented-programming/06_04.cpp b/19-object-oriented-programming/06_04.cpp new file mode 100644 index 0000000..0a31d87 --- /dev/null +++ b/19-object-oriented-programming/06_04.cpp @@ -0,0 +1,53 @@ +#include +using namespace std; + +class MyNumber { +private: + int *val1; + int val2; + +public: + MyNumber(int x = 3, int y = 5) { + cout << "Normal ructor\n"; + val1 = new int; + *val1 = x; + val2 = y; + } + + MyNumber( MyNumber &another) { + cout << "Copy ructor\n"; + val1 = new int; + *val1 = *another.val1; + val2 = another.val2; + } + ~MyNumber() { + delete val1; + } + void PrintValueAndAddress() { + cout << "val1: " << *val1 << " " << val1 << "\n"; + cout << "val2: " << val2 << " " << &val2 << "\n\n"; + } +}; + + +void play1(MyNumber a) {} +void play2(MyNumber &a) {} +void play3( MyNumber &a) {} + +MyNumber play4() { + MyNumber x(1, 1); + return x; // Returned object is temporary +} + +int main() { + play1(MyNumber()); + // play2(MyNumber()); // cannot be bound to a non- reference + play3(MyNumber()); + // play2(play4()); // cannot be bound to a non- reference + + // Notice: Sometimes the copy ructor won't be called! + // Due to C++ return value optimization (RVO) + // It eliminates the temporary object created to hold a function's return value + + return 0; +} diff --git a/19-object-oriented-programming/06_homework_01_answer.txt b/19-object-oriented-programming/06_homework_01_answer.txt new file mode 100644 index 0000000..b235e79 --- /dev/null +++ b/19-object-oriented-programming/06_homework_01_answer.txt @@ -0,0 +1,17 @@ +1- As this constructor is private, extrernal users can't make objects of such a class using this constructor! + If this is the empty constructor and no further constructors, users can't create a class at all + + Why would that be benificial?! + +2- if a copy constructor is made private, objects of that class become non-copyable. + +3- Why argument to a copy constructor must be passed as a reference? + A copy constructor is called when an object is passed by value. + Copy constructor itself is a function. So if we pass an argument by value in a copy constructor, a call to copy constructor + would be made to call copy constructor ==> infinite recursion + Therefore compiler doesn’t allow parameters to be passed by value. + + Surce: geeksforgeeks + +4- https://www.geeksforgeeks.org/copy-constructor-argument-const/ + diff --git a/19-object-oriented-programming/06_homework_02_answer.txt b/19-object-oriented-programming/06_homework_02_answer.txt new file mode 100644 index 0000000..d6437b8 --- /dev/null +++ b/19-object-oriented-programming/06_homework_02_answer.txt @@ -0,0 +1,3 @@ +The first destructor to execute would delete the dynamically allocated memory, +and the other object’s ptr would point to memory that’s no longer allocated, a situation called a dangling pointer. +This would likely result in a serious runtime error (such as early program termination) when the pointer was used. diff --git a/19-object-oriented-programming/06_homework_03_answer.cpp b/19-object-oriented-programming/06_homework_03_answer.cpp new file mode 100644 index 0000000..3d37959 --- /dev/null +++ b/19-object-oriented-programming/06_homework_03_answer.cpp @@ -0,0 +1,46 @@ +#include +using namespace std; + + +class ClassA { +private: + int *val; +public: + ClassA(int v) { + val = new int; + *val = v; + } + ~ClassA() { + delete val; + val = NULL; // good practice + } + + const int* GetVal() { // adding const here prevents from wrong usage + return val; + } + + void SetVal(int* val) { + this->val = val; + } +}; + +int main() { + ClassA a1(10); + ClassA a2(20); + a2.SetVal(a1.GetVal()); + return 0; +} + +/* +The 2 objects now share same pointer. +The first destructor to execute would delete the dynamically allocated memory, +and the other object’s ptr would point to memory that’s no longer allocated, a situation called a dangling pointer. +This would likely result in a serious runtime error (such as early program termination) when the pointer was used. + + +By using const, then user can't reset it so we prevent such behaviour + +Tip: Rewiew slide Accessor & mutator: The proper way? + Careful thinking about your setters and getters + In this scenario, returning pointer can make serious problems +*/ diff --git a/19-object-oriented-programming/06_homework_04_answer.cpp b/19-object-oriented-programming/06_homework_04_answer.cpp new file mode 100644 index 0000000..8b4679c --- /dev/null +++ b/19-object-oriented-programming/06_homework_04_answer.cpp @@ -0,0 +1,62 @@ +#include +using namespace std; + +class MyVector { +private: + int *arr; + int len = 100; + +public: + MyVector(int len, int default_value = 0) { + this->len = len; + this->arr = new int[len]; + + for (int i = 0; i < len; ++i) { + this->arr[i] = default_value; + } + } + + MyVector(const MyVector & another) { + len = another.len; + this->arr = new int[len]; + + for (int i = 0; i < len; ++i) + arr[i] = another.arr[i]; + } + + ~MyVector() { + delete[] this->arr; + } + + int Get(int pos) { + if (pos < len) + return this->arr[pos]; + else { + cout<<"Invalid access\n"; + return -1; + } + + } + + void Set(int pos, int val = 0) { + if (pos < len) + this->arr[pos] = val; + else + cout<<"Invalid access\n"; + } + + int GetLen() { + return len; + } +}; + +int main() { + MyVector v(10, 12345); + MyVector v2(v); + + v2.Set(12000); + + + + return 0; +} diff --git a/19-object-oriented-programming/06_homework_05_answer.cpp b/19-object-oriented-programming/06_homework_05_answer.cpp new file mode 100644 index 0000000..d8fc1d4 --- /dev/null +++ b/19-object-oriented-programming/06_homework_05_answer.cpp @@ -0,0 +1,69 @@ +#include +using namespace std; + +class MyVector { +private: + int *arr; + int len = 100; + +public: + MyVector(int len, int default_value = 0) { + this->len = len; + this->arr = new int[len]; + + for (int i = 0; i < len; ++i) { + this->arr[i] = default_value; + } + } + + MyVector(const MyVector & another) { + len = another.len; + this->arr = new int[len]; + + for (int i = 0; i < len; ++i) + arr[i] = another.arr[i]; + } + + ~MyVector() { + delete[] this->arr; + } + + int Get(int pos) { + if (pos < len) + return this->arr[pos]; + else { + cout<<"Invalid access\n"; + return -1; + } + + } + + void Set(int pos, int val = 0) { + if (pos < len) + this->arr[pos] = val; + else + cout<<"Invalid access\n"; + } + + // Breaks Data-Hiding concept. User has access to private data and can corrupt the system + + int& GetLen() { + return len; + } +}; + +int main() { + MyVector v(10, 12345); + + cout< +using namespace std; + +#include +using namespace std; + +// Improperly declared parameter: sent parameter should be const reference: +void print1(string& s) { +} + +// Properly declared function: function has no intent to modify s: +void print2(const string& s) { +} + +string msg1() { + string x = "aa"; + return x; +} + +const string& msg2() { + return "aa"; +} + +const string& msg3() { + string x = "aa"; + return x; +} + +int main() { + string hello("Hello"); + + print1(hello); + // Next 2 lines create temporary objects. Sent parameter can't be temporary + // Recall: cannot be bound to a non-const reference + print1(string("World")); + print1("!"); + + // As parameter is const & for param: any style can be used + print2(hello); + print2(string("World")); + print2("!"); + + string a1 = msg1(); + // Returned param is temporary. Must receive with & or const & + string &a2 = msg1(); + const string &a3 = msg1(); + + // Run time error. Above function send reference to local variable that will be destroyed + string a = msg2(); + string b = msg2(); + + /* + * Here is a general guideline + * 1) Using no reference (in parameter, function return or receiving variable in the caller) + * A) No compile or run time error + * B) If the object is heavy: takes more time and memory + * + * 2) Using & saves time and memory BUT + * A) As a function parameter: if used & without const: you can't send temporary object => Compile error + * B) As a return: Never return & (or const &) for a local variable as it will be destroyed. This will cause RTE. The is the most dangerous case, as others cause compile error. + * C) You can return & to data member as it won't be destroyed before the receiving variable. But better use const & to follow OO concepts as possible + * D) As a receiving variable: You can't receive & for temporary object. Compile error + * E) As a receiving variable: You can always receive const &, even for temporary object. No problem. + */ + + return 0; +} + diff --git a/19-object-oriented-programming/07_01.cpp b/19-object-oriented-programming/07_01.cpp new file mode 100644 index 0000000..122aa5a --- /dev/null +++ b/19-object-oriented-programming/07_01.cpp @@ -0,0 +1,44 @@ +#include +using namespace std; + +class Rectangle { +private: + double width; + double height; + +public: + Rectangle(double width = 0.0, double height = 0.0) : + width(width), height(height) { + } + double ComputeArea() const { + // CE: function is cont, can't change member variables + // width = 1; + return width * height; + } + // Setters & Getters + double GetHeight() const { + return height; + } + void SetHeight(double height) { + this->height = height; + } + double GetWidth() const { + return width; + } + void SetWidth(double width) { + this->width = width; + } +}; + +int main() { + Rectangle r1(2, 3); + r1.ComputeArea(); + r1.SetWidth(10); + + const Rectangle r2(4, 5); + r2.ComputeArea(); + // CE: const object can't call non-const member function + // r2.SetWidth(10); + + return 0; +} diff --git a/19-object-oriented-programming/07_02.cpp b/19-object-oriented-programming/07_02.cpp new file mode 100644 index 0000000..2ee1caf --- /dev/null +++ b/19-object-oriented-programming/07_02.cpp @@ -0,0 +1,51 @@ +#include +using namespace std; + +class Rectangle { +private: + double width; + double height; + +public: + Rectangle(double width = 0.0, double height = 0.0) : + width(width), height(height) { + } + double ComputeArea() const { + // CE: function is cont, can't change member variables + // width = 1; + return width * height; + } + // Setters & Getters + double GetHeight() const { + return height; + } + void SetHeight(double height) { + this->height = height; + } + double GetWidth() const { + return width; + } + void SetWidth(double width) { + this->width = width; + } +}; + +int main() { + Rectangle r1(2, 3); + + const Rectangle* r2 = new Rectangle (4, 5); + // r3->SetWidth(10.2); // Can't, const data + r2 = & r1; // Ok, not const pointer + + Rectangle* const r3 = new Rectangle (1, 2); + r3->SetWidth(10.2); // Ok, non-const data + // r3 = & r1; // Can't, const pointer + + const Rectangle* const r4 = new Rectangle (1, 2); + //r4->SetWidth(10.2); // Can't, const data + //r4 = & r1; // Can't, const pointer + + const Rectangle* const r5 = &r1; // The opposite is not ok + + return 0; +} diff --git a/19-object-oriented-programming/07_03.cpp b/19-object-oriented-programming/07_03.cpp new file mode 100644 index 0000000..d225908 --- /dev/null +++ b/19-object-oriented-programming/07_03.cpp @@ -0,0 +1,37 @@ +#include +using namespace std; + +class Rectangle { +private: + double width; + double height; + const int tmp1 = 10; // initialized + const int tmp2; + +public: + Rectangle(double width = 0.0, double height = 0.0) : + width(width), height(height), tmp2(6) { + // tmp2 = 6; can't. must use initializer list + } + double ComputeArea() const { + return width * height; + } + // Setters & Getters + double GetHeight() const { + return height; + } + void SetHeight(double height) { + this->height = height; + } + double GetWidth() const { + return width; + } + void SetWidth(double width) { + this->width = width; + } +}; + +int main() { + + return 0; +} diff --git a/19-object-oriented-programming/07_04.cpp b/19-object-oriented-programming/07_04.cpp new file mode 100644 index 0000000..64cc561 --- /dev/null +++ b/19-object-oriented-programming/07_04.cpp @@ -0,0 +1,19 @@ +#include +using namespace std; + +void hello() { + int i1 = 0; + static int i2 = 0; + + cout< +using namespace std; + +class Test { +public: + static int x; // Declare: shared among all objects +}; + +int Test::x = 0; // Define outside + +void f() { + Test::x += 10; // Same x +} + +int main() { + Test::x += 1; // Access + + f(); + + cout << Test::x << "\n"; + + return 0; +} diff --git a/19-object-oriented-programming/07_06.cpp b/19-object-oriented-programming/07_06.cpp new file mode 100644 index 0000000..f1681a8 --- /dev/null +++ b/19-object-oriented-programming/07_06.cpp @@ -0,0 +1,21 @@ +#include +using namespace std; + +class Test { +public: + int x; + static int factorial(int n) { + //x = 10; // can't access member data + + int res = 1; + for (int i = 1; i <= n; ++i) + res *= i; + return res; + } +}; + +int main() { + cout< +using namespace std; + +class Employee { +private: + string name; + static int employees_count; + +public: + Employee(string name) : + name(name) { + ++Employee::employees_count; + } + static int GetEmployeeCount() { + return Employee::employees_count; + } +}; + +int Employee::employees_count = 0; + +int main() { + Employee most("Mostafa"); + Employee("Mona"); + static Employee belal("Belal"); + + cout << Employee::GetEmployeeCount(); // 3 + + return 0; +} diff --git a/19-object-oriented-programming/07_09.cpp b/19-object-oriented-programming/07_09.cpp new file mode 100644 index 0000000..015c84a --- /dev/null +++ b/19-object-oriented-programming/07_09.cpp @@ -0,0 +1,33 @@ +#include +using namespace std; + +class A { +}; + +class B { + +public: + int f; + B(int a, int b) { + f = 10; + } +}; + +class C { +public: + static vector v; + static int arr[10]; + static A a; + static B b; +}; + +vector C::v = vector(20); +int C::arr[10]; +A C::a; +B C::b = B(1, 2); + +int main() { + cout< +using namespace std; + +class A { +private: + int a1_private = 10; + int a2_private = 20; + + void HiddenA() { + cout << "I am hidden\n"; + } +public: + // Friend Class: Access its private section + friend class B; +}; + +class B { +public: + void AcessA1(A& x) { + cout << x.a1_private << "\n"; + } + void AcessA2(A& x) { + cout << x.a2_private << "\n"; + x.HiddenA(); + } +}; + +int main() { + A a; + B b; + b.AcessA1(a); + b.AcessA2(a); + return 0; +} diff --git a/19-object-oriented-programming/07_11.cpp b/19-object-oriented-programming/07_11.cpp new file mode 100644 index 0000000..e267aae --- /dev/null +++ b/19-object-oriented-programming/07_11.cpp @@ -0,0 +1,41 @@ +#include +using namespace std; + +class A; // Define early to break cycle + +class B { +public: + void AcessA1(A& x); + void AcessA2(A& x); +}; + +class A { +private: + int a1_private = 10; + int a2_private = 20; + + void HiddenA() { + cout << "I am hidden\n"; + } +public: + // Friend function only access my private data + friend void B::AcessA1(A& x); +}; + +void B::AcessA1(A& x) { + cout << x.a1_private << "\n"; + x.HiddenA(); +} +void B::AcessA2(A& x) { + // Syntax error: can't access these private data + //cout << x.a2_private << "\n"; + //x.HiddenA(); +} + +int main() { + A a; + B b; + b.AcessA1(a); + b.AcessA2(a); + return 0; +} diff --git a/19-object-oriented-programming/07_12.cpp b/19-object-oriented-programming/07_12.cpp new file mode 100644 index 0000000..a59a27d --- /dev/null +++ b/19-object-oriented-programming/07_12.cpp @@ -0,0 +1,28 @@ +#include +using namespace std; + +class A { +private: + int a1_private = 10; + int a2_private = 20; + + void HiddenA() { + cout << "I am hidden\n"; + } +public: + // global friend function + friend void PrintA(A& x); +}; + +void PrintA(A& x) { + cout << x.a1_private << "\n"; + cout << x.a2_private << "\n"; + x.HiddenA(); +} + +int main() { + A a; + PrintA(a); + + return 0; +} diff --git a/19-object-oriented-programming/07_homework_01_answer.txt b/19-object-oriented-programming/07_homework_01_answer.txt new file mode 100644 index 0000000..5a7658d --- /dev/null +++ b/19-object-oriented-programming/07_homework_01_answer.txt @@ -0,0 +1,6 @@ +In both cases as it doesn't make sense. A static object is shared among all objects and doesn't have its own data members + So this invalidate the use of this pointer + Also using const means no changes for member data, but changes to what?! + +It is useful to think about the language features: + why does it allow something? why not? diff --git a/19-object-oriented-programming/07_homework_02_answer.cpp b/19-object-oriented-programming/07_homework_02_answer.cpp new file mode 100644 index 0000000..8aecf8d --- /dev/null +++ b/19-object-oriented-programming/07_homework_02_answer.cpp @@ -0,0 +1,55 @@ +#include +using namespace std; + + +class Employee { +private: + string name; + +public: + Employee(string name) : + name(name) { + cout<<"Constructor: "< +using namespace std; + +class ConfigurationManger { +private: + string configuration_path; + vector servers_ips; + string aws_service_url; + // Other heavy data + bool is_loaded = false; +public: + ConfigurationManger(string configuration_path) : + configuration_path(configuration_path) { + } + void Load() { + if (is_loaded) + return; + // some heavy load + cout << "Lazy loading\n"; + servers_ips.push_back("10.20.30.40"); + servers_ips.push_back("10.20.30.41"); + servers_ips.push_back("10.20.30.42"); + aws_service_url = "https://dynamodb.us-west-2.amazonaws.com"; + is_loaded = true; + } + string GetAwsServiceUrl() { + Load(); + return aws_service_url; + } +}; + +void f1() { + ConfigurationManger mgr("/home/moustafa/conf_info.txt"); + cout< +using namespace std; + +/* + + - Saying that we need only ONE instance from this class, may trigger what? + - Static object: Shared object among all instances + - Now let's create a static instance to be shared + - But still users can create objects! + - The trick is to make the class constructor private! + - This way no one can create objects! + - But???? Ok, give him a function to return your static object + + - You just learned Singleton Design Pattern :) + + */ + +class ConfigurationManger { +private: + string configuration_path; + vector servers_ips; + string aws_service_url; + // Other heavy data + bool is_loaded = false; + + // Private constructor! No one can create instances of this time (or even default one) + ConfigurationManger(string configuration_path) : + configuration_path(configuration_path) { + } + + // Our shared instance + static ConfigurationManger* conf_mgr; + +public: + + // Give public method to return the static (shared) instance + static ConfigurationManger *GetInstance(const std::string& value) { + // Be careful: initialize once + if (conf_mgr == nullptr) { + cout << "Creating a new ConfigurationManger\n"; + conf_mgr = new ConfigurationManger(value); + } + return conf_mgr; + } + + void Load() { + if (is_loaded) + return; + // some heavy load + cout << "Lazy loading\n"; // what is lazy loading? Google + servers_ips.push_back("10.20.30.40"); + servers_ips.push_back("10.20.30.41"); + servers_ips.push_back("10.20.30.42"); + aws_service_url = "https://dynamodb.us-west-2.amazonaws.com"; // what is Amazon AWS? + is_loaded = true; + } + + string GetAwsServiceUrl() { // why not const? + Load(); + return aws_service_url; + } + ~ConfigurationManger() { + // Note, you shouldn't try to destroy the conf_mgr here!!! + // The first object destroy it but others still use it (or will reload)! + + //FreeInstance(); // if you uncommented = infinite loop. WHY? Answer is belo very bottom + + // Quote: Don’t create problems to solve a problem + } + static void FreeInstance() { + if (ConfigurationManger::conf_mgr != nullptr) { + cout << "Free the instance\n"; + delete ConfigurationManger::conf_mgr; + ConfigurationManger::conf_mgr = nullptr; + } else + cout << "The instance freed already\n"; + } +}; + +ConfigurationManger* ConfigurationManger::conf_mgr = nullptr; + +void f1() { + ConfigurationManger* mgr = ConfigurationManger::GetInstance("/home/moustafa/conf_info.txt"); + cout << mgr->GetAwsServiceUrl() << "\n"; +} + +void f2() { + ConfigurationManger* mgr = ConfigurationManger::GetInstance("/home/moustafa/conf_info.txt"); + cout << mgr->GetAwsServiceUrl() << "\n"; +} + +int main() { + f1(); + f2(); + + // If we forgot to free, it will be memory leak! + // We need more elegant solutions! + ConfigurationManger::FreeInstance(); + return 0; +} + + + + + + + + + + + + + + + + + +// Because destrctor calls destrctor calls destrctor to infinity +// How +// Scope of an object ended, so it calls ~ConfigurationManger(), which calls FreeInstance() +// FreeInstance does: delete ConfigurationManger::conf_mgr; => which is calling the destructor! +// Which repeat the same! +// Hell :) diff --git a/19-object-oriented-programming/07_homework_04.cpp b/19-object-oriented-programming/07_homework_04.cpp new file mode 100644 index 0000000..71c598b --- /dev/null +++ b/19-object-oriented-programming/07_homework_04.cpp @@ -0,0 +1,79 @@ +#include +using namespace std; + +int statistics_total_prints = 0; + +class StudentGradesInfo { +private: + string student_id; + vector grades; + vector courses_names; +public: + + StudentGradesInfo() { + assert(false); + } + + StudentGradesInfo(string name_, string student_id_) { + student_id = student_id_; + } + + int AdjustGrade(int grade) { + if (grade < 0) + return grade; + if (grade > 100) + return 100; + return grade; + } + bool AddGrade(double grade, string course_name) { + grade = AdjustGrade(grade); + grades.push_back(grade); + + for (int i = 0; i < (int) courses_names.size(); ++i) + if(course_name == courses_names[i]) + return false; // already added + courses_names.push_back(course_name); + return true; + } + void PrintAllCourses() { + ++statistics_total_prints; + + cout << "Grades for student: " << student_id << "\n"; + for (int i = 0; i < (int) grades.size(); ++i) + cout << "\t" << courses_names[i] << " = " << grades[i] << "\n"; + } + pair GetCourseGradeInfo(int pos) { + if (pos < 0 || pos >= (int) grades.size()) + return make_pair("", -1); + return make_pair(courses_names[pos], grades[pos]); + } + string GetStudentId() { + return student_id; + } + int GetTotalCoursesCount() { + return grades.size(); + } + // Use GetTotalCoursesCount for naming consistency + pair get_total_gradesSum() { + double sum = 0, total = 0; + for (int i = 0; i < (int) grades.size(); ++i) + sum += grades[i], total += 100; + return make_pair(sum, total); + } +}; + +int main() { + StudentGradesInfo st1("Mostafa", "S000123"); + st1.AddGrade(70, "Math"); + st1.AddGrade(70, "programming 1"); + st1.AddGrade(85, "programming 2"); + + st1.PrintAllCourses(); + + pair p = st1.get_total_gradesSum(); + cout< +using namespace std; + +class StudentGradesInfo { +private: + string student_id; + vector grades; + vector courses_names; + const int MAX_GRADE_PER_COURSE = 100.0; + + // It seems developer wants to keep track of how many times this function is called + // Proper way to maintain a static counter inside the class + + // Side note: in real life, we applications keep track of what users do and analyze it + // This allows discovering what users do/don't so that we improve their experience + static int statistics_total_prints; + + // Several issues in this function + // 1- It is public, although for internal usage! Move to private + // 2- It doesn't change class variables! Make it const. Another way is just to change it to void AdjustGrade(double & grade) + // 3- It uses a magic number: + // A magic number is a numeric literal (for example, 8080 , 2048 ) that is used in the middle of a block of code without explanation. + // It is considered good practice to avoid magic numbers by assigning the numbers to named constants and using the named constants instead + // 4- Also: if requirement changed 100 to say 50, we will do a lot of code changes! + // 5: bug, it should be double not int (in parameter and return) + // 6: bug in if (grade < 0) => should return 0 + double AdjustGrade(double grade) const { + if (grade < 0) + return 0; + if (grade > MAX_GRADE_PER_COURSE) + return MAX_GRADE_PER_COURSE; + return grade; + } +public: + + // It seems developer wants to prevent users from using empty constructor + // Just asserting will break the program + // Removing this constructor will disallow the default constructor! + //StudentGradesInfo() { + // assert(false); + //} + + // Seems string name_ is not used! Don't add what is not useful! + // Use initializer list as possible! + StudentGradesInfo(string student_id) : + student_id(student_id) { + } + + bool AddGrade(double grade, const string &course_name) { + grade = AdjustGrade(grade); + + // Very big bug. A lot of run time errors will happen! + // needed to move to end of function + //grades.push_back(grade); + + for (int i = 0; i < (int) courses_names.size(); ++i) + if (course_name == courses_names[i]) + return false; // already added + + grades.push_back(grade); + courses_names.push_back(course_name); + + return true; + } + + // Make const! + // Use variables names that are understandable! + // Good function and variable names are key in clear code + void PrintAllCourses() const { + ++statistics_total_prints; + + // If there is a getter/setter for a data member, use it + cout << "Grades for student: " << GetStudentId() << "\n"; + for (int course_idx = 0; course_idx < (int) courses_names.size(); ++course_idx) + cout << "\t" << courses_names[course_idx] << " = " << grades[course_idx] << "\n"; + } + + // const! + bool GetCourseGradeInfo(int pos, pair &result) const{ + if (pos < 0 || pos >= (int) grades.size()) { + result = make_pair("", -1); + return false; + } + result = make_pair(courses_names[pos], grades[pos]); + return true; + } + + // const! + string GetStudentId() const { + return student_id; + } + + // const! + int GetTotalCoursesCount() const { + return grades.size(); + } + + // const! + pair GetTotalGradesSum() const { + double sum = 0, total = 0; + for (int grade_idx = 0; grade_idx < (int) grades.size(); ++grade_idx) + sum += grades[grade_idx], total += MAX_GRADE_PER_COURSE; + return make_pair(sum, total); + } +}; + +int StudentGradesInfo::statistics_total_prints = 0; + +int main() { + StudentGradesInfo st1("S000123"); + st1.AddGrade(70, "Math"); + st1.AddGrade(70, "programming 1"); + st1.AddGrade(85, "programming 2"); + + st1.PrintAllCourses(); + + pair p = st1.GetTotalGradesSum(); + cout << p.first << "/" << p.second << "\n"; + + cout << "Bye\n"; + + return 0; +} diff --git a/19-object-oriented-programming/07_homework_05_answer.cpp b/19-object-oriented-programming/07_homework_05_answer.cpp new file mode 100644 index 0000000..3ec16ac --- /dev/null +++ b/19-object-oriented-programming/07_homework_05_answer.cpp @@ -0,0 +1,183 @@ +#include +using namespace std; + +class StudentGradesInfo { +private: + string student_id; + vector grades; + vector courses_names; + const int MAX_GRADE_PER_COURSE = 100.0; + + static int statistics_total_prints; + + double AdjustGrade(double grade) const { + if (grade < 0) + return 0; + if (grade > MAX_GRADE_PER_COURSE) + return MAX_GRADE_PER_COURSE; + return grade; + } +public: + + StudentGradesInfo(string student_id) : + student_id(student_id) { + } + + bool AddGrade(double grade, const string &course_name) { + grade = AdjustGrade(grade); + + for (int i = 0; i < (int) courses_names.size(); ++i) + if (course_name == courses_names[i]) + return false; // already added + + grades.push_back(grade); + courses_names.push_back(course_name); + return true; + } + void PrintAllCourses() const { + ++statistics_total_prints; + + cout << "Grades for student: " << GetStudentId() << "\n"; + for (int course_idx = 0; course_idx < (int) courses_names.size(); ++course_idx) + cout << "\t" << courses_names[course_idx] << " = " << grades[course_idx] << "\n"; + } + bool GetCourseGradeInfo(int pos, pair &result) const{ + if (pos < 0 || pos >= (int) grades.size()) { + result = make_pair("", -1); + return false; + } + result = make_pair(courses_names[pos], grades[pos]); + return true; + } + + string GetStudentId() const { + return student_id; + } + + int GetTotalCoursesCount() const { + return grades.size(); + } + + pair GetTotalGradesSum() const { + double sum = 0, total = 0; + for (int grade_idx = 0; grade_idx < (int) grades.size(); ++grade_idx) + sum += grades[grade_idx], total += MAX_GRADE_PER_COURSE; + return make_pair(sum, total); + } +}; + +int StudentGradesInfo::statistics_total_prints = 0; + + +class StudentGradesInfoBlaxBoxTester { +private: + const int MAX_GRADE_PER_COURSE = 100.0; +public: + + void Test_TotalCoursesCount() { + cout << __func__ << "\n"; // print fuction name + StudentGradesInfo st1("S000123"); + assert(st1.GetTotalCoursesCount() == 0); + st1.AddGrade(70, "Math"); + st1.AddGrade(70, "programming 1"); + st1.AddGrade(85, "programming 2"); + assert(st1.GetTotalCoursesCount() == 3); + + st1.AddGrade(75, "programming 2"); + st1.AddGrade(65, "programming 2"); + st1.AddGrade(95, "programming 2"); + assert(st1.GetTotalCoursesCount() == 3); + + assert(st1.GetStudentId() == "S000123"); + + } + + void Test_TotalGradesSum() { + cout << __func__ << "\n"; + pair p; + + StudentGradesInfo st1("S000123"); + p = st1.GetTotalGradesSum(); + assert(p.first == 0); + assert(p.second == 0); + + st1.AddGrade(200, "Math"); + p = st1.GetTotalGradesSum(); + assert(p.first == MAX_GRADE_PER_COURSE); + assert(p.second == MAX_GRADE_PER_COURSE); + + st1.AddGrade(70, "programming 1"); + p = st1.GetTotalGradesSum(); + assert(p.first == 70 + MAX_GRADE_PER_COURSE); + assert(p.second == 2 * MAX_GRADE_PER_COURSE); + + // If readded, make sure not updated + st1.AddGrade(60, "programming 1"); // try lower + p = st1.GetTotalGradesSum(); + assert(p.first == 70 + MAX_GRADE_PER_COURSE); + assert(p.second == 2 * MAX_GRADE_PER_COURSE); + + // If readded, make sure not updated + st1.AddGrade(80, "programming 1"); // try bigger + p = st1.GetTotalGradesSum(); + assert(p.first == 70 + MAX_GRADE_PER_COURSE); + assert(p.second == 2 * MAX_GRADE_PER_COURSE); + + st1.AddGrade(85, "programming 2"); + p = st1.GetTotalGradesSum(); + assert(p.first == 85 + 70 + MAX_GRADE_PER_COURSE); + assert(p.second == 3 * MAX_GRADE_PER_COURSE); + + if (false) { + // This will fail. We should handle the code to not be case sensetive! + st1.AddGrade(85, "PROGramming 2"); + p = st1.GetTotalGradesSum(); + assert(p.first == 85 + 70 + MAX_GRADE_PER_COURSE); + assert(p.second == 3 * MAX_GRADE_PER_COURSE); + } + + } + + void Test_GetCourseGradeInfo() { + cout << __func__ << "\n"; + StudentGradesInfo st1("S000123"); + assert(st1.GetTotalCoursesCount() == 0); + st1.AddGrade(200, "Math"); + st1.AddGrade(70, "programming 1"); + + pair result; + assert(st1.GetCourseGradeInfo(st1.GetTotalCoursesCount(), result) == false); + assert(st1.GetCourseGradeInfo(-5, result) == false); + + st1.GetCourseGradeInfo(0, result); + assert(result.first == "Math"); + assert(result.second == MAX_GRADE_PER_COURSE); + + st1.GetCourseGradeInfo(1, result); + assert(result.first == "programming 1"); + assert(result.second == 70); + } + + void Test_PrintAllCourses() { + cout << __func__ << "\n"; + // This function is writing to console! How to test? + // 1) use Freopen to direct output to file + // 2) read file content + // 3) compare to what you expect! + } + + void TestAll() { + Test_TotalCoursesCount(); + Test_TotalGradesSum(); + Test_GetCourseGradeInfo(); + Test_PrintAllCourses(); + + cout<<"Black box: Passed all unit tests\n"; + } +}; + +int main() { + StudentGradesInfoBlaxBoxTester().TestAll(); + + return 0; +} diff --git a/19-object-oriented-programming/07_homework_06_answer.cpp b/19-object-oriented-programming/07_homework_06_answer.cpp new file mode 100644 index 0000000..afeaffc --- /dev/null +++ b/19-object-oriented-programming/07_homework_06_answer.cpp @@ -0,0 +1,251 @@ +#include +using namespace std; + +class StudentGradesInfo { +private: + string student_id; + vector grades; + vector courses_names; + const int MAX_GRADE_PER_COURSE = 100.0; + + friend class StudentGradesInfoWhiteBoxTester; // as a friend + + static int statistics_total_prints; + + double AdjustGrade(double grade) const { + if (grade < 0) + return 0; + if (grade > MAX_GRADE_PER_COURSE) + return MAX_GRADE_PER_COURSE; + return grade; + } +public: + + StudentGradesInfo(string student_id) : + student_id(student_id) { + } + + bool AddGrade(double grade, const string &course_name) { + grade = AdjustGrade(grade); + + for (int i = 0; i < (int) courses_names.size(); ++i) + if (course_name == courses_names[i]) + return false; // already added + + grades.push_back(grade); + courses_names.push_back(course_name); + return true; + } + void PrintAllCourses() const { + ++statistics_total_prints; + + cout << "Grades for student: " << GetStudentId() << "\n"; + for (int course_idx = 0; course_idx < (int) courses_names.size(); ++course_idx) + cout << "\t" << courses_names[course_idx] << " = " << grades[course_idx] << "\n"; + } + bool GetCourseGradeInfo(int pos, pair &result) { + if (pos < 0 || pos >= (int) grades.size()) { + result = make_pair("", -1); + return false; + } + result = make_pair(courses_names[pos], grades[pos]); + return true; + } + + string GetStudentId() const { + return student_id; + } + + int GetTotalCoursesCount() const { + return grades.size(); + } + + pair GetTotalGradesSum() const { + double sum = 0, total = 0; + for (int grade_idx = 0; grade_idx < (int) grades.size(); ++grade_idx) + sum += grades[grade_idx], total += MAX_GRADE_PER_COURSE; + return make_pair(sum, total); + } +}; + +int StudentGradesInfo::statistics_total_prints = 0; + + +//////////////////////////// + +class StudentGradesInfoBlaxBoxTester { +private: + const static int MAX_GRADE_PER_COURSE = 100.0; +public: + + void static Test_TotalCoursesCount() { + cout << __func__ << "\n"; // print fuction name + StudentGradesInfo st1("S000123"); + assert(st1.GetTotalCoursesCount() == 0); + st1.AddGrade(70, "Math"); + st1.AddGrade(70, "programming 1"); + st1.AddGrade(85, "programming 2"); + assert(st1.GetTotalCoursesCount() == 3); + + st1.AddGrade(75, "programming 2"); + st1.AddGrade(65, "programming 2"); + st1.AddGrade(95, "programming 2"); + assert(st1.GetTotalCoursesCount() == 3); + + assert(st1.GetStudentId() == "S000123"); + + } + + void static Test_TotalGradesSum() { + cout << __func__ << "\n"; + pair p; + + StudentGradesInfo st1("S000123"); + p = st1.GetTotalGradesSum(); + assert(p.first == 0); + assert(p.second == 0); + + st1.AddGrade(200, "Math"); + p = st1.GetTotalGradesSum(); + assert(p.first == MAX_GRADE_PER_COURSE); + assert(p.second == MAX_GRADE_PER_COURSE); + + st1.AddGrade(70, "programming 1"); + p = st1.GetTotalGradesSum(); + assert(p.first == 70 + MAX_GRADE_PER_COURSE); + assert(p.second == 2 * MAX_GRADE_PER_COURSE); + + // If readded, make sure not updated + st1.AddGrade(60, "programming 1"); // try lower + p = st1.GetTotalGradesSum(); + assert(p.first == 70 + MAX_GRADE_PER_COURSE); + assert(p.second == 2 * MAX_GRADE_PER_COURSE); + + // If readded, make sure not updated + st1.AddGrade(80, "programming 1"); // try bigger + p = st1.GetTotalGradesSum(); + assert(p.first == 70 + MAX_GRADE_PER_COURSE); + assert(p.second == 2 * MAX_GRADE_PER_COURSE); + + st1.AddGrade(85, "programming 2"); + p = st1.GetTotalGradesSum(); + assert(p.first == 85 + 70 + MAX_GRADE_PER_COURSE); + assert(p.second == 3 * MAX_GRADE_PER_COURSE); + + if (false) { + // This will fail. We should handle the code to not be case sensetive! + st1.AddGrade(85, "PROGramming 2"); + p = st1.GetTotalGradesSum(); + assert(p.first == 85 + 70 + MAX_GRADE_PER_COURSE); + assert(p.second == 3 * MAX_GRADE_PER_COURSE); + } + + } + + void static Test_GetCourseGradeInfo() { + cout << __func__ << "\n"; + StudentGradesInfo st1("S000123"); + assert(st1.GetTotalCoursesCount() == 0); + st1.AddGrade(200, "Math"); + st1.AddGrade(70, "programming 1"); + + pair result; + assert(st1.GetCourseGradeInfo(st1.GetTotalCoursesCount(), result) == false); + assert(st1.GetCourseGradeInfo(-5, result) == false); + + st1.GetCourseGradeInfo(0, result); + assert(result.first == "Math"); + assert(result.second == MAX_GRADE_PER_COURSE); + + st1.GetCourseGradeInfo(1, result); + assert(result.first == "programming 1"); + assert(result.second == 70); + } + + void static Test_PrintAllCourses() { + cout << __func__ << "\n"; + // This function is writing to console! How to test? + // 1) use Freopen to direct output to file + // 2) read file content + // 3) compare to what you expect! + } + + void static TestAll() { + Test_TotalCoursesCount(); + Test_TotalGradesSum(); + Test_GetCourseGradeInfo(); + Test_PrintAllCourses(); + + cout<<"Black box: Passed all unit tests\n"; + } +}; +////////////////////////////////////////////// + +// One bad issue in white testing, it is very "coupled" with the class +// Any change in above code may change here too! +class StudentGradesInfoWhiteBoxTester { +private: + const static int MAX_GRADE_PER_COURSE = 100.0; +public: + + void static Test_AdjustGrade() { + cout << __func__ << "\n"; + + StudentGradesInfo st1("S000123"); + assert(st1.AdjustGrade(50.1) == 50.1); + assert(st1.AdjustGrade(-200) == 0); + assert(st1.AdjustGrade(200) == 100); + assert(st1.AdjustGrade(70 == 70)); // can spot coding bug? + } + + void static Test_AddGrade() { + cout << __func__ << "\n"; + + StudentGradesInfo st1("S000123"); + + st1.AddGrade(200, "Math"); + assert(st1.courses_names.size() == st1.grades.size() && st1.courses_names.size() == 1); + + st1.AddGrade(70, "programming 1"); + assert(st1.courses_names.size() == st1.grades.size() && st1.courses_names.size() == 2); + + st1.AddGrade(60, "programming 1"); + assert(st1.courses_names.size() == st1.grades.size() && st1.courses_names.size() == 2); + assert(st1.grades.back() == 70); // not updated + assert(st1.courses_names.back() == "programming 1"); + } + + void static Test_statistics_total_prints() { + cout << __func__ << "\n"; + + StudentGradesInfo st1("S000123"); + StudentGradesInfo st2("S300123"); + + assert(StudentGradesInfo::statistics_total_prints == 0); + st1.PrintAllCourses(); + assert(StudentGradesInfo::statistics_total_prints == 1); + + st1.AddGrade(70, "programming 1"); + st1.PrintAllCourses(); + assert(StudentGradesInfo::statistics_total_prints == 2); + st2.PrintAllCourses(); + assert(StudentGradesInfo::statistics_total_prints == 3); + } + // And so on + + void static TestAll() { + StudentGradesInfoBlaxBoxTester::TestAll(); + + Test_AdjustGrade(); + Test_AddGrade(); + Test_statistics_total_prints(); + + cout<<"White box: Passed all unit tests\n"; + } +}; + +int main() { + StudentGradesInfoWhiteBoxTester::TestAll(); + + return 0; +} diff --git a/19-object-oriented-programming/07_homework_07.cpp b/19-object-oriented-programming/07_homework_07.cpp new file mode 100644 index 0000000..750f94d --- /dev/null +++ b/19-object-oriented-programming/07_homework_07.cpp @@ -0,0 +1,107 @@ +#include +using namespace std; + +class StudentGradesInfo { +private: + string student_id; + vector grades; + vector courses_names; + const int MAX_GRADE_PER_COURSE = 100.0; + + static int statistics_total_prints; + + double AdjustGrade(double grade) const { + if (grade < 0) + return 0; + if (grade > MAX_GRADE_PER_COURSE) + return MAX_GRADE_PER_COURSE; + return grade; + } +public: + + StudentGradesInfo(string student_id) : + student_id(student_id) { + } + + bool AddGrade(double grade, const string &course_name) { + grade = AdjustGrade(grade); + + for (int i = 0; i < (int) courses_names.size(); ++i) + if (course_name == courses_names[i]) + return false; // already added + + grades.push_back(grade); + courses_names.push_back(course_name); + return true; + } + void PrintAllCourses() const { + ++statistics_total_prints; + + cout << "Grades for student: " << GetStudentId() << "\n"; + for (int course_idx = 0; course_idx < (int) courses_names.size(); ++course_idx) + cout << "\t" << courses_names[course_idx] << " = " << grades[course_idx] << "\n"; + } + bool GetCourseGradeInfo(int pos, pair &result) const { + if (pos < 0 || pos >= (int) grades.size()) { + result = make_pair("", -1); + return false; + } + result = make_pair(courses_names[pos], grades[pos]); + return true; + } + + string GetStudentId() const { + return student_id; + } + + int GetTotalCoursesCount() const { + return grades.size(); + } + + pair GetTotalGradesSum() const { + double sum = 0, total = 0; + for (int grade_idx = 0; grade_idx < (int) grades.size(); ++grade_idx) + sum += grades[grade_idx], total += MAX_GRADE_PER_COURSE; + return make_pair(sum, total); + } +}; + +int StudentGradesInfo::statistics_total_prints = 0; + +class StudentGradesInfoPrinter { + //Your TODO +private: + +public: + +}; + +int main() { + StudentGradesInfo st1("S000123"); + StudentGradesInfoPrinter printer(st1); + + st1.AddGrade(50, "Math"); + st1.AddGrade(60, "programming 1"); + + int limit = 3; + cout << "Printing top " << limit << " Grades, if available\n"; + while (limit-- && printer.HasNext()) { + pair result = printer.GetNext(); + + cout << "\t" << result.first << " = " << result.second << "\n"; + } + + st1.AddGrade(70, "Algorithms"); + st1.AddGrade(67, "programming 2"); + + printer.ResetIterator(); + limit = 3; + cout << "\nPrinting top " << limit << " Grades, if available\n"; + while (limit-- && printer.HasNext()) { + pair result = printer.GetNext(); + + cout << "\t" << result.first << " = " << result.second << "\n"; + } + + return 0; +} diff --git a/19-object-oriented-programming/07_homework_07_answer.cpp b/19-object-oriented-programming/07_homework_07_answer.cpp new file mode 100644 index 0000000..e7a6d15 --- /dev/null +++ b/19-object-oriented-programming/07_homework_07_answer.cpp @@ -0,0 +1,142 @@ +#include +using namespace std; + +class StudentGradesInfo { +private: + string student_id; + vector grades; + vector courses_names; + const int MAX_GRADE_PER_COURSE = 100.0; + + static int statistics_total_prints; + + double AdjustGrade(double grade) const { + if (grade < 0) + return 0; + if (grade > MAX_GRADE_PER_COURSE) + return MAX_GRADE_PER_COURSE; + return grade; + } +public: + + StudentGradesInfo(string student_id) : + student_id(student_id) { + } + + bool AddGrade(double grade, const string &course_name) { + grade = AdjustGrade(grade); + + for (int i = 0; i < (int) courses_names.size(); ++i) + if (course_name == courses_names[i]) + return false; // already added + + grades.push_back(grade); + courses_names.push_back(course_name); + return true; + } + void PrintAllCourses() const { + ++statistics_total_prints; + + cout << "Grades for student: " << GetStudentId() << "\n"; + for (int course_idx = 0; course_idx < (int) courses_names.size(); ++course_idx) + cout << "\t" << courses_names[course_idx] << " = " << grades[course_idx] << "\n"; + } + bool GetCourseGradeInfo(int pos, pair &result) const { + if (pos < 0 || pos >= (int) grades.size()) { + result = make_pair("", -1); + return false; + } + result = make_pair(courses_names[pos], grades[pos]); + return true; + } + + string GetStudentId() const { + return student_id; + } + + int GetTotalCoursesCount() const { + return grades.size(); + } + + pair GetTotalGradesSum() const { + double sum = 0, total = 0; + for (int grade_idx = 0; grade_idx < (int) grades.size(); ++grade_idx) + sum += grades[grade_idx], total += MAX_GRADE_PER_COURSE; + return make_pair(sum, total); + } +}; + +int StudentGradesInfo::statistics_total_prints = 0; + +class StudentGradesInfoPrinter { +private: + const StudentGradesInfo & student_info; + int cur_course_pos = 0; + +public: + // Make it object by reference to feel updates. Const to never change its content as printer + StudentGradesInfoPrinter(const StudentGradesInfo & student_info) : + student_info(student_info) { + } + + void ResetIterator() { + cur_course_pos = 0; // from scratch + } + + bool HasNext() const { + // just make sure still smaller position + return cur_course_pos < student_info.GetTotalCoursesCount(); + } + + pair GetNext() { + // return next item + pair result; + student_info.GetCourseGradeInfo(cur_course_pos++, result); + return result; + } +}; + +/* + +You just learned 2 things: + +1- Open–closed principle +"Software entities ... should be open for extension, but closed for modification." +We managed to extend the functionality of the class to ore controlled printing. We did not need to change original code + +2- Iterator Design Pattern +- HasNext / GetNext is a general strategy to allow iterating on something +- STL has iterators on several containers + + + */ + +int main() { + StudentGradesInfo st1("S000123"); + StudentGradesInfoPrinter printer(st1); + + st1.AddGrade(50, "Math"); + st1.AddGrade(60, "programming 1"); + + int limit = 3; + cout << "Printing top " << limit << " Grades, if available\n"; + while (limit-- && printer.HasNext()) { + pair result = printer.GetNext(); + + cout << "\t" << result.first << " = " << result.second << "\n"; + } + + st1.AddGrade(70, "Algorithms"); + st1.AddGrade(67, "programming 2"); + + printer.ResetIterator(); + limit = 3; + cout << "\nPrinting top " << limit << " Grades, if available\n"; + while (limit-- && printer.HasNext()) { + pair result = printer.GetNext(); + + cout << "\t" << result.first << " = " << result.second << "\n"; + } + + return 0; +} diff --git a/19-object-oriented-programming/07_homework_08.cpp b/19-object-oriented-programming/07_homework_08.cpp new file mode 100644 index 0000000..65b870d --- /dev/null +++ b/19-object-oriented-programming/07_homework_08.cpp @@ -0,0 +1,120 @@ +#include +using namespace std; + +class StudentGradesInfo { +private: + string student_id; + vector grades; + vector courses_names; + const int MAX_GRADE_PER_COURSE = 100.0; + + friend class StudentGradesInfoWhiteBoxTester; // as a friend + + static int statistics_total_prints; + + double AdjustGrade(double grade) const { + if (grade < 0) + return 0; + if (grade > MAX_GRADE_PER_COURSE) + return MAX_GRADE_PER_COURSE; + return grade; + } +public: + + StudentGradesInfo(string student_id) : + student_id(student_id) { + } + + bool AddGrade(double grade, const string &course_name) { + grade = AdjustGrade(grade); + + for (int i = 0; i < (int) courses_names.size(); ++i) + if (course_name == courses_names[i]) + return false; // already added + + grades.push_back(grade); + courses_names.push_back(course_name); + return true; + } + void PrintAllCourses() const { + ++statistics_total_prints; + + cout << "Grades for student: " << GetStudentId() << "\n"; + for (int course_idx = 0; course_idx < (int) courses_names.size(); ++course_idx) + cout << "\t" << courses_names[course_idx] << " = " << grades[course_idx] << "\n"; + } + bool GetCourseGradeInfo(int pos, pair &result) const { + if (pos < 0 || pos >= (int) grades.size()) { + result = make_pair("", -1); + return false; + } + result = make_pair(courses_names[pos], grades[pos]); + return true; + } + + string GetStudentId() const { + return student_id; + } + + int GetTotalCoursesCount() const { + return grades.size(); + } + + pair GetTotalGradesSum() const { + double sum = 0, total = 0; + for (int grade_idx = 0; grade_idx < (int) grades.size(); ++grade_idx) + sum += grades[grade_idx], total += MAX_GRADE_PER_COURSE; + return make_pair(sum, total); + } +}; + +int StudentGradesInfo::statistics_total_prints = 0; + +class StudentGradesInfoWrapper { +private: + +public: + + bool AddGrade(double grade, const string &course_name) { + } + + void PrintAllCourses() const { + } + bool GetCourseGradeInfo(int pos, pair &result) const { + } + + string GetStudentId() const { + } + + int GetTotalCoursesCount() const { + + } + + pair GetTotalGradesSum() const { + } +}; + + +int main() { + StudentGradesInfoWrapper st1("S000123"); + st1.AddGrade(70, "Math"); + st1.AddGrade(70, "programming 1"); + st1.AddGrade(85, "programming 2"); + + st1.PrintAllCourses(); + + pair p = st1.GetTotalGradesSum(); + cout << p.first << "/" << p.second << "\n"; + + StudentGradesInfoWrapper st2("S000129"); + st2.PrintAllCourses(); + st2.PrintAllCourses(); + st2.PrintAllCourses(); + + cout << "Total Students " << StudentGradesInfoWrapper::GetTotalStudents() << "\n"; + cout << "Total Prints " << StudentGradesInfoWrapper::GetTotalPrints() << "\n"; + + cout << "Bye\n"; + + return 0; +} diff --git a/19-object-oriented-programming/07_homework_08_answer.cpp b/19-object-oriented-programming/07_homework_08_answer.cpp new file mode 100644 index 0000000..83c42b8 --- /dev/null +++ b/19-object-oriented-programming/07_homework_08_answer.cpp @@ -0,0 +1,161 @@ +#include +using namespace std; + +class StudentGradesInfo { +private: + string student_id; + vector grades; + vector courses_names; + const int MAX_GRADE_PER_COURSE = 100.0; + + friend class StudentGradesInfoWhiteBoxTester; // as a friend + + static int statistics_total_prints; + + double AdjustGrade(double grade) const { + if (grade < 0) + return 0; + if (grade > MAX_GRADE_PER_COURSE) + return MAX_GRADE_PER_COURSE; + return grade; + } +public: + + StudentGradesInfo(string student_id) : + student_id(student_id) { + } + + bool AddGrade(double grade, const string &course_name) { + grade = AdjustGrade(grade); + + for (int i = 0; i < (int) courses_names.size(); ++i) + if (course_name == courses_names[i]) + return false; // already added + + grades.push_back(grade); + courses_names.push_back(course_name); + return true; + } + void PrintAllCourses() const { + ++statistics_total_prints; + + cout << "Grades for student: " << GetStudentId() << "\n"; + for (int course_idx = 0; course_idx < (int) courses_names.size(); ++course_idx) + cout << "\t" << courses_names[course_idx] << " = " << grades[course_idx] << "\n"; + } + bool GetCourseGradeInfo(int pos, pair &result) const { + if (pos < 0 || pos >= (int) grades.size()) { + result = make_pair("", -1); + return false; + } + result = make_pair(courses_names[pos], grades[pos]); + return true; + } + + string GetStudentId() const { + return student_id; + } + + int GetTotalCoursesCount() const { + return grades.size(); + } + + pair GetTotalGradesSum() const { + double sum = 0, total = 0; + for (int grade_idx = 0; grade_idx < (int) grades.size(); ++grade_idx) + sum += grades[grade_idx], total += MAX_GRADE_PER_COURSE; + return make_pair(sum, total); + } +}; + +int StudentGradesInfo::statistics_total_prints = 0; + +class StudentGradesInfoWrapper { +private: + StudentGradesInfo student_info; + + static int statistics_total_prints; + static int statistics_total_students; +public: + + StudentGradesInfoWrapper(string student_id) : + student_info(StudentGradesInfo(student_id)) { + ++statistics_total_students; + } + + bool AddGrade(double grade, const string &course_name) { + return student_info.AddGrade(grade, course_name); + } + + void PrintAllCourses() const { + // Sadly StudentGradesInfoWrapper is not fully extensible. We can't retrieve statistics_total_prints + // Let's redo the work + ++statistics_total_prints; + + student_info.PrintAllCourses(); + } + bool GetCourseGradeInfo(int pos, pair &result) const { + return student_info.GetCourseGradeInfo(pos, result); + } + + string GetStudentId() const { + return student_info.GetStudentId(); + } + + int GetTotalCoursesCount() const { + return student_info.GetTotalCoursesCount(); + + } + + pair GetTotalGradesSum() const { + return student_info.GetTotalGradesSum(); + } + + int static GetTotalPrints() { + return statistics_total_prints; + } + int static GetTotalStudents() { + return statistics_total_students; + } +}; + +int StudentGradesInfoWrapper::statistics_total_prints = 0; +int StudentGradesInfoWrapper::statistics_total_students = 0; + +/* +In real life, we may use some open source code +But what if we later discovered it is so buggy and need replacement? +Or team stopped maintenance and we need more features? + +It is better in these conditions to WRAP them so that your code +depends on the wrapper +Once u decided to change the wrapper, everything else in ur code did not change + +It is important to design code that changes very little + +Reading: https://stackoverflow.com/questions/889160/what-is-a-wrapper-class + */ + +int main() { + StudentGradesInfoWrapper st1("S000123"); + st1.AddGrade(70, "Math"); + st1.AddGrade(70, "programming 1"); + st1.AddGrade(85, "programming 2"); + + st1.PrintAllCourses(); + + pair p = st1.GetTotalGradesSum(); + cout << p.first << "/" << p.second << "\n"; + + StudentGradesInfoWrapper st2("S000129"); + st2.PrintAllCourses(); + st2.PrintAllCourses(); + st2.PrintAllCourses(); + + cout << "Total Students " << StudentGradesInfoWrapper::GetTotalStudents() << "\n"; + cout << "Total Prints " << StudentGradesInfoWrapper::GetTotalPrints() << "\n"; + + cout << "Bye\n"; + + return 0; +} diff --git a/19-object-oriented-programming/07_homework_09_answer.txt b/19-object-oriented-programming/07_homework_09_answer.txt new file mode 100644 index 0000000..08e3556 --- /dev/null +++ b/19-object-oriented-programming/07_homework_09_answer.txt @@ -0,0 +1,8 @@ +- One of the popular principles is You aren't gonna need it (YAGNI) +- Always implement things when you actually need them, never when you just foresee that you need them +- Otherwise, they might be actually useless features and the team just lost resources for nothing +- Side note: It is good that the design allows extensions, but implement when need + +Reading: https://martinfowler.com/bliki/Yagni.html + artin Fowler is a British software developer, author and international public speaker on software development, + specialising in object-oriented analysis and design, UML, patterns, and agile software development methodologies, including extreme programming diff --git a/19-object-oriented-programming/07_homework_10_answer.txt b/19-object-oriented-programming/07_homework_10_answer.txt new file mode 100644 index 0000000..fd5770b --- /dev/null +++ b/19-object-oriented-programming/07_homework_10_answer.txt @@ -0,0 +1,45 @@ +string GetAnswerText() { + return answer_text; +} + +- Correct +- But the return calls copy constructor which takes memory & time +- As we don't change data members, C++ OO encourages using const! + + + +string GetAnswerText() const { + return answer_text; +} + +- Same as above, but now doesn't violate OO + +string& GetAnswerText() const { + return answer_text; +} + +- Good side: No copy constructor. The reference saves time & memory +- Bad. A user can make use of the returned string to reset it externally + + +const string& GetAnswerText() const { + return answer_text; +} + +- Perfect +- Return by refence, but prevent him from signing to a different value + const function also + + + +Think deeper :) + + + + + + + + + + + diff --git a/19-object-oriented-programming/09_homework_01_answer_AskMe_project.cpp b/19-object-oriented-programming/09_homework_01_answer_AskMe_project.cpp new file mode 100644 index 0000000..4a4a56d --- /dev/null +++ b/19-object-oriented-programming/09_homework_01_answer_AskMe_project.cpp @@ -0,0 +1,844 @@ +// You are encouraged to challenge this code and notify me of issues :) +// Compare this code with Programming 1 code to realize differences + +// From Model View perspective, this code mixes things. This makes real-life development harder due to coupling + +#include +using namespace std; + +/////////////////////////////// Helper Methods /////////////////////////////// +vector ReadFileLines(const string &path) { + vector lines; + + fstream file_handler(path.c_str()); + + if (file_handler.fail()) { + cout << "\n\nERROR: Can't open the file\n\n"; + return lines; + } + string line; + + while (getline(file_handler, line)) { + if (line.size() == 0) + continue; + lines.push_back(line); + } + + file_handler.close(); + return lines; +} + +void WriteFileLines(const string &path, const vector &lines, bool append = true) { + auto status = ios::in | ios::out | ios::app; + + if (!append) + status = ios::in | ios::out | ios::trunc; // overwrite + + fstream file_handler(path.c_str(), status); + + if (file_handler.fail()) { + cout << "\n\nERROR: Can't open the file\n\n"; + return; + } + for (const auto &line : lines) + file_handler << line << "\n"; + + file_handler.close(); +} + +vector SplitString(const string &str, const string &delimiter = ",") { + string s = str; + vector strs; + + int pos = 0; + string substr; + while ((pos = (int) s.find(delimiter)) != -1) { + substr = s.substr(0, pos); + strs.push_back(substr); + s.erase(0, pos + delimiter.length()); + } + strs.push_back(s); + return strs; +} + +int ToInt(const string &str) { + istringstream iss(str); + int num; + iss >> num; + + return num; +} + +int ReadInt(int low, int high) { + cout << "\nEnter number in range " << low << " - " << high << ": "; + int value; + + cin >> value; + + if (low <= value && value <= high) + return value; + + cout << "ERROR: invalid number...Try again\n"; + return ReadInt(low, high); +} + +int ShowReadMenu(const vector &choices) { + cout << "\nMenu:\n"; + for (int ch = 0; ch < (int) choices.size(); ++ch) { + cout << "\t" << ch + 1 << ": " << choices[ch] << "\n"; + } + return ReadInt(1, choices.size()); +} +////////////////////////////////////////////////////////////// + +class Question { +private: + int question_id; + // To support thread. Each question look to a parent question + // -1 No parent (first question in the thread) + int parent_question_id; + int from_user_id; + int to_user_id; + int is_anonymous_questions; // 0 or 1 + string question_text; + string answer_text; // empty = not answered + +public: + /* + * How many conclassor arguments is too many? + * https://stackoverflow.com/questions/40264/how-many-conclassor-arguments-is-too-many + */ + Question() : + question_id(-1), parent_question_id(-1), from_user_id(-1), to_user_id(-1), is_anonymous_questions(1) { + } + + Question(const string &line) { + vector substrs = SplitString(line); + assert(substrs.size() == 7); + + question_id = ToInt(substrs[0]); + parent_question_id = ToInt(substrs[1]); + from_user_id = ToInt(substrs[2]); + to_user_id = ToInt(substrs[3]); + is_anonymous_questions = ToInt(substrs[4]); + question_text = substrs[5]; + answer_text = substrs[6]; + } + + // It is more proper (or safer) to use the getters/setters in the class itself. For simplicity, I did not apply this in the code. + + string ToString() const { + ostringstream oss; + oss << question_id << "," << parent_question_id << "," << from_user_id << "," << to_user_id << "," << is_anonymous_questions << "," << question_text << "," << answer_text; + + return oss.str(); + } + + void PrintToQuestion() const { + string prefix = ""; + + if (parent_question_id != -1) + prefix = "\tThread: "; + + cout << prefix << "Question Id (" << question_id << ")"; + if (!is_anonymous_questions) + cout << " from user id(" << from_user_id << ")"; + cout << "\t Question: " << question_text << "\n"; + + if (answer_text != "") + cout << prefix << "\tAnswer: " << answer_text << "\n"; + cout << "\n"; + } + + void PrintFromQuestion() const { + cout << "Question Id (" << question_id << ")"; + if (!is_anonymous_questions) + cout << " !AQ"; + + cout << " to user id(" << to_user_id << ")"; + cout << "\t Question: " << question_text; + + if (answer_text != "") + cout << "\tAnswer: " << answer_text << "\n"; + else + cout << "\tNOT Answered YET\n"; + } + + void PrintFeedQuestion() const { + if (parent_question_id != -1) + cout << "Thread Parent Question ID (" << parent_question_id << ") "; + + cout << "Question Id (" << question_id << ")"; + if (!is_anonymous_questions) + cout << " from user id(" << from_user_id << ")"; + + cout << " To user id(" << to_user_id << ")"; + + cout << "\t Question: " << question_text << "\n"; + if (answer_text != "") + cout << "\tAnswer: " << answer_text << "\n"; + } + ///////////////// + // Setters & Getters + + const string& GetAnswerText() const { + return answer_text; + } + + void SetAnswerText(const string& answerText) { + answer_text = answerText; + } + + int GetFromUserId() const { + return from_user_id; + } + + void SetFromUserId(int fromUserId) { + from_user_id = fromUserId; + } + + int GetIsAnonymousQuestions() const { + return is_anonymous_questions; + } + + void SetIsAnonymousQuestions(int isAnonymousQuestions) { + is_anonymous_questions = isAnonymousQuestions; + } + + int GetParentQuestionId() const { + return parent_question_id; + } + + void SetParentQuestionId(int parentQuestionId) { + parent_question_id = parentQuestionId; + } + + int GetQuestionId() const { + return question_id; + } + + void SetQuestionId(int questionId) { + question_id = questionId; + } + + const string& GetQuestionText() const { + return question_text; + } + + void SetQuestionText(const string& questionText) { + question_text = questionText; + } + + int GetToUserId() const { + return to_user_id; + } + + void SetToUserId(int toUserId) { + to_user_id = toUserId; + } +}; + +class User { +private: + int user_id; // internal system ID + string user_name; + string password; + string name; + string email; + int allow_anonymous_questions; // 0 or 1 + + vector questions_id_from_me; + // From question id to list of questions IDS on this question (thread questions) - For this user + map> questionid_questionidsThead_to_map; + +public: + User() : + user_id(-1), allow_anonymous_questions(-1) { + } + + User(const string &line) { + vector substrs = SplitString(line); + assert(substrs.size() == 6); + + user_id = ToInt(substrs[0]); + user_name = substrs[1]; + password = substrs[2]; + name = substrs[3]; + email = substrs[4]; + allow_anonymous_questions = ToInt(substrs[5]); + } + + string ToString() const { + ostringstream oss; + oss << user_id << "," << user_name << "," << password << "," << name << "," << email << "," << allow_anonymous_questions; + + return oss.str(); + } + + void Print() const { + cout << "User " << user_id << ", " << user_name << " " << password << ", " << name << ", " << email << "\n"; + } + + void ResetToQuestions(const vector &to_questions) { + questions_id_from_me.clear(); + + for (const auto & question_id : to_questions) + questions_id_from_me.push_back(question_id); + } + void ResetFromQuestions(const vector> &to_questions) { + questionid_questionidsThead_to_map.clear(); + + for (const auto & id_pair : to_questions) + questionid_questionidsThead_to_map[id_pair.first].push_back(id_pair.second); + } + + void ReadUser(const string &user_name, int id) { + SetUserName(user_name); + SetUserId(id); + + string str; + + cout << "Enter password: "; + cin >> str; + SetPassword(str); + + cout << "Enter name: "; + cin >> str; + SetName(str); + + cout << "Enter email: "; + cin >> str; + SetEmail(str); + + cout << "Allow anonymous questions? (0 or 1): "; + int st; + cin >> st; + SetAllowAnonymousQuestions(st); + } + + int IsAllowAnonymousQuestions() const { + return allow_anonymous_questions; + } + + void SetAllowAnonymousQuestions(int allowAnonymousQuestions) { + allow_anonymous_questions = allowAnonymousQuestions; + } + + const string& GetEmail() const { + return email; + } + + void SetEmail(const string& email) { + this->email = email; + } + + const string& GetName() const { + return name; + } + + void SetName(const string& name) { + this->name = name; + } + + const string& GetPassword() const { + return password; + } + + void SetPassword(const string& password) { + this->password = password; + } + + int GetUserId() const { + return user_id; + } + + void SetUserId(int userId) { + user_id = userId; + } + + const string& GetUserName() const { + return user_name; + } + + void SetUserName(const string& userName) { + user_name = userName; + } + + const map >& GetQuestionidQuestionidsTheadToMap() const { + return questionid_questionidsThead_to_map; + // Note no setter is provided / returned as const & + } + + const vector& GetQuestionsIdFromMe() const { + return questions_id_from_me; + // Note no setter is provided + } +}; + +class QuestionsManager { +private: + // From question id to list of questions IDS on this question (thread questions) - All users + map> questionid_questionidsThead_to_map; + + // Map the question id to question object. Let's keep one place ONLY with the object + // When you study pointers, easier handling + map questionid_questionobject_map; + + int last_id; + +public: + QuestionsManager() { + last_id = 0; + } + + void LoadDatabase() { + last_id = 0; + questionid_questionidsThead_to_map.clear(); + questionid_questionobject_map.clear(); + + vector lines = ReadFileLines("09_homework_01_answer_AskMe_project_questions.txt"); + for (const auto &line : lines) { + Question question(line); + last_id = max(last_id, question.GetQuestionId()); + + questionid_questionobject_map[question.GetQuestionId()] = question; + + if (question.GetParentQuestionId() == -1) + questionid_questionidsThead_to_map[question.GetQuestionId()].push_back(question.GetQuestionId()); + else + questionid_questionidsThead_to_map[question.GetParentQuestionId()].push_back(question.GetQuestionId()); + } + } + + vector GetUserToQuestions(const User &user) const { + vector question_ids; + + for (const auto &pair : questionid_questionidsThead_to_map) { // pair> + for (const auto &question_id : pair.second) { // vector + + // Get the question from the map. & means same in memory, DON'T COPY + const Question &question = questionid_questionobject_map.find(question_id)->second; + + if (question.GetFromUserId() == user.GetUserId()) + question_ids.push_back(question.GetQuestionId()); + } + } + return question_ids; + } + + vector> GetUserFromQuestions(const User &user) const { + vector> question_ids; + + for (const auto &pair : questionid_questionidsThead_to_map) { // pair> + for (const auto &question_id : pair.second) { // vector + // Get the question from the map. & means same in memory, DON'T COPY + const Question &question = questionid_questionobject_map.find(question_id)->second; + + if (question.GetToUserId() == user.GetUserId()) { + if (question.GetParentQuestionId() == -1) + question_ids.push_back(make_pair(question.GetQuestionId(), question.GetQuestionId())); + else + question_ids.push_back(make_pair(question.GetParentQuestionId(), question.GetQuestionId())); + } + } + } + return question_ids; + } + + void PrintUserToQuestions(const User &user) const { + cout << "\n"; + + if (user.GetQuestionidQuestionidsTheadToMap().size() == 0) + cout << "No Questions"; + + for (const auto &pair : user.GetQuestionidQuestionidsTheadToMap()) { // pair> + for (const auto &question_id : pair.second) { // vector + + // Get the question from the map. & means same in memory, DON'T COPY + // Accessing questionid_questionobject_map[] change the map by adding if not exist. You can't use in const function + // Here we just find, which return iterator (second is like a pointer to object) + const Question &question = questionid_questionobject_map.find(question_id)->second; + question.PrintToQuestion(); + } + } + cout << "\n"; + } + + void PrintUserFromQuestions(const User &user) const { + cout << "\n"; + if (user.GetQuestionsIdFromMe().size() == 0) + cout << "No Questions"; + + for (const auto &question_id : user.GetQuestionsIdFromMe()) { // vector + const Question &question = questionid_questionobject_map.find(question_id)->second; + question.PrintFromQuestion(); + } + cout << "\n"; + } + + // Used in Answering a question for YOU. + // It can be any of your questions (thread or not) + int ReadQuestionIdAny(const User &user) const { + int question_id; + cout << "Enter Question id or -1 to cancel: "; + cin >> question_id; + + if (question_id == -1) + return -1; + + if (!questionid_questionobject_map.count(question_id)) { + cout << "\nERROR: No question with such ID. Try again\n\n"; + return ReadQuestionIdAny(user); + } + const Question &question = questionid_questionobject_map.find(question_id)->second; + + if (question.GetToUserId() != user.GetUserId()) { + cout << "\nERROR: Invalid question ID. Try again\n\n"; + return ReadQuestionIdAny(user); + } + return question_id; + } + + // Used to ask a question on a specific thread for whatever user + int ReadQuestionIdThread(const User &user) const { + int question_id; + cout << "For thread question: Enter Question id or -1 for new question: "; + cin >> question_id; + + if (question_id == -1) + return -1; + + if (!questionid_questionidsThead_to_map.count(question_id)) { + cout << "No thread question with such ID. Try again\n"; + return ReadQuestionIdThread(user); + } + return question_id; + } + + void AnswerQuestion(const User &user) { + int question_id = ReadQuestionIdAny(user); + + if (question_id == -1) + return; + + Question &question = questionid_questionobject_map.find(question_id)->second; + + question.PrintToQuestion(); + + if (question.GetAnswerText() != "") + cout << "\nWarning: Already answered. Answer will be updated\n"; + + cout << "Enter answer: "; // if user entered comma, system fails :) + + string line; + getline(cin, line); + getline(cin, line); + question.SetAnswerText(line); + } + + void DeleteQuestion(const User &user) { + int question_id = ReadQuestionIdAny(user); + + if (question_id == -1) + return; + + vector ids_to_remove; // to remove from questionid_questionobject_map + + // Let's see if thread or not. If thread, remove all of it + if (questionid_questionidsThead_to_map.count(question_id)) { // thread + ids_to_remove = questionid_questionidsThead_to_map[question_id]; + questionid_questionidsThead_to_map.erase(question_id); + } else { + ids_to_remove.push_back(question_id); + + // let's find in which thread to remove. Consistency is important when have multi-view + for (auto &pair : questionid_questionidsThead_to_map) { + vector &vec = pair.second; + for (int pos = 0; pos < (int) vec.size(); ++pos) { + if (question_id == vec[pos]) { + vec.erase(vec.begin() + pos); + break; + } + } + } + } + for (const auto &id : ids_to_remove) + questionid_questionobject_map.erase(id); + } + + void AskQuestion(const User &user, const pair &to_user_pair) { + Question question; + + if (!to_user_pair.second) { + cout << "Note: Anonymous questions are not allowed for this user\n"; + question.SetIsAnonymousQuestions(0); + } else { + cout << "Is anonymous questions?: (0 or 1): "; + int st; + cin >> st; + question.SetIsAnonymousQuestions(st); + } + + question.SetParentQuestionId(ReadQuestionIdThread(user)); + + cout << "Enter question text: "; // if user entered comma, system fails :) + string line; + getline(cin, line); + getline(cin, line); + question.SetQuestionText(line); + + question.SetFromUserId(user.GetUserId()); + question.SetToUserId(to_user_pair.first); + + // What happens in 2 parallel sessions who asked question? + // They are given same id. This is wrong handling :) + question.SetQuestionId(++last_id); + + questionid_questionobject_map[question.GetQuestionId()] = question; + + if (question.GetParentQuestionId() == -1) + questionid_questionidsThead_to_map[question.GetQuestionId()].push_back(question.GetQuestionId()); + else + questionid_questionidsThead_to_map[question.GetParentQuestionId()].push_back(question.GetQuestionId()); + } + + void ListFeed() const { + for (const auto &pair : questionid_questionobject_map) { + const Question &question = pair.second; + + if (question.GetAnswerText() == "") + continue; + question.PrintFeedQuestion(); + } + } + + void UpdateDatabase() { + vector lines; + + for (const auto &pair : questionid_questionobject_map) + lines.push_back(pair.second.ToString()); + + WriteFileLines("09_homework_01_answer_AskMe_project_questions.txt", lines, false); + } +}; + +class UsersManager { +private: + map userame_userobject_map; + User current_user; + int last_id; + + +public: + UsersManager() { + last_id = 0; + } + + void LoadDatabase() { + last_id = 0; + userame_userobject_map.clear(); + + vector lines = ReadFileLines("09_homework_01_answer_AskMe_project_users.txt"); + for (const auto &line : lines) { + User user(line); + userame_userobject_map[user.GetUserName()] = user; + last_id = max(last_id, user.GetUserId()); + } + } + + void AccessSystem() { + int choice = ShowReadMenu( { "Login", "Sign Up" }); + if (choice == 1) + DoLogin(); + else + DoSignUp(); + } + + void DoLogin() { + LoadDatabase(); // in case user added from other parallel run + + while (true) { + string name, pass; + cout << "Enter user name & password: "; + cin >> name >> pass; + current_user.SetUserName(name); + current_user.SetPassword(pass); + + if (!userame_userobject_map.count(current_user.GetUserName())) { + cout << "\nInvalid user name or password. Try again\n\n"; + continue; + } + const User& user_exist = userame_userobject_map[current_user.GetUserName()]; + + if (current_user.GetPassword() != user_exist.GetPassword()) { + cout << "\nInvalid user name or password. Try again\n\n"; + continue; + } + current_user = user_exist; + break; + } + } + + void DoSignUp() { + string user_name; + while (true) { + cout << "Enter user name. (No spaces): "; + cin >> user_name; + + if (userame_userobject_map.count(user_name)) + cout << "Already used. Try again\n"; + else + break; + } + // Move logic to user class, which may keep extending data members in future + + current_user.ReadUser(user_name, ++last_id); + userame_userobject_map[current_user.GetUserName()] = current_user; + + UpdateDatabase(current_user); + } + + void ResetToQuestions(const vector &to_questions) { + current_user.ResetToQuestions(to_questions); + } + + void ResetFromQuestions(const vector> &to_questions) { + current_user.ResetFromQuestions(to_questions); + } + + void ListUsersNamesIds() const { + for (const auto &pair : userame_userobject_map) + cout << "ID: " << pair.second.GetUserId() << "\t\tName: " << pair.second.GetName() << "\n"; + } + + pair ReadUserId() const { + int user_id; + cout << "Enter User id or -1 to cancel: "; + cin >> user_id; + + if (user_id == -1) + return make_pair(-1, -1); + + for (const auto &pair : userame_userobject_map) { + if (pair.second.GetUserId() == user_id) + return make_pair(user_id, pair.second.IsAllowAnonymousQuestions()); + } + + cout << "Invalid User ID. Try again\n"; + return ReadUserId(); + } + + void UpdateDatabase(const User &user) { + string line = user.ToString(); + vector lines(1, line); + WriteFileLines("18_users.txt", lines); + } + + const User& GetCurrentUser() const { + return current_user; + } +}; + +class AskMeSystem { +private: + UsersManager users_manager; + QuestionsManager questions_manager; + + void LoadDatabase(bool fill_user_questions = false) { // Internal + users_manager.LoadDatabase(); + questions_manager.LoadDatabase(); + + if (fill_user_questions) // first time, waiting for login + ResetCurrentUserQuestions(); + } + + /* + * Probably the most important design change + * We needed to decouple the question manager from relying on User implementation + * We break to 2 steps + * 1) Question manager return relevant question + * 2) User manager helps reseting the user question. Even the manager doesn't do this by itself + * + * This is more OO now + */ + void ResetCurrentUserQuestions() { + const User& user = users_manager.GetCurrentUser(); + + const auto &to_questions = questions_manager.GetUserToQuestions(user); + users_manager.ResetToQuestions(to_questions); + + const auto &from_questions = questions_manager.GetUserFromQuestions(user); + users_manager.ResetFromQuestions(from_questions); + } + +public: + void Run() { // only public one + LoadDatabase(false); + users_manager.AccessSystem(); + ResetCurrentUserQuestions(); + + vector menu; + menu.push_back("Print Questions To Me"); + menu.push_back("Print Questions From Me"); + menu.push_back("Answer Question"); + menu.push_back("Delete Question"); + menu.push_back("Ask Question"); + menu.push_back("List System Users"); + menu.push_back("Feed"); + menu.push_back("Logout"); + + while (true) { + int choice = ShowReadMenu(menu); + LoadDatabase(true); + + if (choice == 1) + questions_manager.PrintUserToQuestions(users_manager.GetCurrentUser()); + else if (choice == 2) + questions_manager.PrintUserFromQuestions(users_manager.GetCurrentUser()); + else if (choice == 3) { + questions_manager.AnswerQuestion(users_manager.GetCurrentUser()); + questions_manager.UpdateDatabase(); + } else if (choice == 4) { + questions_manager.DeleteQuestion(users_manager.GetCurrentUser()); + // Let's build again (just easier, but slow) + ResetCurrentUserQuestions(); + questions_manager.UpdateDatabase(); + } else if (choice == 5) { + pair to_user_pair = users_manager.ReadUserId(); + if (to_user_pair.first != -1) { + questions_manager.AskQuestion(users_manager.GetCurrentUser(), to_user_pair); + questions_manager.UpdateDatabase(); + } + } else if (choice == 6) + users_manager.ListUsersNamesIds(); + else if (choice == 7) + questions_manager.ListFeed(); + else + break; + } + Run(); // Restart again + } +}; + +int main() { + AskMeSystem service; + service.Run(); + + return 0; +} + +/* + 101,-1,11,13,0,Should I learn C++ first or Java,I think C++ is a better Start + 203,101,11,13,0,Why do you think so!,Just Google. There is an answer on Quora. + 205,101,45,13,0,What about python?, + 211,-1,13,11,1,It was nice to chat to you,For my pleasure Dr Mostafa + 212,-1,13,45,0,Please search archive before asking, + 300,101,11,13,1,Is it ok to learn Java for OOP?,Good choice + 301,-1,11,13,0,Free to meet?, + 302,101,11,13,1,Why so late in reply?, + + 13,mostafa,111,mostafa_saad_ibrahim,mostafa@gmail.com,1 + 11,noha,222,noha_salah,nono171@gmail.com,0 + 45,ali,333,ali_wael,wael@gmail.com,0 + + */ diff --git a/19-object-oriented-programming/09_homework_01_answer_AskMe_project_questions.txt b/19-object-oriented-programming/09_homework_01_answer_AskMe_project_questions.txt new file mode 100644 index 0000000..bcaa2a7 --- /dev/null +++ b/19-object-oriented-programming/09_homework_01_answer_AskMe_project_questions.txt @@ -0,0 +1,3 @@ +211,-1,13,11,1,It was nice to chat to you,For my pleasure Dr Mostafa +212,-1,13,45,0,Please search archive before asking, +301,-1,11,13,0,Free to meet?, diff --git a/19-object-oriented-programming/09_homework_01_answer_AskMe_project_users.txt b/19-object-oriented-programming/09_homework_01_answer_AskMe_project_users.txt new file mode 100644 index 0000000..d16de1b --- /dev/null +++ b/19-object-oriented-programming/09_homework_01_answer_AskMe_project_users.txt @@ -0,0 +1,4 @@ +13,mostafa,111,mostafa_saad_ibrahim,mostafa@gmail.com,1 +11,noha,222,noha_salah,nono171@gmail.com,0 +45,ali,333,ali_wael,wael@gmail.com,0 + diff --git a/19-object-oriented-programming/09_homework_02_answer_OnlineBookReader_project.cpp b/19-object-oriented-programming/09_homework_02_answer_OnlineBookReader_project.cpp new file mode 100644 index 0000000..a40e6f7 --- /dev/null +++ b/19-object-oriented-programming/09_homework_02_answer_OnlineBookReader_project.cpp @@ -0,0 +1,665 @@ +// If you don't understand reason behind something, change it and see +// E.g. why the system has users_manager as pointer? + +#include +#include +using namespace std; + +////////////////////////// Utilities ////////////////////////// +int ReadInt(int low, int high) { + cout << "\nEnter number in range " << low << " - " << high << ": "; + int value; + + cin >> value; + + if (low <= value && value <= high) + return value; + + cout << "ERROR: invalid number...Try again\n"; + return ReadInt(low, high); +} + +int ShowReadMenu(const vector &choices) { + cout << "\nMenu:\n"; + for (int ch = 0; ch < (int) choices.size(); ++ch) { + cout << "\t" << ch + 1 << ": " << choices[ch] << "\n"; + } + return ReadInt(1, choices.size()); +} + +string GetCurrentTimeDate() { // src: https://stackoverflow.com/questions/17223096/outputting-date-and-time-in-c-using-stdchrono + auto now = std::chrono::system_clock::now(); + auto in_time_t = std::chrono::system_clock::to_time_t(now); + + std::stringstream ss; + ss << std::put_time(std::localtime(&in_time_t), "%Y-%m-%d %X"); + return ss.str(); +} + +/////////////////////////////////////////////////// + +class Book { +private: + string isbn; + string title; + string author; + vector pages; + +public: + void Read() { + string str; + + cout << "Enter ISBN: "; + cin >> str; + SetIsbn(str); + + cout << "Enter Title: "; + cin >> str; + SetTitle(str); + + cout << "Enter Author Name: "; + cin >> str; + SetAuthor(str); + + cout << "Enter How many pages: "; + int pages_count; + cin >> pages_count; + + for (int page = 0; page < pages_count; ++page) { + cout << "Enter page # " << page + 1 << ": "; + cin >> str; + pages.push_back(str); + } + } + + const string& GetAuthor() const { + return author; + } + + void SetAuthor(const string& author) { + this->author = author; + } + + const string& GetIsbn() const { + return isbn; + } + + void SetIsbn(const string& isbn) { + this->isbn = isbn; + } + + const vector& GetPages() const { + return pages; + } + + void SetPages(const vector& pages) { + this->pages = pages; + } + + const string& GetTitle() const { + return title; + } + + void SetTitle(const string& title) { + this->title = title; + } + + string ToString() { + return title; + } +}; + +class BookReadingSession { +private: + // Using a pointer is a bad design chioce here: what if the original book removed now by admin? We access garbage! + // A more proper way: use book isbn, and later use book manager to find the book + Book* book; // Note, we did not create this pointer. Someone else should destory + int current_page; + string last_access_date; + +public: + BookReadingSession() : + BookReadingSession(nullptr) { + } + + BookReadingSession(Book* book) : + book(book), current_page(0), last_access_date(GetCurrentTimeDate()) { + + } + string ToString() { + ostringstream oss; + oss << GetBook()->GetTitle() << " Page: " << PageIdxStr() << " - " << GetLastAccessDate(); + return oss.str(); + } + + string GetCurrentPageContent() { + return book->GetPages()[current_page]; + } + + const Book* GetBook() const { + return book; // No set + } + + const string& GetLastAccessDate() const { + return last_access_date; + } + + void ResetLastAccessDate() { // More convenient + last_access_date = GetCurrentTimeDate(); + } + + int GetCurrentPage() const { + return current_page; + } + + string PageIdxStr() { + ostringstream oss; + oss << GetCurrentPage() + 1 << "/" << book->GetPages().size(); + return oss.str(); + } + + void NextPage() { + if (current_page < (int) book->GetPages().size() - 1) + current_page++; + } + void PreviousPage() { + if (current_page > 0) + current_page--; + } +}; + +class User { +private: + string user_name; + string password; + string name; + string email; + bool is_library_admin; + + vector reading_sessions; + +public: + + // If you have pointers internally: start with canceling copy constructor, so that you discover any bugs due to misuse + // Provide it based on logic & needs + User(const User&) = delete; + void operator=(const User&) = delete; + + User() { + is_library_admin = false; + } + + ~User() { + cout << "Destructor User\n"; + for (auto &session : reading_sessions) + delete session; + + reading_sessions.clear(); + } + + string ToString() const { + ostringstream oss; + oss << "Name: " << user_name; + if (IsLibraryAdmin()) + oss << " | Admin"; + oss << "\n"; + oss << "Email: " << email << "\n"; + oss << "User name: " << user_name << "\n"; + return oss.str(); + } + + void Read(const string &user_name) { + SetUserName(user_name); + + string str; + + cout << "Enter password: "; + cin >> str; + SetPassword(str); + + cout << "Enter name: "; + cin >> str; + SetName(str); + + cout << "Enter email: "; + cin >> str; + SetEmail(str); + } + + const string& GetEmail() const { + return email; + } + + void SetEmail(const string& email) { + this->email = email; + } + + const string& GetName() const { + return name; + } + + void SetName(const string& name) { + this->name = name; + } + + const string& GetPassword() const { + return password; + } + + void SetPassword(const string& password) { + this->password = password; + } + + const string& GetUserName() const { + return user_name; + } + + void SetUserName(const string& userName) { + user_name = userName; + } + + bool IsLibraryAdmin() const { + return is_library_admin; + } + + void SetIsLibraryAdmin(bool isLibraryAdmin) { + is_library_admin = isLibraryAdmin; + } + + const vector& GetReadingSessions() const { + // Note: Although the return is const vector, but the pointer is not const, so someone can cause problems using setters on pointer + return reading_sessions; // No set + } + + BookReadingSession* AddReadingSession(Book* book) { + // We create pointer & later delete it + BookReadingSession* session = new BookReadingSession(book); + reading_sessions.push_back(session); + return session; + } +}; + +class UsersManager { +private: + User* current_user = nullptr; + map userame_userobject_map; + + void FreeLoadedData() { + for (auto pair : userame_userobject_map) { + delete pair.second; + } + userame_userobject_map.clear(); + current_user = nullptr; + } + +public: + UsersManager() { + } + + ~UsersManager() { + cout << "Destuctor: UsersManager\n"; + FreeLoadedData(); + } + + // No sense for such a class (manager of objects) to be copyable! + // This is a C++ 11 feature that prevents Copy constructor and Assignment Operator (=)from being called. It delete then from the class + // https://ariya.io/2015/01/c-class-and-preventing-object-copy#:~:text=There%20are%20three%20ways%20to,have%20its%20instance%20copied%20around. + UsersManager(const UsersManager&) = delete; + void operator=(const UsersManager&) = delete; + + void LoadDatabase() { + cout<<"UsersManager: LoadDatabase\n"; + + FreeLoadedData(); + // Some "Dummy Data" for simplicity + User* user1 = new User(); + user1->SetUserName("mostafa"); + user1->SetPassword("111"); + user1->SetEmail("most@gmail.com"); + user1->SetIsLibraryAdmin(true); + user1->SetName("Mostafa Saad Ibrahim"); + userame_userobject_map[user1->GetUserName()] = user1; + + User* user2 = new User(); + user2->SetUserName("asmaa"); + user2->SetPassword("222"); + user2->SetEmail("asmaa@gmail.com"); + user2->SetIsLibraryAdmin(false); + user2->SetName("Asmaa Saad Ibrahim"); + userame_userobject_map[user2->GetUserName()] = user2; + } + + void AccessSystem() { + int choice = ShowReadMenu( { "Login", "Sign Up" }); + if (choice == 1) + DoLogin(); + else + DoSignUp(); + } + + void DoLogin() { + LoadDatabase(); + + while (true) { + string user_name, pass; + cout << "Enter user user_name & password: "; + cin >> user_name >> pass; + + if (!userame_userobject_map.count(user_name)) { + cout << "\nInvalid user user_name or password. Try again\n\n"; + continue; + } + User* user_exist = userame_userobject_map.find(user_name)->second; + + if (pass != user_exist->GetPassword()) { + cout << "\nInvalid user user_name or password. Try again\n\n"; + continue; + } + current_user = user_exist; + break; + } + } + + void DoSignUp() { + string user_name; + while (true) { + cout << "Enter user name. (No spaces): "; + cin >> user_name; + + if (userame_userobject_map.count(user_name)) + cout << "Already used. Try again\n"; + else + break; + } + + current_user->Read(user_name); + userame_userobject_map[current_user->GetUserName()] = current_user; + } + + BookReadingSession* AddReadingSession(Book* book) { + return current_user->AddReadingSession(book); + } + + const User* GetCurrentUser() const { + return current_user; + } +}; + +class BooksManager { +private: + map isbn_to_book_map; + + void FreeLoadedData() { + for (auto pair : isbn_to_book_map) { + delete pair.second; + } + isbn_to_book_map.clear(); + } + +public: + BooksManager() { + } + + void LoadDatabase() { + cout<<"BooksManager: LoadDatabase\n"; + FreeLoadedData(); + + Book* book1 = new Book(); + book1->SetIsbn("00001"); + book1->SetAuthor("Mostafa"); + book1->SetTitle("C++ how to program"); + vector pages1 = { "A C++", "B C++", "C C++", "D C++", "E C++" }; + book1->SetPages(pages1); + AddBook(book1); + + Book* book2 = new Book(); + book2->SetIsbn("00002"); + book2->SetAuthor("Morad"); + book2->SetTitle("Intro to algo"); + vector pages2 = { "A Algo", "B Algo", "C Algo", "D Algo", "E " }; + book2->SetPages(pages2); + AddBook(book2); + + Book* book3 = new Book(); + book3->SetIsbn("00003"); + book3->SetAuthor("Morad"); + book3->SetTitle("Data Structures in C++"); + vector pages3 = { "A Data", "B Data", "C Data", "D Data", "E Data" }; + book3->SetPages(pages3); + AddBook(book3); + } + + BooksManager(const BooksManager&) = delete; + void operator=(const BooksManager&) = delete; + + ~BooksManager() { + cout << "Destuctor: BooksManager\n"; + FreeLoadedData(); + } + + // CRUD operations + void AddBook(Book* book) { + isbn_to_book_map[book->GetIsbn()] = book; + } + + void UpdateBook(string isbn, Book* book) { + } + + void DeleteBook(string isbn) { + } + + Book* GetBook(string isbn) { + return nullptr; + } + + const map& GetIsbnToBookMap() const { + return isbn_to_book_map; + } + + void SetIsbnToBookMap(const map& isbnToBookMap) { + isbn_to_book_map = isbnToBookMap; + } + +}; + +class UserView { +private: + UsersManager &users_manager; + BooksManager &books_manager; +public: + + UserView(UsersManager & users_manager, BooksManager &books_manager) : + users_manager(users_manager), books_manager(books_manager) { + + } + + void Display() { + const User* user = users_manager.GetCurrentUser(); + cout << "\n\nHello " << user->GetName() << " | User View\n"; + + vector menu; + menu.push_back("View Profile"); + menu.push_back("List & Select from My Reading History"); + menu.push_back("List & Select from Available Books"); + menu.push_back("Logout"); + + while (true) { + int choice = ShowReadMenu(menu); + if (choice == 1) + ViewProfile(); + else if (choice == 2) + ListReadingHistory(); + else if (choice == 3) + ListAvailableBooks(); + else + break; + } + } + + void ViewProfile() { + const User* user = users_manager.GetCurrentUser(); + + cout << "\n" << user->ToString() << "\n"; + } + + void DisplaySession(BookReadingSession* session) { + vector menu; + menu.push_back("Next Page"); + menu.push_back("Previous Page"); + menu.push_back("Stop Reading"); + + while (true) { + cout << "Current Page: " << session->PageIdxStr() << "\n"; + cout << session->GetCurrentPageContent() << "\n"; + + int choice = ShowReadMenu(menu); + if (choice == 1) + session->NextPage(); + else if (choice == 2) + session->PreviousPage(); + else + break; + } + session->ResetLastAccessDate(); + } + + void ListReadingHistory() { + int idx = 0; + const auto& sessions = users_manager.GetCurrentUser()->GetReadingSessions(); + for (auto& session : sessions) { + cout << ++idx << ": " << session->ToString() << "\n"; + } + + if (idx == 0) + cout << "\nNo history. List books and start having fun\n"; + else { + cout << "\nWhich session to open?: "; + int choice = ReadInt(1, idx); + DisplaySession(sessions[choice - 1]); + } + } + + void ListAvailableBooks() { + const map& mp = books_manager.GetIsbnToBookMap(); + + cout << "\nOur current book collection:\n"; + int idx = 0; + for (const auto &pair : mp) { + // As we call ToString: we don't need to worry about book data members future changes + cout << "\t" << ++idx << " " << pair.second->ToString() << "\n"; + } + + cout << "\nWhich book to read?: "; + int choice = ReadInt(1, idx); // For simplicity, assume a new book is selected + + idx = 0; + for (const auto &pair : mp) { + if (++idx == choice) { + BookReadingSession* session = users_manager.AddReadingSession(pair.second); + DisplaySession(session); + break; + } + } + + } +}; + +class AdminView { +private: + UsersManager &users_manager; + BooksManager &books_manager; +public: + + AdminView(UsersManager &users_manager, BooksManager &books_manager) : + users_manager(users_manager), books_manager(books_manager) { + + } + + void Display() { + const User* user = users_manager.GetCurrentUser(); + + cout << "\n\nHello " << user->GetName() << " | Admin View\n"; + vector menu; + menu.push_back("View Profile"); + menu.push_back("Add Book"); + menu.push_back("Logout"); + + while (true) { + int choice = ShowReadMenu(menu); + if (choice == 1) + ViewProfile(); + else if (choice == 2) + AddBook(); + else + break; + } + } + + void ViewProfile() { + const User* user = users_manager.GetCurrentUser(); + + cout << "\n" << user->ToString() << "\n"; + } + + void AddBook() { + Book *book = new Book(); + book->Read(); + books_manager.AddBook(book); + } + +}; + +class OnlineReaderSystem { +private: + BooksManager *books_manager; + UsersManager *users_manager; + + void LoadDatabase() { + users_manager->LoadDatabase(); + books_manager->LoadDatabase(); + } + +public: + OnlineReaderSystem() : + books_manager(new BooksManager()), users_manager(new UsersManager()) { + } + + ~OnlineReaderSystem() { + cout << "Destuctor: OnlineReaderSystem\n"; + + if (books_manager != nullptr) { + delete books_manager; + books_manager = nullptr; + } + if (users_manager != nullptr) { + delete users_manager; + users_manager = nullptr; + } + } + + void Run() { // only public one + LoadDatabase(); + + while (true) { + users_manager->AccessSystem(); // login/signup + + // Let's make for every user, its own viewer class: Remember: Single responsibility principle + if (users_manager->GetCurrentUser()->IsLibraryAdmin()) { + AdminView view(*users_manager, *books_manager); + view.Display(); + } else { + UserView view(*users_manager, *books_manager); + view.Display(); + } + } + } +}; + +int main() { + OnlineReaderSystem site; + + site.Run(); + + return 0; +} + diff --git a/19-object-oriented-programming/10_01.cpp b/19-object-oriented-programming/10_01.cpp new file mode 100644 index 0000000..4097b2c --- /dev/null +++ b/19-object-oriented-programming/10_01.cpp @@ -0,0 +1,41 @@ +#include +using namespace std; + + + +class Student { +private: + string name; + string email; + string address; + string natioal_id; + + int starting_study_year; + double GPA; + vector studied_courses; +public: + bool IsValidEmailFormat(); + void AddCourseGrade(int course_id, double grade); + void PrintGrades(); +}; + +class Teacher { +private: + string name; + string email; + string address; + string natioal_id; + + int starting_employement_year; + double current_salary; + vector teaching_courses; +public: + bool IsValidEmailFormat(); + void AddCourse(int course_id); +}; + + +int main() { + + return 0; +} diff --git a/19-object-oriented-programming/10_02.cpp b/19-object-oriented-programming/10_02.cpp new file mode 100644 index 0000000..a57b172 --- /dev/null +++ b/19-object-oriented-programming/10_02.cpp @@ -0,0 +1,42 @@ +#include +using namespace std; + +class Person { +public: + string name = "Mostafa"; + string email = "most@gmail"; + + bool IsValidEmailFormat() { + return true; + } +}; + +class Student: public Person { +private: + double GPA; + +public: + void PrintGrades() { + cout << name << " GPA=" << GPA << "\n"; + } + + void SetGpa(double gpa) { + GPA = gpa; + } +}; + +int main() { + Student student; + + // Student is a person. + student.SetGpa(3.5); + student.IsValidEmailFormat(); + student.PrintGrades(); + + //Person is not necessarily a student + Person person; + person.IsValidEmailFormat(); + //person.PrintGrades(); // no nothing about student! + + return 0; +} diff --git a/19-object-oriented-programming/10_03.cpp b/19-object-oriented-programming/10_03.cpp new file mode 100644 index 0000000..bf9df8a --- /dev/null +++ b/19-object-oriented-programming/10_03.cpp @@ -0,0 +1,47 @@ +#include +using namespace std; + +class Person { +protected: + // Act as private for outsiders + // But inherited children can see it + string name = "Mostafa"; + string email = "most@gmail"; + +public: + bool IsValidEmailFormat() { + return true; + } +}; + +class Student: public Person { +private: + double GPA; + +public: + void PrintGrades() { + // Now we can see name again, but outsiders can't + cout << name << " GPA=" << GPA << "\n"; + } + + void SetGpa(double gpa) { + GPA = gpa; + } +}; + +int main() { + Student student; + + // Student is a person. + student.SetGpa(3.5); + student.IsValidEmailFormat(); + student.PrintGrades(); + + //Person is not necessarily a student + Person person; + //person.email; // can't: protected is like private for outsiders + person.IsValidEmailFormat(); + //person.PrintGrades(); // no nothing about student! + + return 0; +} diff --git a/19-object-oriented-programming/10_04.cpp b/19-object-oriented-programming/10_04.cpp new file mode 100644 index 0000000..b30fdf5 --- /dev/null +++ b/19-object-oriented-programming/10_04.cpp @@ -0,0 +1,59 @@ +#include +using namespace std; + +class Person { +protected: + string name; + string email; + string address; + string natioal_id; + +public: + bool IsValidEmailFormat() {return true;} + + void SetName(const string& name) { + this->name = name; + } +}; + +class Student: public Person { +private: + int starting_study_year; + double GPA; + vector studied_courses; + +public: + void AddCourseGrade(int course_id, double grade) {} + void PrintGrades() { + cout< teaching_courses; + +public: + void AddCourse(int course_id) {} + + void SetCurrentSalary(double currentSalary) { + current_salary = currentSalary; + } +}; + +int main() { + Student student; + student.SetGpa(3.5); + student.PrintGrades(); + + Teacher teacher; + teacher.SetCurrentSalary(5000.0); + + return 0; +} diff --git a/19-object-oriented-programming/10_homework_01_answer.cpp b/19-object-oriented-programming/10_homework_01_answer.cpp new file mode 100644 index 0000000..cac9370 --- /dev/null +++ b/19-object-oriented-programming/10_homework_01_answer.cpp @@ -0,0 +1,38 @@ +#include +using namespace std; + +class Shape { +}; + +class TwoDimensionalShape : public Shape { +}; + +class Circle : public TwoDimensionalShape { +}; + +class Square : public TwoDimensionalShape { +}; + +class Triangle : public TwoDimensionalShape { +}; + + + + +class ThreeDimensionalShape : public Shape { +}; + +class Sphere : public ThreeDimensionalShape { +}; + +class Cube : public ThreeDimensionalShape { +}; + +class Tetrahedron : public ThreeDimensionalShape { +}; + +int main() { + + + return 0; +} diff --git a/19-object-oriented-programming/10_homework_02_answer.cpp b/19-object-oriented-programming/10_homework_02_answer.cpp new file mode 100644 index 0000000..3388a2e --- /dev/null +++ b/19-object-oriented-programming/10_homework_02_answer.cpp @@ -0,0 +1,49 @@ +#include +using namespace std; + +class CommunityMember { +}; + + + +class Student : public CommunityMember { +}; + +class Alumnus : public CommunityMember { +}; + +class Employee : public CommunityMember { +}; + + + + + +class Staff : public Employee { +}; + +class Faculty : public Employee { +}; + + + + + +class Teacher : public Faculty { +}; + +class Administrator : public Faculty { +}; + + + + +class AdministratorTeacher : public Teacher, public Administrator { +}; + + +int main() { + + + return 0; +} diff --git a/19-object-oriented-programming/10_homework_03_answer.txt b/19-object-oriented-programming/10_homework_03_answer.txt new file mode 100644 index 0000000..bbd3689 --- /dev/null +++ b/19-object-oriented-programming/10_homework_03_answer.txt @@ -0,0 +1,7 @@ +The semantic is wrong. There is no clear and strong has-a relationship. Never do that in inheritance + +A car is not an Engine. The car is not 4 wheels. Sometimes we can stack things like inheritance and it works for now (and be a big mess later) + +The right relationship is composition. The car has an engine and 4-wheels + +Prefer composition over inheritance most of the time, even if inheritance makes more sense unless it really should be an inheritance. Think twice. diff --git a/19-object-oriented-programming/10_homework_04_answer.txt b/19-object-oriented-programming/10_homework_04_answer.txt new file mode 100644 index 0000000..0730d10 --- /dev/null +++ b/19-object-oriented-programming/10_homework_04_answer.txt @@ -0,0 +1,15 @@ +- We wanna represent these 3 animals, which are mammals +- There are 3 common functions as in the class +- 2 of them are common behavior +- but the sound is unique for each element + +- More importantly, the design means EVERY mammal should have these functionalities +- But Platypus lays eggs and doesn't give birth + +- Why the designer made this mistake? +- Initial requirements were to model these 3 animals. +- As the 3 functionalities are common, they all added in the mammal superclass + +- Whenever you have a parent class, make sure it is VALID for all possible future sub-classes, not only current ones. Your teammates will extend your work in the future! + +Reading: https://www.clear.rice.edu/comp201/07-spring/lectures/lec06/ diff --git a/19-object-oriented-programming/10_homework_05_answer.txt b/19-object-oriented-programming/10_homework_05_answer.txt new file mode 100644 index 0000000..94d0bf9 --- /dev/null +++ b/19-object-oriented-programming/10_homework_05_answer.txt @@ -0,0 +1,4 @@ +- If we extended from the 4 classes, we will end up with a lot of functions that are irrelevant to the current class +- Usually, we do mistakes in design and even with a reasonable has-a relationship, a lot of functions just are in our new class that has no use! + +- In the example, A robot dog won't go toilet, it is a made dog, not a real one. Sometimes the has-a relationship is not as strong as we wish diff --git a/19-object-oriented-programming/10_homework_06_answer.txt b/19-object-oriented-programming/10_homework_06_answer.txt new file mode 100644 index 0000000..8c3a204 --- /dev/null +++ b/19-object-oriented-programming/10_homework_06_answer.txt @@ -0,0 +1,22 @@ +The diamond problem occurs when two superclasses of a class have a common base class. + For example, the copier class gets two copies of all attributes of PoweredDevice class, this causes ambiguities. + +To solve the ambigiuty, c++ offers virtual keyword + 1: You define both Scanner and printer to be: virtual public PoweredDevice + 2: Default constructor will only be called in PoweredDevice + + In general if class can be visible from more than direction, use virtual public CLASS not just public CLASS + +Generally speaking, avoiding multiple inheritance is highly recommended. Otherwise, strongly defend your choices + Most of the time you really don't need it. It causes a lot of problems. + Stick to tree structure + Better idea to depend on Interfaces (later) + + +Further readings: What is Diamond Problem + https://www.geeksforgeeks.org/multiple-inheritance-in-c/ + https://www.freecodecamp.org/news/multiple-inheritance-in-c-and-the-diamond-problem-7c12a9ddbbec/ + + + + diff --git a/19-object-oriented-programming/10_homework_09_answer.png b/19-object-oriented-programming/10_homework_09_answer.png new file mode 100644 index 0000000..c3b8b93 Binary files /dev/null and b/19-object-oriented-programming/10_homework_09_answer.png differ diff --git a/19-object-oriented-programming/10_homework_10_answer.png b/19-object-oriented-programming/10_homework_10_answer.png new file mode 100644 index 0000000..d77f6c7 Binary files /dev/null and b/19-object-oriented-programming/10_homework_10_answer.png differ diff --git a/19-object-oriented-programming/10_homework_10_answer.txt b/19-object-oriented-programming/10_homework_10_answer.txt new file mode 100644 index 0000000..ac6726c --- /dev/null +++ b/19-object-oriented-programming/10_homework_10_answer.txt @@ -0,0 +1,20 @@ +This problem is known as an Exploding class hierarchy + +We could easily from the begin build one class and keep changing it so that it has boolean in the constructor for: +    - is thread-safe? is logging? is caching? +     +- But this means we have a huge code with several reasons to change = mess + +- When we tried to follow design guidelines = every time we expanded the tree leaves with more classes to support a new feature + +- Here is another real case +    https://stackoverflow.com/questions/60540457/class-hierarchies-exploding + +- "Large inheritance hierarchies in general, and deep ones in particular, are confusing to understand and therefore difficult to maintain. " +- "Inheritance is a design-time decision and trades off a lot of runtime flexibility." + +- + +- Diagrams source: https://dzone.com/articles/is-inheritance-dead + + diff --git a/19-object-oriented-programming/11_01.cpp b/19-object-oriented-programming/11_01.cpp new file mode 100644 index 0000000..53a786d --- /dev/null +++ b/19-object-oriented-programming/11_01.cpp @@ -0,0 +1,42 @@ +#include +using namespace std; + +class Person { +protected: + string name; + +public: + Person() : name("most") { + cout << "Person Default Constructor\n"; + } + Person(string name) : + name(name) { + cout << "Person 2nd Constructor\n"; + } + ~Person() { + cout<<"Person Destructor\n"; + } +}; + +class Student : public Person { +private: + double gpa; +public: + Student() { // CE: name("hani") you can't access base here + cout << "Student Default Constructor\n"; + gpa = 0; + name = "hani"; // you can set here + } + Student(double gpa) : Person("Ali"), gpa(gpa) { + cout << "Student 2nd Constructor\n"; + } + ~Student() { + cout<<"Student Destructor\n"; + } +}; + +int main() { + Student student1; + Student student2(3.0); + return 0; +} diff --git a/19-object-oriented-programming/11_02.cpp b/19-object-oriented-programming/11_02.cpp new file mode 100644 index 0000000..3a748c0 --- /dev/null +++ b/19-object-oriented-programming/11_02.cpp @@ -0,0 +1,30 @@ +#include +using namespace std; + +class A { +public: + int GetValue() { + return 10; + } + + string GetStr() { + return "Hello"; + } +}; + +class B: public A { +public: + int GetValue() { + return 20; + } +}; + +int main() { + B b1; + cout << b1.GetValue() << " " << b1.GetStr() << "\n"; + + B* b2 = new B(); + cout << b2->GetValue() << " " << b2->GetStr() << "\n"; + + return 0; +} diff --git a/19-object-oriented-programming/11_03.cpp b/19-object-oriented-programming/11_03.cpp new file mode 100644 index 0000000..f3212a5 --- /dev/null +++ b/19-object-oriented-programming/11_03.cpp @@ -0,0 +1,25 @@ +#include +using namespace std; + +class A { +public: + int x; + int y; + A(int x, int y = 20) : + x(x), y(y) { + } +}; + +class B: public A { + int z; +public: + // C++1 inheriting base class constructors + using A::A; +}; + +int main() { + B b(3); + cout< +using namespace std; + +class A { +public: + void f1() { cout << "A::f1\n"; } + void f1(int x) { cout << "A::f1(x)\n"; } + void f1(int x, int y) { cout << "A::f1(x,y)\n"; } +}; + +class B: public A { +public: + void f1() { cout << "B::f1\n"; } + void f1(int x) { cout << "B::f1(x)\n"; } + void f1(int x, int y) { cout << "B::f1(x,y)\n"; } +}; + +int main() { + B* b1 = new B(); + b1->f1(); + b1->f1(1); + b1->f1(1, 2); + delete b1; +} diff --git a/19-object-oriented-programming/11_05.cpp b/19-object-oriented-programming/11_05.cpp new file mode 100644 index 0000000..08c6afc --- /dev/null +++ b/19-object-oriented-programming/11_05.cpp @@ -0,0 +1,39 @@ +#include +using namespace std; + +class A { +public: + int x; +protected: + int y; +private: + // Always invisible for outsiders + int z; +}; + +class B: public A { + // x is public + // y is protected +}; + +class C: protected A { + // x is protected + // y is protected +}; + +class D: private A { + // Now invisible for outsiders + // x is private + // y is private +}; + +int main() { + A a; + a.x = 1; // can't access y or z + + B b; + b.x = 1; // can't access y or z + + C c; // can't access x or y or z + return 0; +} diff --git a/19-object-oriented-programming/11_06.cpp b/19-object-oriented-programming/11_06.cpp new file mode 100644 index 0000000..104d9c0 --- /dev/null +++ b/19-object-oriented-programming/11_06.cpp @@ -0,0 +1,57 @@ +#include +using namespace std; + +// https://users.cs.fiu.edu/~weiss/phc++/code/exceptionDemo.cpp + +void div(int x) { + 100000/x; +} + +void array_access(int pos) { + vector v(5); + + v.at(pos) = 1; // out_of_range = logic_error +} + +double mysqrt(double x) { + if (x < 0) + throw domain_error("sqrt of neg number"); + else + return sqrt(x); +} + +double myexp(double x) { + double result = exp(x); + if (result == HUGE_VAL) + throw out_of_range("exp too large"); + else + return result; +} + + + +void test(double x) { + try { + mysqrt(x); + myexp(x); + array_access(x); + } catch (domain_error & e) { + cout << "Caught DOMAIN exception " << e.what() << endl; // invoke correct what + } catch (logic_error & e) { + cout << "Caught logical error exception " << e.what() << endl; // invoke correct what + } catch (...) { + cout << "Catching a lot\n"; + // you can't catch division by zero + // "low-level events, such as arithmetic overflows and divide by zero, + // are assumed to be handled by a dedicated lower-level mechanism rather than by exceptions " + } +} + +int main() { + test(10); + test(-4); + test(10000000); + test(0); // program crach + + return 0; +} diff --git a/19-object-oriented-programming/11_homework_01_answer.txt b/19-object-oriented-programming/11_homework_01_answer.txt new file mode 100644 index 0000000..57656ec --- /dev/null +++ b/19-object-oriented-programming/11_homework_01_answer.txt @@ -0,0 +1,79 @@ +In constructors, line 25, C++ prevents classes from initializing inherited member variables in the initialization list of a constructor. +Why? Think in cases that languages designers considered + + +1) Because const variables must be initialized with a value at the time of creation, the base class constructor must set its value when the variable is created. + +2) However, when the base class constructor finishes, the derived class constructors initialization lists are then executed. +Each derived class would then have the opportunity to initialize that variable, potentially changing its value! +By restricting the initialization of variables to the constructor of the class those variables belong to, +C++ ensures that all variables are initialized only ONCE. + +https://www.learncpp.com/cpp-tutorial/114-constructors-and-initialization-of-derived-classes/ + +==================== + +In C++, Friendship is neither inherited nor transitive. +Why functions are not inherited? + +https://stackoverflow.com/questions/3561648/why-does-c-not-allow-inherited-friendship/24304490 + +==================== +Comparing, the set of objects of a base class with its derived classes, which one is bigger? + +Yhe set of objects represented by a base class typically is larger than the set of objects represented by any of its derived classes. +For example, the base class Vehicle represents all vehicles, including cars, trucks, boats, airplanes, bicycles and so on. + +By contrast, derived class Car represents a smaller, more specific subset of all vehicles. + + +======================== +We know that we don’t access private variables, but are they still inherited? + +Sure. They are they still in the memory. The base class has its own functions that works on its private variables & functions + +Inheritance != Access + + +========================= +Think: Making variable protected vs public getter/setter for it? + +- The rule of thumb is simple: make each class or member as inaccessible as possible. In other words, + use the lowest possible access level consistent with the proper functioning of the software that you are writing. +- Use the most restrictive access level that makes sense for a particular member. Use private unless you have a good reason not to. + - Public fields tend to link you to a particular implementation and limit your flexibility in changing your code. +- If you are not sure why you need a protected class member, then declare it private. If you wish to set it from outside the class, then make a public setter. + +- A protected field allows the subclass to modify parent class state directly. + This means a subclass may be able to violate the parent's "invariants" or validations (e.g. setter has validations). + In other words, this approach might cause a class to behave inconsistently + + + Side note, what are invariants in previous answer? + In OOP, an invariant is a set of assertions that must always hold true during the life of an object for the program to be valid. + It should hold true from the end of the constructor to the start of the destructor whenever the object is not currently executing a method that changes its state. + + An example of invariant could be that exactly one of two member variables should be null. + + Or that if one has a given value, then the set of allowed values for the other is this or that... + + I sometime use a member function of the object to check that the invariant holds. If this is not the case, an assert is raised. + And the method is called at the start and exit of each method that changes the object + + https://softwareengineering.stackexchange.com/questions/32727/what-are-invariants-how-can-they-be-used-and-have-you-ever-used-it-in-your-pro + +Coupling: +- With using protected data members is that derived, class member functions are more likely to be written so that they depend on the base-class implementation. +- Derived classes should depend only on the base-class services (i.e., non- private member functions) and not on the base-class implementation. +- With protected data members in the base class, if the base-class implementation changes, we may need to modify all derived classes of that base class. +- For example, if for some reason we were to change the names of data members firstName and lastName to first and last, +- then we’d have to do so for all occurrences in which a derived class references these base-class data members directly. +- Such software is said to be fragile or brittle, because a small change in the base class can “break” derived-class implementation. +- You should be able to change the base-class implementation while still providing the same services to derived classes. +- Of course, if the base-class services change, we must reimplement our derived classes—good object-oriented design attempts to prevent this. +- From: C++ How to program + + + + + + diff --git a/19-object-oriented-programming/11_homework_02_answer_package.cpp b/19-object-oriented-programming/11_homework_02_answer_package.cpp new file mode 100644 index 0000000..b9c7d75 --- /dev/null +++ b/19-object-oriented-programming/11_homework_02_answer_package.cpp @@ -0,0 +1,210 @@ +#include +using namespace std; + +class Address { +private: + string name; + string address; + string city; +public: + const string& GetAddress() const { + return address; + } + + void SetAddress(const string& address) { + this->address = address; + } + + const string& GetCity() const { + return city; + } + + void SetCity(const string& city) { + this->city = city; + } + + const string& GetName() const { + return name; + } + + void SetName(const string& name) { + this->name = name; + } +}; + +class StandardPackage { +private: + Address sender_address; + Address reciever_address; + double weight_kg; + double price_per_kg; + +public: + + StandardPackage(const Address &sender_address, const Address &reciever_address, double weight_kg, double price_per_kg) : + sender_address(sender_address), reciever_address(reciever_address), weight_kg(weight_kg), price_per_kg(price_per_kg) { + } + + double TotalCost() const { + return weight_kg * price_per_kg; + } + + double GetPricePerKg() const { + return price_per_kg; + } + + void SetPricePerKg(double pricePerKg) { + price_per_kg = pricePerKg; + } + + const Address &GetRecieverAddress() const { + return reciever_address; + } + + void SetRecieverAddress(const Address &recieverAddress) { + reciever_address = recieverAddress; + } + + const Address & GetSenderAddress() const { + return sender_address; + } + + void SetSenderAddress(const Address &senderAddress) { + sender_address = senderAddress; + } + + double GetWeightKg() const { + return weight_kg; + } + + void SetWeightKg(double weightKg) { + weight_kg = weightKg; + } +}; + +class TwoDayPackage: public StandardPackage { +private: + double fixed_fee; + +public: + TwoDayPackage(const Address &sender_address, const Address &reciever_address, double weight_kg, double price_per_kg, double fixed_fee) : + StandardPackage(sender_address, reciever_address, weight_kg, price_per_kg), fixed_fee(fixed_fee) { + } + + double TotalCost() const { + return StandardPackage::TotalCost() + fixed_fee; + } + + double GetFixedFee() const { + return fixed_fee; + } + + void SetFixedFee(double fixedFee) { + fixed_fee = fixedFee; + } +}; + +class HeavyPackage: public StandardPackage { +private: + const double limit_kg = 100; + double extra_price_per_kg; + +public: + HeavyPackage(const Address &sender_address, const Address &reciever_address, double weight_kg, double price_per_kg, double extra_price_per_kg) : + StandardPackage(sender_address, reciever_address, weight_kg, price_per_kg), extra_price_per_kg(extra_price_per_kg) { + } + + double TotalCost() const { + double ret = StandardPackage::TotalCost(); + + if (GetWeightKg() > limit_kg) + ret += (GetWeightKg() - limit_kg) * extra_price_per_kg; + return ret; + } + + double GetExtraPricePerKg() const { + return extra_price_per_kg; + } + + void SetExtraPricePerKg(double extraPricePerKg) { + extra_price_per_kg = extraPricePerKg; + } +}; + +class PaymentCard { +private: + string card_number; + double expiry_date; +}; + +class CreditCard: public PaymentCard { +}; + +class DebitCard: public PaymentCard { +}; + +class Shipment { +private: + // How ugly is such way below?! + vector standard_packages; + vector two_day_packages; + vector heavy_packages; + + CreditCard credit_card; + DebitCard debit_card; + bool is_credit_card_used; + +public: + void AddStandardPackage(const StandardPackage & package) { + standard_packages.push_back(package); + } + void AddTwoDayPackage(const TwoDayPackage & package) { + two_day_packages.push_back(package); + } + void AddHeavyPackage(const HeavyPackage & package) { + heavy_packages.push_back(package); + } + + void SetCreditCard(const CreditCard &credit_card_) { + credit_card = credit_card_; + is_credit_card_used = true; + } + void SetDebitCard(const DebitCard &debit_card_) { + debit_card = debit_card_; + is_credit_card_used = false; + } + + double TotalCost() const { + double total = 0; + + // What is wrong from OO principles here? + for (auto const & package : standard_packages) + total += package.TotalCost(); + + for (auto const & package : two_day_packages) + total += package.TotalCost(); + + for (auto const & package : heavy_packages) + total += package.TotalCost(); + + return total; + } +}; + +class Customer { +private: + vector shipments; + vector credit_cards; + vector debit_cards; +public: + + void AddShipment() { + + } +}; + +int main() { + + return 0; +} + diff --git a/19-object-oriented-programming/11_homework_03_answer.cpp b/19-object-oriented-programming/11_homework_03_answer.cpp new file mode 100644 index 0000000..dc6f4e3 --- /dev/null +++ b/19-object-oriented-programming/11_homework_03_answer.cpp @@ -0,0 +1,66 @@ +#include +using namespace std; + +class A { +public: + A(string str) { cout<<"Constructor "< +using namespace std; + +class A { +protected: + int px; + void pf() { + } +}; + +class B { +protected: + int px; + void pf() { + } + + int GetSalary() { + return 100; + } +}; + +class C: public A, public B { +public: + void f() { + // If common data/function, use resolution operator to specificy which one as compiler will be confused (Ambiguity) + A::px = 1; // to access px from A + B::pf(); // to access pf from B + } + + int GetSalary() { + // The developer wanted to call parent GetSalary, but his method is same name + // This will be infinite recursion. Again access parent clearly by B:: + int parent_salary = B::GetSalary(); + return 2 * parent_salary + 1; + } +}; + +int main() { + C c; + cout< +using namespace std; + +class A { +public: + int x = 1; + void print() { + cout << "I am A\n"; + } + ~A() { + cout << "A Destructor\n"; + } +}; + +class B: public A { +public: + int y = 2; + void print() { + cout << "I am B\n"; + } + ~B() { + cout << "B Destructor\n"; + } +}; + +class C: public B { +public: + int z = 3; + void print() { + cout << "I am C\n"; + } + ~C() { + cout << "C Destructor\n"; + } +}; + +void hello(A* a) { + a->x = 1; + a->print(); +} + +int main() { + C* c = new C(); + A* a_points_c = new C(); + + hello(c); + hello(a_points_c); + + c->print(); + a_points_c->print(); + + delete c; + delete a_points_c; + + return 0; +} diff --git a/19-object-oriented-programming/11_homework_05_answer.cpp b/19-object-oriented-programming/11_homework_05_answer.cpp new file mode 100644 index 0000000..8498f6f --- /dev/null +++ b/19-object-oriented-programming/11_homework_05_answer.cpp @@ -0,0 +1,85 @@ +#include +using namespace std; + +class A { +public: + int x = 1; + + void print() { + cout << "I am A\n"; + } + + ~A() { + cout << "A Destructor\n"; + } + +}; + +class B: public A { +public: + int y = 2; + + void print() { + cout << "I am B\n"; + } + + ~B() { + cout << "B Destructor\n"; + } +}; + +class C: public B { +public: + int z = 3; + + void print() { + cout << "I am C\n"; + } + + ~C() { + cout << "C Destructor\n"; + } +}; + +void hello(A* a) { + // what is visible? only A members + a->x = 1; + a->print(); +} + +int main() { + // Normal and each see his members and parents members + C* c = new C(); + + // As type eventually is A*, only what in A is visible + // Looks like casting! + A* a_points_c = new C(); + //a_points_c->z = 1; // Compiler error + + // Observation: an object of a derived class can be treated as an object of its base class. + // However, we cannot treat a base-class object as an object of any of its derived classes. + + hello(c); + hello(a_points_c); + + // the invoked functionality depends on the type of the pointer used to invoke the function, + // not the type of the object for which the member function is called. + c->print(); + a_points_c->print(); + + delete c; + delete a_points_c; // same as above. Destructor is a function. Only A destructor called. MEMORY LEAK + + return 0; +} + +/* +I am A +I am A +I am C +I am A +C Destructor +B Destructor +A Destructor +A Destructor + */ diff --git a/19-object-oriented-programming/11_homework_06_answer.cpp b/19-object-oriented-programming/11_homework_06_answer.cpp new file mode 100644 index 0000000..bfb1987 --- /dev/null +++ b/19-object-oriented-programming/11_homework_06_answer.cpp @@ -0,0 +1,32 @@ +#include +using namespace std; + +class DecoratedString: public string { +public: + + // inheriting the constructors from string + using string::string; + + // using std::string::operator=; + + void decorate() { + string str = *this; + str = "<<[[" + str + "]]>>"; + + //*this = str; + this->assign(str); + + // You can't just use: *this = str; + // as this is = assignment operator (later to study) + // The default assignment operator = now is for DecoratedString not std::string + // If you want it possible, add also using std::string::operator=; + } +}; + +int main() { + DecoratedString str = "I am learning CS"; + + str.decorate(); + cout << str << "\n"; // <<[[I am learning CS]]>> + cout<<( str == "<<[[I am learning CS]]>>" ); // True +} diff --git a/19-object-oriented-programming/11_homework_07_answer.txt b/19-object-oriented-programming/11_homework_07_answer.txt new file mode 100644 index 0000000..2e5726b --- /dev/null +++ b/19-object-oriented-programming/11_homework_07_answer.txt @@ -0,0 +1,24 @@ +1) The system explains an image editor which is "aggregated" of a set of shapes to draw (0 or more shape) +    Each shape supports the Draw function to draw it and another to compute its area +    The shape can be either rectangle or circle that should override the draw/area functions +     +    Adobe Photoshop is an image editor with extra functionality of Enlarging the drawn shape by percent +     +    From the data perspective +        both color and shapes are protected variables +        rectangle and circle use a point class (x, y) which is enough to compute area or draw +             +             +2) There are 2 implementation concerns +    First, the Image editor has an array of shapes! Maybe we should have an array of rectangles and another array of circles +        But also this is so weird. We will keep duplicating code to do the same tasks of each shape +        Can't we just iterate on Shapes parent somehow? +         +    Second: Method Draw/ComputeArea in parent class shape. No default implementation can be provided! +        Should we do just empty function? What if someone just forgot to implement? +        Or maybe an assert? +        Can't we force a compile error if the user forgot to implement it? +         +    Both issues are handled with polymorphism! +         +         diff --git a/19-object-oriented-programming/11_homework_08_answer.txt b/19-object-oriented-programming/11_homework_08_answer.txt new file mode 100644 index 0000000..32afec4 --- /dev/null +++ b/19-object-oriented-programming/11_homework_08_answer.txt @@ -0,0 +1,33 @@ +- Scalability is a critical key to the success of the business. Let's think about it for the following 2 choices +- Assume we have 10 Million mobile users, say of 15 different types of mobiles + + +Choice 1: Each app periodically contacts the server to see if there are new notifications or not +- As mobiles are creating the requests, this means the server is receiving periodically millions of requests +- 2 critical problems here +- The server will be very slow to handle "concurrent requests" of such size +- Most of the time there won't be messages to notify + + +Choice 2: When a user opens his mobile game, he sends to the Game to register for messages to get notifications +- The server provides an API for apps to register or de-register +- When there is a message, the server loops on them and just notify +- Each device type might need special code to send notifications + + + + +Implementation: +Choice 1: +You need a thread per mobile app that wakes up say each 1 minute, then send a request for the Game API + + +Choice 2: +You need to give API to get register/de-register requests +You need to handle each device type separately +You need with every message to iterate on objects of each device type to send a request +    E.g. vector mobiles;   vector tablets;   vector desktops; +     +    It is a bit annoying to do such duplication in efforts +    With polymorphism, we see how this can be done better +    With the Observer design pattern, we see how such problem is common diff --git a/19-object-oriented-programming/11_homework_09_answer.txt b/19-object-oriented-programming/11_homework_09_answer.txt new file mode 100644 index 0000000..ec5361f --- /dev/null +++ b/19-object-oriented-programming/11_homework_09_answer.txt @@ -0,0 +1,32 @@ +The problem: +- For N banks and M services, we will build N*M software programs. This is Many to Many relationships. +- With every new service, the banks need to wait a lot till the service provide solutions for the banks +- With every new bank, it has to search the market for which services are available. Bank has to implement software per service to communicate +- There will be a lot of time to discuss agreements on commission per transaction +- Code wise, most of the codes will be implemented with several different teams, and there will be a lot of code duplications  + + +The business opportunity: +- Introduce a company that acts as middle players between banks and services +- Each bank builds one software ONLY to contact the middle +    - It asks to get the bills of a specific service to view them to the user +    - If a customer asked to pay a bill, the bank verifies the balance, and send to the middle to mark the bill as paid +- Each service builds one software ONLY to contact the middle +    - It provides the bills to the middle and marks them paid if they are paid +- Middle build N software for banks and M for services +    - This means we now build 2N + 2M software projects not N*M +    - N+M by the middle. As one company, a lot of code can be shared not duplicate +- If there is a new bank, it only needs to build one software from its side to get access directly for M services +- This means the system scales very well +- This is the core idea of Fawry company in Egypt, and similar ones abroad +    - Fawry is a middle layer that takes commissions on transactions that happen through it +     +     +Like any business +- You don't only depend on your elegant solution if it is elegant even :D +- Also a lot of effort to validate your business model, and market it +- Read links in the homework slides + + +Technical question: +- How the middle can avoid duplication in code when say dealing with banks? diff --git a/19-object-oriented-programming/12_01.cpp b/19-object-oriented-programming/12_01.cpp new file mode 100644 index 0000000..2eb88f0 --- /dev/null +++ b/19-object-oriented-programming/12_01.cpp @@ -0,0 +1,50 @@ +#include +using namespace std; + +class Person { +public: + void print() { cout << "Person\n"; } + ~Person() { cout << "~Person\n";} +}; + +class Student: public Person { +public: + void print() { cout << "Student\n"; } + ~Student() { cout << "~Student\n";} +}; + +int main() { + Person person; // first object + Student stud; // 2nd object + + person.print(); + stud.print(); + + // No object construct/deconstruct for the refrence + Person* per_ptr = &person; + Student* stud_ptr1 = &stud; + Person* stud_ptr2 = &stud; + Person* stud_ptr3 = new Student(); // 3rd object + + per_ptr->print(); + stud_ptr1->print(); + stud_ptr2->print(); // Call Person not Student + stud_ptr3->print(); // Call Person not Student + + delete stud_ptr3; // Memory leak + + return 0; +} + +/* +Person +Student +Person +Student +Person +Person +~Person from 3rd object: memory leak: student is not cleaned +~Student from 2nd object: derived +~Person from 2nd object: base +~Person from first object + */ diff --git a/19-object-oriented-programming/12_02.cpp b/19-object-oriented-programming/12_02.cpp new file mode 100644 index 0000000..c191322 --- /dev/null +++ b/19-object-oriented-programming/12_02.cpp @@ -0,0 +1,70 @@ +#include +using namespace std; + +class Person { +public: + virtual void print() { cout << "Person\n"; } + virtual ~Person() { cout << "~Person\n";} +}; + +class Student: public Person { +public: + void print() { cout << "Student\n"; } + ~Student() { cout << "~Student\n";} +}; + + +int main() { + Person* stud_ptr3 = new Student(); + stud_ptr3->print(); + stud_ptr3->Person::print(); // Explicit + + delete stud_ptr3; + + /* +Student +~Student +~Person + * + */ + + return 0; +} + + +int main2() { + Person person; // first object + Student stud; // 2nd object + + person.print(); + stud.print(); + + Person* per_ptr = &person; + Student* stud_ptr1 = &stud; + Person* stud_ptr2 = &stud; + Person* stud_ptr3 = new Student(); // 3rd object + + per_ptr->print(); + stud_ptr1->print(); + stud_ptr2->print(); + stud_ptr3->print(); + + delete stud_ptr3; + + return 0; +} + +/* +Person +Student +Person +Student +Person +Person +~Student from 3rd object: derived +~Person from 3rd object: base +~Student from 2nd object: derived +~Person from 2nd object: base +~Person from first object + + */ diff --git a/19-object-oriented-programming/12_03.cpp b/19-object-oriented-programming/12_03.cpp new file mode 100644 index 0000000..92a74c0 --- /dev/null +++ b/19-object-oriented-programming/12_03.cpp @@ -0,0 +1,47 @@ +#include +using namespace std; + +class A { +public: + virtual void f1() { cout << "A::f1\n"; } // virtual + void f2() { cout << "A::f2\n"; } + void f3() { cout << "A::f3\n"; } +}; + +class B: public A { +public: + void f1() { cout << "B::f1\n"; } // virtual + virtual void f2(){ cout << "B::f2\n"; } // virtual + void f3() { cout << "B::f3\n"; } +}; + +class C: public B { +public: + void f1() { cout << "C::f1\n"; } // virtual + void f2() { cout << "C::f2\n"; } // virtual + virtual void f3() { cout << "C::f3\n"; } +}; + +class D: public C { +public: + void f1() { cout << "D::f1\n"; } // virtual + void f2() { cout << "D::f2\n"; } // virtual + void f3() { cout << "D::f3\n"; } // virtual +}; + +// we should provide virtual destructors to avoid memory leaks + +int main() { + B* d1 = new D(); + d1->f1(); + d1->f2(); + d1->f3(); + cout<<"\n"; + + A* d2 = new D(); + d2->f1(); + d2->f2(); + d2->f3(); + + return 0; +} diff --git a/19-object-oriented-programming/12_04.cpp b/19-object-oriented-programming/12_04.cpp new file mode 100644 index 0000000..74099b1 --- /dev/null +++ b/19-object-oriented-programming/12_04.cpp @@ -0,0 +1,51 @@ +#include +using namespace std; + +class Shape { +private: + string name; +public: + Shape(string name) : + name(name) { + } + + virtual int Area() { + throw logic_error("Not implemented. Do override"); + return -1; + } + + string GetShapeName() { + return name; + } + virtual ~Shape() {} +}; + +class Rectangle: public Shape { + int wid; + int height; +public: + Rectangle(string name, int wid, int height) : + Shape(name), wid(wid), height(height) { + } + int Area() { + return wid * height; + } +}; + +void process(Shape* shape) { + // This function knows nothing about children! + + // Compile time determined + cout << "This shape's name is: " << shape->GetShapeName() << ". "; + + // Run Time determined + cout << "Its area: " << shape->Area() << "\n"; +} + +int main() { + Rectangle r("Nice Rect", 4, 5); + + process(&r); + + return 0; +} diff --git a/19-object-oriented-programming/12_05_package_delivery.cpp b/19-object-oriented-programming/12_05_package_delivery.cpp new file mode 100644 index 0000000..4217748 --- /dev/null +++ b/19-object-oriented-programming/12_05_package_delivery.cpp @@ -0,0 +1,191 @@ +#include +using namespace std; + +class Address { +private: + string name; + string address; + string city; +public: + const string& GetAddress() const { + return address; + } + + void SetAddress(const string& address) { + this->address = address; + } + + const string& GetCity() const { + return city; + } + + void SetCity(const string& city) { + this->city = city; + } + + const string& GetName() const { + return name; + } + + void SetName(const string& name) { + this->name = name; + } +}; + +class Package { +public: + virtual double TotalCost() const = 0; + virtual ~Package() {} +}; + +class StandardPackage : public Package { +private: + Address sender_address; + Address reciever_address; + double weight_kg; + double price_per_kg; + +public: + + StandardPackage(const Address &sender_address, const Address &reciever_address, double weight_kg, double price_per_kg) : + sender_address(sender_address), reciever_address(reciever_address), weight_kg(weight_kg), price_per_kg(price_per_kg) { + } + + double TotalCost() const { + return weight_kg * price_per_kg; + } + + double GetPricePerKg() const { + return price_per_kg; + } + + void SetPricePerKg(double pricePerKg) { + price_per_kg = pricePerKg; + } + + const Address &GetRecieverAddress() const { + return reciever_address; + } + + void SetRecieverAddress(const Address &recieverAddress) { + reciever_address = recieverAddress; + } + + const Address & GetSenderAddress() const { + return sender_address; + } + + void SetSenderAddress(const Address &senderAddress) { + sender_address = senderAddress; + } + + double GetWeightKg() const { + return weight_kg; + } + + void SetWeightKg(double weightKg) { + weight_kg = weightKg; + } +}; + +class TwoDayPackage: public StandardPackage { +private: + double fixed_fee; + +public: + TwoDayPackage(const Address &sender_address, const Address &reciever_address, double weight_kg, double price_per_kg, double fixed_fee) : + StandardPackage(sender_address, reciever_address, weight_kg, price_per_kg), fixed_fee(fixed_fee) { + } + + double TotalCost() const { + return StandardPackage::TotalCost() + fixed_fee; + } + + double GetFixedFee() const { + return fixed_fee; + } + + void SetFixedFee(double fixedFee) { + fixed_fee = fixedFee; + } +}; + +class HeavyPackage: public StandardPackage { +private: + const double limit_kg = 100; + double extra_price_per_kg; + +public: + HeavyPackage(const Address &sender_address, const Address &reciever_address, double weight_kg, double price_per_kg, double extra_price_per_kg) : + StandardPackage(sender_address, reciever_address, weight_kg, price_per_kg), extra_price_per_kg(extra_price_per_kg) { + } + + double TotalCost() const { + double ret = StandardPackage::TotalCost(); + + if (GetWeightKg() > limit_kg) + ret += (GetWeightKg() - limit_kg) * extra_price_per_kg; + return ret; + } + + double GetExtraPricePerKg() const { + return extra_price_per_kg; + } + + void SetExtraPricePerKg(double extraPricePerKg) { + extra_price_per_kg = extraPricePerKg; + } +}; + +class PaymentCard { +private: + string card_number; + double expiry_date; +}; + +class CreditCard: public PaymentCard { +}; + +class DebitCard: public PaymentCard { +}; + +class Shipment { +private: + vector packages; + PaymentCard* payement_card; + +public: + void AddPackage(StandardPackage* package) { + packages.push_back(package); + } + + void SetPaymentCard(PaymentCard* payement_card_) { + payement_card = payement_card_; + } + + double TotalCost() const { + double total = 0; + + for (Package* package : packages) + total += package->TotalCost(); + + return total; + } +}; + +class Customer { +private: + vector shipments; + vector payment_cards; +public: + + void AddShipment() { + + } +}; + +int main() { + + return 0; +} + diff --git a/19-object-oriented-programming/12_06_editor_program.cpp b/19-object-oriented-programming/12_06_editor_program.cpp new file mode 100644 index 0000000..36065c5 --- /dev/null +++ b/19-object-oriented-programming/12_06_editor_program.cpp @@ -0,0 +1,160 @@ +#include +using namespace std; + +class Point { +private: + double x; + double y; +public: + Point(double x, double y) : + x(x), y(y) { + } + double GetX() const { + return x; + } + + void SetX(double x) { + this->x = x; + } + + double GetY() const { + return y; + } + + void SetY(double y) { + this->y = y; + } + + string ToString() const { + ostringstream oss; + oss << "(" << x << ", " << y << ")"; + return oss.str(); + } +}; + +class Shape { +protected: + int color; +public: + Shape(int color) : + color(color) { + } + + virtual int ComputeArea() const { + throw logic_error("Not implemented. Do override"); + return -1; + } + virtual void Draw() const { + // Not implemented now + cout << "Drawing shape of area " << ComputeArea() << "\n"; + } + virtual Shape* Clone() const { // virtual copy constructor + throw logic_error("Not implemented. Do override"); + return nullptr; + } + virtual ~Shape() { + } + + int GetColor() const { + return color; + } + void SetColor(int color) { + this->color = color; + } +}; + +class Rectangle: public Shape { +private: + Point top_left; + Point bottom_right; +public: + Rectangle(int color, const Point &top_left, const Point &bottom_right) : + Shape(color), top_left(top_left), bottom_right(bottom_right) { + } + virtual int ComputeArea() const override { + return 10; // just compute + } + virtual void Draw() const override { + Shape::Draw(); + cout << "Drawing rectangle TL " << top_left.ToString() + << " - BR " << bottom_right.ToString() << "\n"; + } + + virtual Shape* Clone() const { + return new Rectangle(*this); + } +}; + +class Circle: public Shape { +private: + Point center; + double radius; +public: + Circle(int color, const Point ¢er, double radius) : + Shape(color), center(center), radius(radius) { + } + virtual int ComputeArea() const override { + return 20; // just compute + } + virtual void Draw() const override { + Shape::Draw(); + cout << "Drawing circle center " << center.ToString() + << " - radius " << radius << "\n"; + } + virtual Shape* Clone() const { + return new Circle(*this); + } +}; + +class ImageEditor { +protected: + vector shapes; + +public: + void AddShape(const Shape &shape) { + shapes.push_back(shape.Clone()); + } + virtual void Draw() const { + cout << "ImageEditor::Draw\n"; + for (auto shapePtr : shapes) + shapePtr->Draw(); + } + virtual ~ImageEditor() { + for (auto shapePtr : shapes) { + delete shapePtr; + } + shapes.clear(); + } +}; + +class AdobeImageEditor: public ImageEditor { +public: + void EnlargeShpaes(double percent) { + for (auto shapePtr : shapes) { + // Enlarge + } + } +}; + +void initalize(AdobeImageEditor* editor) { + Rectangle r1(10, Point(3, 4), Point(5, 6)); + Circle c1(20, Point(8, 9), 3.5); + + editor->AddShape(r1); + editor->AddShape(c1); +} + +int main() { + AdobeImageEditor* editor = new AdobeImageEditor(); + + initalize(editor); + editor->Draw(); + editor->EnlargeShpaes(0.5); + + delete editor; + editor = nullptr; + + cout << "Bye"; + + return 0; +} diff --git a/19-object-oriented-programming/12_07.cpp b/19-object-oriented-programming/12_07.cpp new file mode 100644 index 0000000..dff7008 --- /dev/null +++ b/19-object-oriented-programming/12_07.cpp @@ -0,0 +1,24 @@ +#include +using namespace std; + +class A { +public: + virtual void f1(int x = 1) { + cout<f1(); // 1 in B + + return 0; +} diff --git a/19-object-oriented-programming/12_homework_01_answer.txt b/19-object-oriented-programming/12_homework_01_answer.txt new file mode 100644 index 0000000..770bf1c --- /dev/null +++ b/19-object-oriented-programming/12_homework_01_answer.txt @@ -0,0 +1,9 @@ +Reading https://www.codeproject.com/Articles/34125/Chapter-10-Object-Oriented-Programming-Polymorphis + from Software Engineering Case Study: Incorporating Inheritance into the ATM System + +In summary + ATM composed of 4 hardware components + It can execute a transaction (polymorphism), which can be one 3 types. + Deposit & Withdraw each is associated with a hardware + ATM need to interact with Database to verify the login account + Also transaction needs some database ID for operation + change balance diff --git a/19-object-oriented-programming/12_homework_02_answer.txt b/19-object-oriented-programming/12_homework_02_answer.txt new file mode 100644 index 0000000..3fbf7fd --- /dev/null +++ b/19-object-oriented-programming/12_homework_02_answer.txt @@ -0,0 +1,18 @@ +- The engineer though: Square is a rectangle with all sides equal +- This is good for a square class +- But in a polymorphism setup, a square object is sent to a rectangle object +- Then this rectangle can do change for width/height +- We then end up with a corrupted square status! + +- Tip: Make sure your sub-class is really a valid superclass. This is related to the Liskov Substitution Principle + +- The right way is a composition +- Square class has an instance of type Rectangle +- Delegate all calls to a rectangle +- Now we are safe, without the need for inheritance between rectangle and square + + + + + +https://effectivesoftwaredesign.com/2010/09/20/when-a-square-is-not-a-rectangle/#:~:text=Let's%20say%20that%20we%20organize,a%2Dkind%2Dof%20relationship. diff --git a/19-object-oriented-programming/12_homework_03_answer.cpp b/19-object-oriented-programming/12_homework_03_answer.cpp new file mode 100644 index 0000000..ed0014e --- /dev/null +++ b/19-object-oriented-programming/12_homework_03_answer.cpp @@ -0,0 +1,161 @@ +#include +using namespace std; + +class Payable { +public: + virtual double GetAmountToPay() const {} + virtual ~Payable() { + } +}; + +class StaffMember: public Payable { +private: + string name; + string address; +public: +}; + +class Employee: public StaffMember { +private: + int day_to_pay; +public: + +}; + +class HourlyEmployee: public Employee { +private: + int total_working_hours; + double salary_per_hour; +public: + virtual double GetAmountToPay() const override { + cout << "HourlyEmployee\n"; + return total_working_hours * salary_per_hour; + } +}; + +class SalariedEmployee: public Employee { +private: + double monthly_salary; +public: + virtual double GetAmountToPay() const override { + cout << "SalariedEmployee\n"; + return monthly_salary; + } +}; + +class CommisionSalariedEmployee: public SalariedEmployee { +private: + double commision_rate; + double current_month_sales; +public: + virtual double GetAmountToPay() const override { + cout << "CommisionSalariedEmployee\n"; + return SalariedEmployee::GetAmountToPay() + current_month_sales * commision_rate; + } +}; + +class Volunteer: public StaffMember { +private: + int current_payment; +public: + virtual double GetAmountToPay() const override { + return current_payment; + } +}; + +class Item { +private: + string desc; + double price; + int quantity; +public: + double GetPrice() const { + return price * quantity; + } +}; + +class Book: public Item { +private: + string author; +}; + +class Food: public Item { +private: + string expiration_date; +}; + +class Invoice: public Payable { +private: + int invoice_id = -1; + vector items; +public: + void AddItem(Item* item) { + items.push_back(item); + } + + virtual double GetAmountToPay() const override { + cout << "Invoice\n"; + + double sum = 0; + for (const Item* item_ptr : items) + sum += item_ptr->GetPrice(); + return sum; + } +}; + +class Payroll { +private: + vector payables; + +public: + void AddPayable(Payable* payable) { + payables.push_back(payable); // we should add copy + } + void Pay() { + cout << "Payroll::Pay\n"; + ; + for (const auto payable : payables) + payable->GetAmountToPay(); + } +}; + +class Company { +private: + Payroll payroll; +public: + Company() { + } + + void Run() { + payroll.AddPayable(new Volunteer()); + payroll.AddPayable(new HourlyEmployee()); + payroll.AddPayable(new SalariedEmployee()); + payroll.AddPayable(new CommisionSalariedEmployee()); + + Invoice* invoice = new Invoice(); + invoice->AddItem(new Book()); + invoice->AddItem(new Food()); + + payroll.AddPayable(invoice); + + payroll.Pay(); + } +}; + +int main() { + Company company; + company.Run(); + + return 0; +} + +/* + +Payroll::Pay +HourlyEmployee +SalariedEmployee +CommisionSalariedEmployee +SalariedEmployee +Invoice + + */ diff --git a/19-object-oriented-programming/13_01.cpp b/19-object-oriented-programming/13_01.cpp new file mode 100644 index 0000000..2fc098d --- /dev/null +++ b/19-object-oriented-programming/13_01.cpp @@ -0,0 +1,128 @@ +#include +using namespace std; + +class IDevice { +}; + +class ICameraDevice: public IDevice { +public: + virtual string GetVersion() = 0; + virtual bool Start() = 0; + virtual bool Stop() = 0; + virtual ~ICameraDevice() {} +}; + +class UbuntuDriverOpenSource: public ICameraDevice { +public: + string GetVersion() { return "Ubuntu OpenSource"; } + bool Start() { return true; } + bool Stop() { return false; } + ~UbuntuDriverOpenSource() { } +}; + +class UbuntuDriver3rdParty: public ICameraDevice { +public: + string GetVersion() { return "Ubuntu 3rdParty"; } + bool Start() { return true; } + bool Stop() { return false; } + ~UbuntuDriver3rdParty() { + } +}; + +class UbuntuDriverWindows10: public ICameraDevice { +public: + string GetVersion() { + return "Microsot Windows 10"; + } + bool Start() { + return true; + } + bool Stop() { + return false; + } + ~UbuntuDriverWindows10() { + } +}; + +class App { +protected: + string app_info; +public: + virtual void Run() = 0; + virtual void Shutdown() { } + virtual ~App() { } +}; + +class CameraAppCheese: public App { +private: + ICameraDevice* camera; +public: + CameraAppCheese(ICameraDevice* camera) :camera(camera) { } + + void Run() { + // record images/videos + for (int i = 0; i < 5; ++i) { + cout << "CameraAppCheese - I am fast\n"; + } + } + ~CameraAppCheese() { } +}; + +class CameraAppKamoso: public App { +private: + ICameraDevice* camera; +public: + CameraAppKamoso(ICameraDevice* camera) : + camera(camera) { + } + + void Run() { + // record images/videos + for (int i = 0; i < 5; ++i) { + cout << "CameraAppKamoso - I am slow\n"; + } + } + ~CameraAppKamoso() { + } +}; + +class UbuntuOS { +private: + vector devices; + vector apps; +public: + App* GetCameraApp(string app_name) { + ICameraDevice* driver = new UbuntuDriverOpenSource(); + App* app = nullptr; + + if (app_name == "Cheese") app = new CameraAppCheese(driver); + else if (app_name == "Kamoso") app = new CameraAppKamoso(driver); + else return nullptr; + + devices.push_back(driver); + apps.push_back(app); + return app; + } + void Shutdown() { + for (App* app : apps) app->Shutdown(); + } + ~UbuntuOS() { + cout << "OS Terminate\n"; + Shutdown(); + for (App* app : apps) delete app; + apps.clear(); + for (IDevice* device : devices) delete device; + devices.clear(); + } +}; + +int main() { + UbuntuOS os; + + App* app = os.GetCameraApp("Cheese"); + + if (app != nullptr) + app->Run(); + + return 0; +} diff --git a/19-object-oriented-programming/13_02.cpp b/19-object-oriented-programming/13_02.cpp new file mode 100644 index 0000000..e69de29 diff --git a/19-object-oriented-programming/13_03.cpp b/19-object-oriented-programming/13_03.cpp new file mode 100644 index 0000000..6c34b85 --- /dev/null +++ b/19-object-oriented-programming/13_03.cpp @@ -0,0 +1,34 @@ +#include +using namespace std; + + +class Printable { +public: + virtual void Print() const = 0; + virtual ~Printable() { + } +}; + + +class Cloneable { +public: + // function to clone + virtual ~Cloneable() { + } +}; + +class Person : public Printable, + public Cloneable { + +}; + +class Employee : public Person { + +}; + +int main() { + + + return 0; +} + diff --git a/19-object-oriented-programming/13_04.cpp b/19-object-oriented-programming/13_04.cpp new file mode 100644 index 0000000..9da51b4 --- /dev/null +++ b/19-object-oriented-programming/13_04.cpp @@ -0,0 +1,52 @@ +#include +using namespace std; + +class A { // must be virtual to cast +public: + virtual ~A() { } +}; +class B: public A {}; +class C: public A {}; +class D {}; + +void dynamic_cast_test() { + // Run time conversion using RTTI + A* a_from_b = new B(); + + // No problem. Valid conversion + B* b = dynamic_cast(a_from_b); + cout<(a_from_b); + cout<(a_from_b); + cout<(a_from_b); + cout<(a_from_b); + cout<(a_from_b); +} + + + +int main() { + dynamic_cast_test(); + + return 0; +} + diff --git a/19-object-oriented-programming/13_homework_01_answer.cpp b/19-object-oriented-programming/13_homework_01_answer.cpp new file mode 100644 index 0000000..2a7a99b --- /dev/null +++ b/19-object-oriented-programming/13_homework_01_answer.cpp @@ -0,0 +1,229 @@ +#include +using namespace std; + +class Payable { +public: + virtual double GetAmountToPay() const = 0; + virtual ~Payable() { + } +}; + +class StaffMember: public Payable { +private: + string name; + string address; +public: +}; + +class Employee: public StaffMember { +private: + int day_to_pay; +public: + +}; + +class HourlyEmployee: public Employee { +private: + int total_working_hours; + double salary_per_hour; +public: + virtual double GetAmountToPay() const override { + cout << "HourlyEmployee\n"; + return total_working_hours * salary_per_hour; + } +}; + +class SalariedEmployee: public Employee { +private: + double monthly_salary; +public: + virtual double GetAmountToPay() const override { + cout << "SalariedEmployee\n"; + return monthly_salary; + } +}; + +class CommisionSalariedEmployee: public SalariedEmployee { +private: + double commision_rate; + double current_month_sales; +public: + virtual double GetAmountToPay() const override { + cout << "CommisionSalariedEmployee\n"; + return SalariedEmployee::GetAmountToPay() + current_month_sales * commision_rate; + } +}; + +class Volunteer: public StaffMember { +private: + int current_payment; +public: + virtual double GetAmountToPay() const override { + return current_payment; + } +}; + +class Item { +private: + string desc; + double price; + int quantity; +public: + double GetPrice() const { + return price * quantity; + } +}; + +class Book: public Item { +private: + string author; +}; + +class Food: public Item { +private: + string expiration_date; +}; + +class Invoice; + +class VaidationRule { +public: + virtual bool ValidateRule(const Invoice* const invoice) = 0; + virtual ~VaidationRule() {} +}; + +class InvoiceValidator { +protected: + vector rules; +public: + virtual bool ValidateInvoice(const Invoice* const invoice) { + cout << "Validator\n"; + for (const auto rule_ptr : rules) + rule_ptr->ValidateRule(invoice); // ask child: inverse of control + } + virtual ~InvoiceValidator() { + } +}; + +class Invoice: public Payable { +private: + int invoice_id = -1; + vector items; + InvoiceValidator* validator; // doesn't know which validator/rule +public: + Invoice(InvoiceValidator* validator) : + validator(validator) { + } + + void AddItem(Item* item) { + items.push_back(item); + } + + virtual double GetAmountToPay() const override { + cout << "Invoice\n"; + validator->ValidateInvoice(this); + + double sum = 0; + for (const Item* item_ptr : items) + sum += item_ptr->GetPrice(); + return sum; + } +}; + +class TaxesVaidationRule: public VaidationRule { +public: + virtual bool ValidateRule(const Invoice* const invoice) { + cout << "Tax Validation rule\n"; + return true; + } +}; + +class SuppliersDealsVaidationRule: public VaidationRule { +public: + virtual bool ValidateRule(const Invoice* const invoice) { + cout << "Suppliers deals validation rule\n"; + return true; + } +}; + +class MandatoryInvoiceValidator: public InvoiceValidator { +public: + MandatoryInvoiceValidator() { // could be singleton + rules.push_back(new TaxesVaidationRule()); + } +}; + +class CompleteInvoiceValidator: public InvoiceValidator { +public: + CompleteInvoiceValidator() { // could be singleton + rules.push_back(new TaxesVaidationRule()); + rules.push_back(new SuppliersDealsVaidationRule()); + } +}; + +class Payroll { +private: + vector payables; + +public: + void AddPayable(Payable* payable) { + payables.push_back(payable); // we should add copy + } + void Pay() { + cout << "Payroll::Pay\n"; + ; + for (const auto payable : payables) + payable->GetAmountToPay(); + } +}; + +class Company { +private: + bool is_use_complete_validations = true; + InvoiceValidator* validator = nullptr; + Payroll payroll; +public: + Company() { + if (is_use_complete_validations) + validator = new CompleteInvoiceValidator(); + else + validator = new MandatoryInvoiceValidator(); + } + + void Run() { + payroll.AddPayable(new Volunteer()); + payroll.AddPayable(new HourlyEmployee()); + payroll.AddPayable(new SalariedEmployee()); + payroll.AddPayable(new CommisionSalariedEmployee()); + + Invoice* invoice = new Invoice(validator); + invoice->AddItem(new Book()); + invoice->AddItem(new Food()); + + payroll.AddPayable(invoice); + + payroll.Pay(); + } +}; + +int main() { + Company company; + company.Run(); + + return 0; +} + +/* + +Payroll::Pay +HourlyEmployee +SalariedEmployee +CommisionSalariedEmployee +SalariedEmployee +Invoice +Validator +Tax Validation rule +Suppliers deals validation rule + + + */ diff --git a/19-object-oriented-programming/13_homework_02_answer.cpp b/19-object-oriented-programming/13_homework_02_answer.cpp new file mode 100644 index 0000000..123e182 --- /dev/null +++ b/19-object-oriented-programming/13_homework_02_answer.cpp @@ -0,0 +1,111 @@ +#include +using namespace std; + +class Reservation { +public: + virtual double TotalCost() const = 0; + + virtual Reservation* Clone() const = 0; + + virtual ~Reservation() { + } +}; + +class FlightReservation: public Reservation { +private: + // Some data + +public: + FlightReservation(string several_parms = "") { + } + + virtual FlightReservation* Clone() const override { + return new FlightReservation(*this); + } + + virtual double TotalCost() const override { + return 2000; + } +}; + +class HotelReservation: public Reservation { +private: + int price_per_night; + int total_nights; + +public: + HotelReservation(int price_per_night, int total_nights) : + price_per_night(price_per_night), total_nights(total_nights) { + } + + virtual HotelReservation* Clone() const override { + return new HotelReservation(*this); + } + + virtual double TotalCost() const override { + return price_per_night * total_nights; + } +}; + +class ItineraryReservation: public Reservation { +protected: + vector reservations; // As has pointers, we need copy constructor + +public: + ItineraryReservation() { + } + + ItineraryReservation(const ItineraryReservation& another_reservation) { // copy constructor + for (const Reservation* reservation : another_reservation.GetReservations()) + AddReservation(*reservation); + } + + void AddReservation(const Reservation& reservation) { + reservations.push_back(reservation.Clone()); + } + + virtual double TotalCost() const { + double cost = 0; + + for (const Reservation* reservation : reservations) + cost += reservation->TotalCost(); + + return cost; + } + + ~ItineraryReservation() { + Clear(); + } + + const vector& GetReservations() const { + return reservations; + } + + void Clear() { + for (const Reservation* reservation : reservations) + delete reservation; + reservations.clear(); + } + + virtual Reservation* Clone() const override { + return new ItineraryReservation(*this); + } +}; + +ItineraryReservation Make_ititinary() { + ItineraryReservation itinerary; + + itinerary.AddReservation(FlightReservation()); + itinerary.AddReservation(FlightReservation()); + itinerary.AddReservation(HotelReservation(50, 2)); + + return itinerary; +} + +int main() { + ItineraryReservation itinerary = Make_ititinary(); + cout << itinerary.TotalCost(); // 4100 = 2000 + 2000 + 100 + + return 0; +} + diff --git a/19-object-oriented-programming/13_homework_03.cpp b/19-object-oriented-programming/13_homework_03.cpp new file mode 100644 index 0000000..e9f04da --- /dev/null +++ b/19-object-oriented-programming/13_homework_03.cpp @@ -0,0 +1,68 @@ +#include +using namespace std; + +// PayPalCreditCard and PayPalOnlinePaymentAPI are NOT our code. They are Paypal API. +// We have to use them to be able to call PayPal service + + +class PayPalCreditCard { +public: + string name; + string address; + string id; + string expire_date; + int ccv; +}; + +class PayPalOnlinePaymentAPI { +public: + void SetCardInfo(const PayPalCreditCard* const card) { + } + bool MakePayment(double money) { + return true; + } +}; + +class StripeUserInfo { +public: + string name; + string address; +}; + +class StripeCardInfo { +public: + string id; + string expire_date; +}; + +class StripePaymentAPI { +public: + bool static WithDrawMoney(StripeUserInfo user, + StripeCardInfo card, + double money) { + return true; + } +}; + +class TransactionInfo { +public: + double required_money_amount; + string name; + string address; + string id; + string expire_date; + int ccv; +}; + +class Craigslist { + public: + bool Pay(TransactionInfo) { + //TODO: generic (no nothing about Paypal) + } +}; + + +int main() +{ + return 0; +} diff --git a/19-object-oriented-programming/13_homework_03_answer.cpp b/19-object-oriented-programming/13_homework_03_answer.cpp new file mode 100644 index 0000000..5e12395 --- /dev/null +++ b/19-object-oriented-programming/13_homework_03_answer.cpp @@ -0,0 +1,144 @@ +#include +using namespace std; + +// Below: What we did with payments satisfies Dependency inversion principle +// High-level modules (wesite class) should not depend on low-level modules (PaypalPayment APIs). +// Both should depend on abstractions (e.g. IPayment). + + +class PayPalCreditCard { +public: + string name; + string address; + string id; + string expire_date; + int ccv; +}; + +class PayPalOnlinePaymentAPI { +public: + void SetCardInfo(const PayPalCreditCard* const card) { + } + bool MakePayment(double money) { + return true; + } +}; + +class StripeUserInfo { +public: + string name; + string address; +}; + +class StripeCardInfo { +public: + string id; + string expire_date; +}; + +class StripePaymentAPI { +public: + bool static WithDrawMoney(StripeUserInfo user, + StripeCardInfo card, + double money) { + return true; + } +}; + +///////////////////// +class IPayment { +public: + virtual void SetUserInfo(string name, string address) = 0; + virtual void SetCardInfo(string id, string expire_date, int ccv) = 0; + virtual bool MakePayment(double money) = 0; + virtual ~IPayment() { + } +}; + +class PayPalPayment: public IPayment { +private: + PayPalOnlinePaymentAPI paypal; + PayPalCreditCard card; +public: + virtual void SetUserInfo(string name, string address) { + card.name = name; + card.address = address; + } + virtual void SetCardInfo(string id, string expire_date, int ccv) { + card.id = id; + card.expire_date = expire_date; + card.ccv = ccv; + } + virtual bool MakePayment(double money) { + paypal.SetCardInfo(&card); + return paypal.MakePayment(money); + } +}; + +class StripePayment: public IPayment { +private: + StripeCardInfo card; + StripeUserInfo user; +public: + virtual void SetUserInfo(string name, string address) { + user.name = name; + user.address = address; + } + virtual void SetCardInfo(string id, string expire_date, int ccv) { + card.id = id; + card.expire_date = expire_date; + } + virtual bool MakePayment(double money) { + return StripePaymentAPI::WithDrawMoney(user, card, money); + } +}; + +class Factory { +public: + // In single place, gather all payments + // In future a change happens here + // Called Factory method design pattern + static IPayment* GetPaymentHelper() { + if (true) + return new PayPalPayment(); + else + return new StripePayment(); + } +}; +////////////////////////////// + +class TransactionInfo { +public: + double required_money_amount; + string name; + string address; + string id; + string expire_date; + int ccv; +}; + +class Craigslist { +private: + IPayment* payment; + +public: + Craigslist() { + // Craigslist knows nothing about PayPal + payment = Factory::GetPaymentHelper(); + } + + bool Pay(TransactionInfo info) { + payment->SetUserInfo(info.name, info.address); + payment->SetCardInfo(info.id, info.expire_date, info.ccv); + return payment->MakePayment(info.required_money_amount); + } +}; + + +int main() { + TransactionInfo info = { 20.5, "mostafa", "canada", "11-22-33-44", "09-2021", 333 }; + Craigslist site; + site.Pay(info); + + return 0; +} diff --git a/19-object-oriented-programming/13_homework_04_answer.cpp b/19-object-oriented-programming/13_homework_04_answer.cpp new file mode 100644 index 0000000..f7373fd --- /dev/null +++ b/19-object-oriented-programming/13_homework_04_answer.cpp @@ -0,0 +1,195 @@ +#include +using namespace std; + +#include "json.hpp" +using namespace json; + +// Below: What we did with payments satisfies Dependency inversion principle +// High-level modules (wesite class) should not depend on low-level modules (PaypalPayment APIs). +// Both should depend on abstractions (e.g. IPayment). + + +class PayPalCreditCard { +public: + string name; + string address; + string id; + string expire_date; + int ccv; +}; + +class PayPalOnlinePaymentAPI { +public: + void SetCardInfo(const PayPalCreditCard* const card) { + } + bool MakePayment(double money) { + return true; + } +}; + +class StripeUserInfo { +public: + string name; + string address; +}; + +class StripeCardInfo { +public: + string id; + string expire_date; +}; + +class StripePaymentAPI { +public: + bool static WithDrawMoney(StripeUserInfo user, + StripeCardInfo card, + double money) { + return true; + } +}; + +class SquarePaymentAPI { +public: + bool static WithDrawMoney(string JsonQuery) { + //cout << JsonQuery << "\n"; + json::JSON obj = JSON::Load(JsonQuery); + return true; + } +}; + +///////////////////// +class IPayment { +public: + virtual void SetUserInfo(string name, string address) = 0; + virtual void SetCardInfo(string id, string expire_date, int ccv) = 0; + virtual bool MakePayment(double money) = 0; + virtual ~IPayment() { + } +}; + +class PayPalPayment: public IPayment { +private: + PayPalOnlinePaymentAPI paypal; + PayPalCreditCard card; +public: + virtual void SetUserInfo(string name, string address) { + card.name = name; + card.address = address; + } + virtual void SetCardInfo(string id, string expire_date, int ccv) { + card.id = id; + card.expire_date = expire_date; + card.ccv = ccv; + } + virtual bool MakePayment(double money) { + paypal.SetCardInfo(&card); + return paypal.MakePayment(money); + } +}; + +class StripePayment: public IPayment { +private: + StripeCardInfo card; + StripeUserInfo user; +public: + virtual void SetUserInfo(string name, string address) { + user.name = name; + user.address = address; + } + virtual void SetCardInfo(string id, string expire_date, int ccv) { + card.id = id; + card.expire_date = expire_date; + } + virtual bool MakePayment(double money) { + return StripePaymentAPI::WithDrawMoney(user, card, money); + } +}; + +class SquarePayment: public IPayment { +private: + string name; + string address; + string id; + string expiry_date; + int ccv; + +public: + virtual void SetUserInfo(string name_, string address_) { + name = name_; + address = address_; + } + virtual void SetCardInfo(string id_, string expiry_date_, int ccv_) { + id = id_; + expiry_date = expiry_date_; + ccv = ccv_; + } + virtual bool MakePayment(double money) { + // This now similar to Adapter pattern. We change format of interface to match another interface + json::JSON obj; + obj["user_info"] = json::Array(name, address); + obj["card_info"]["ID"] = id; + obj["card_info"]["DATE"] = expiry_date; + obj["card_info"]["CCV"] = ccv; + obj["money"] = money; + + ostringstream oss; + oss << obj; + string json_query = oss.str(); + + return SquarePaymentAPI::WithDrawMoney(json_query); + } +}; + + +class PaymentFactory { +public: + // In single place, gather all payments + // In future a change happens here + // Called Factory method design pattern + static IPayment* GetPaymentHelper() { + if (true) + return new SquarePayment(); + else if (true) + return new PayPalPayment(); + else + return new StripePayment(); + } +}; + +////////////////////////////// + +class TransactionInfo { +public: + double required_money_amount; + string name; + string address; + string id; + string expire_date; + int ccv; +}; + +class Craigslist { +private: + IPayment* payment; + +public: + Craigslist() { + // Craigslist knows nothing about PayPal + payment = PaymentFactory::GetPaymentHelper(); + } + + bool Pay(TransactionInfo info) { + payment->SetUserInfo(info.name, info.address); + payment->SetCardInfo(info.id, info.expire_date, info.ccv); + return payment->MakePayment(info.required_money_amount); + } +}; + + +int main() { + TransactionInfo info = { 20.5, "mostafa", "canada", "11-22-33-44", "09-2021", 333 }; + Craigslist site; + site.Pay(info); + + return 0; +} diff --git a/19-object-oriented-programming/13_homework_05_answer.cpp b/19-object-oriented-programming/13_homework_05_answer.cpp new file mode 100644 index 0000000..a23f8c8 --- /dev/null +++ b/19-object-oriented-programming/13_homework_05_answer.cpp @@ -0,0 +1,204 @@ +#include +using namespace std; + +/* + * Why virtual public Object not just public Object? + * As Object will be visible from many inheritance. Virtual keyword make it once only. + */ +class Object { // make it a polymorphic class +public: + virtual string GetClassName() const = 0; + + virtual ~Object() { + } +}; + +class Cloneable: virtual public Object { +public: + virtual Object* Clone() const = 0; + virtual ~Cloneable() { + } +}; + +class Printable: virtual public Object { +public: + virtual void Print() const = 0; + virtual ~Printable() { + } +}; + +class Comparable: virtual public Object { +public: + // Comparable needs some class + // But if we provided specific class (e.g. employee) we have to make one comparable class for every type! + // Work around: create parent object class for all comparable classes. + virtual bool Compare(Object* obj) const = 0; + virtual ~Comparable() { + } +}; + +class Payable: public Cloneable, public Printable, public Comparable { +public: + virtual double GetAmountToPay() const = 0; + virtual ~Payable() { + } +}; + +class Employee: public Payable { +private: + double salary; + string name; +public: + Employee(double salary, string name) : + salary(salary), name(name) { + } + + virtual string GetClassName() const override { + return "Employee"; + } + + virtual Object* Clone() const override { + return new Employee(*this); // Default copy constructor is good, as no internal pointers so far + } + + virtual void Print() const override { + cout << "Employee " << name << " has salary " << salary << "\n"; + } + + double GetAmountToPay() const override { + return salary; + } + + virtual bool Compare(Object* obj) const override { + //Employee* another = (Employee*)obj; // can't castdown directly + + Employee* another_ptr = nullptr; + if ((another_ptr = dynamic_cast(obj))) + return tie(salary, name) < tie(another_ptr->salary, another_ptr->name); + else + return false; // Not an employee! + } +}; + +class Invoice: public Payable { +private: + double cost; +public: + Invoice(double cost) : + cost(cost) { + } + + virtual string GetClassName() const override { + return "Invoice"; + } + + virtual Object* Clone() const override { + return new Invoice(*this); + } + + virtual void Print() const override { + cout << "Invoice cost " << cost << "\n"; + } + + double GetAmountToPay() const override { + return cost; + } + + virtual bool Compare(Object* obj) const override { + Invoice* another_ptr = nullptr; + if ((another_ptr = dynamic_cast(obj))) + return cost < another_ptr->cost; + else + return false; + } +}; + +class Sortable: virtual public Object { +public: + virtual void OrderItems() = 0; + virtual ~Sortable() { + } +}; + +bool Compare(Payable* obj1, Payable* obj2) { + if (obj1->GetClassName() != obj2->GetClassName()) + return obj1->GetClassName() < obj2->GetClassName(); + + return obj1->Compare(obj2); +} + +class CompanyPayroll: public Printable, public Sortable { +private: + vector payables; + +public: + CompanyPayroll() { + } + // Prevent copy constructor + CompanyPayroll(const CompanyPayroll&) = delete; + // Prevent assignment operator + void operator=(const CompanyPayroll&) = delete; + + void AddPayable(const Payable& payable) { + payables.push_back(dynamic_cast(payable.Clone())); + } + + virtual string GetClassName() const override { + return "CompanyPayroll"; + } + + virtual void Print() const override { + double to_pay_sum = 0; + + for (auto payable : payables) { + payable->Print(); + to_pay_sum += payable->GetAmountToPay(); + } + + cout << "Total to be paid: " << to_pay_sum << "\n"; + } + + virtual void OrderItems() override { + // Sort modifies content. This function CAN'T be const + // Try to make const. See the log :( + sort(payables.begin(), payables.end(), Compare); + } + + ~CompanyPayroll() { + + for (auto payable : payables) + delete payable; + payables.clear(); + } +}; + +void test() { + CompanyPayroll payroll; + + payroll.AddPayable(Employee(50, "mostafa")); + payroll.AddPayable(Invoice(200)); + payroll.AddPayable(Employee(10, "ziad")); + payroll.AddPayable(Invoice(100)); + payroll.AddPayable(Employee(30, "belal")); + payroll.AddPayable(Invoice(300)); + + payroll.OrderItems(); + payroll.Print(); // Notice ordered + + /* +Employee ziad has salary 10 +Employee belal has salary 30 +Employee mostafa has salary 50 +Invoice cost 100 +Invoice cost 200 +Invoice cost 300 +Total to be paid: 690 + */ +} + +int main() { + test(); + + return 0; +} + diff --git a/19-object-oriented-programming/14_01.cpp b/19-object-oriented-programming/14_01.cpp new file mode 100644 index 0000000..be431cf --- /dev/null +++ b/19-object-oriented-programming/14_01.cpp @@ -0,0 +1,51 @@ +#include +using namespace std; + +class MyPair { +private: + int first, second; + +public: + MyPair(int first, int second) : + first(first), second(second) { + } + + MyPair Add(const MyPair &c2) { + MyPair &c1 = *this; + return MyPair(c1.GetFirst() + c2.GetFirst(), + c1.GetSecond() + c2.GetSecond()); + } + + MyPair operator +(const MyPair &c2) { + MyPair &c1 = *this; + return MyPair(c1.GetFirst() + c2.GetFirst(), + c1.GetSecond() + c2.GetSecond()); + } + + void print() { + cout << "(" << first << "," << second << ")\n"; + } + int GetFirst() const { + return first; + } + void SetFirst(int first) { + this->first = first; + } + int GetSecond() const { + return second; + } + void SetSecond(int second) { + this->second = second; + } +}; + +int main() { + MyPair x(1, 2); + MyPair y(10, 20); + + //MyPair z = x.Add(y); + MyPair z = x + y; + z.print(); // (11,22) + + return 0; +} diff --git a/19-object-oriented-programming/14_02.cpp b/19-object-oriented-programming/14_02.cpp new file mode 100644 index 0000000..c6de606 --- /dev/null +++ b/19-object-oriented-programming/14_02.cpp @@ -0,0 +1,50 @@ +#include +using namespace std; + +class MyPair { +private: + int first, second; + +public: + MyPair(int first, int second) : + first(first), second(second) { + } + + MyPair Add(const MyPair &c2) { + MyPair &c1 = *this; + return MyPair(c1.GetFirst() + c2.GetFirst(), + c1.GetSecond() + c2.GetSecond()); + } + + void print() { + cout << "(" << first << "," << second << ")\n"; + } + int GetFirst() const { + return first; + } + void SetFirst(int first) { + this->first = first; + } + int GetSecond() const { + return second; + } + void SetSecond(int second) { + this->second = second; + } +}; + +MyPair operator +(const MyPair &c1, const MyPair &c2) { + return MyPair(c1.GetFirst() + c2.GetFirst(), + c1.GetSecond() + c2.GetSecond()); +} + +int main() { + MyPair x(1, 2); + MyPair y(10, 20); + + //MyPair z = x.Add(y); + MyPair z = x + y; + z.print(); // (11,22) + + return 0; +} diff --git a/19-object-oriented-programming/14_03.cpp b/19-object-oriented-programming/14_03.cpp new file mode 100644 index 0000000..32ae60b --- /dev/null +++ b/19-object-oriented-programming/14_03.cpp @@ -0,0 +1,32 @@ +#include +using namespace std; + +class MyPair { +private: + int first, second; + +public: + MyPair(int first, int second) : + first(first), second(second) { + } + void print() { + cout << "(" << first << "," << second << ")\n"; + } + friend MyPair operator +(const MyPair &c1, const MyPair &c2); +}; + +MyPair operator +(const MyPair &c1, const MyPair &c2) { + return MyPair(c1.first + c2.first, + c1.second + c2.second); +} + +int main() { + MyPair x(1, 2); + MyPair y(10, 20); + + //MyPair z = x.Add(y); + MyPair z = x + y; + z.print(); // (11,22) + + return 0; +} diff --git a/19-object-oriented-programming/14_04.cpp b/19-object-oriented-programming/14_04.cpp new file mode 100644 index 0000000..912f288 --- /dev/null +++ b/19-object-oriented-programming/14_04.cpp @@ -0,0 +1,66 @@ +#include +using namespace std; + +class MyPair { +private: + int first, second; + +public: + MyPair(int first, int second) : + first(first), second(second) { + } + + MyPair Add(const MyPair &c2) { + MyPair &c1 = *this; + return MyPair(c1.GetFirst() + c2.GetFirst(), c1.GetSecond() + c2.GetSecond()); + } + + void print() { + cout << "(" << first << "," << second << ")\n"; + } + int GetFirst() const { + return first; + } + void SetFirst(int first) { + this->first = first; + } + int GetSecond() const { + return second; + } + void SetSecond(int second) { + this->second = second; + } +}; + +MyPair operator +(const MyPair &c1, const MyPair &c2) { + return MyPair(c1.GetFirst() + c2.GetFirst(), + c1.GetSecond() + c2.GetSecond()); +} +MyPair operator +(const MyPair &c1, int x) { + return MyPair(c1.GetFirst() + x, + c1.GetSecond() + x); +} +MyPair operator *(int x, const MyPair &c1) { + return MyPair(c1.GetFirst() * x, + c1.GetSecond() * x); +} +MyPair operator -(const MyPair &c1, pair p) { + return MyPair(c1.GetFirst() - p.first, + c1.GetSecond() - p.second); +} + +int main() { + pair p = make_pair(1, 3); + MyPair x(1, 2); + MyPair z1 = x + 5; // CE: 5+x + MyPair z2 = 3 * x; // CE: x * 3 + MyPair z3 = x - p; // CE: p - x + z1.print(); // (6,7) + z2.print(); // (3,6) + z3.print(); // (0,-1) + + MyPair z4 = 3 * x + 5 + x; + z4.print(); // (9,13) + + return 0; +} diff --git a/19-object-oriented-programming/14_05.cpp b/19-object-oriented-programming/14_05.cpp new file mode 100644 index 0000000..9825f99 --- /dev/null +++ b/19-object-oriented-programming/14_05.cpp @@ -0,0 +1,48 @@ +#include +using namespace std; + +class MyPair { +private: + int first, second; + +public: + MyPair(int first, int second) : + first(first), second(second) { + } + + MyPair Add(const MyPair &c2) { + MyPair &c1 = *this; + return MyPair(c1.GetFirst() + c2.GetFirst(), c1.GetSecond() + c2.GetSecond()); + } + + void print() { + cout << "(" << first << "," << second << ")\n"; + } + int GetFirst() const { + return first; + } + void SetFirst(int first) { + this->first = first; + } + int GetSecond() const { + return second; + } + void SetSecond(int second) { + this->second = second; + } + + MyPair operator !() { + cout<<"Here\n"; + MyPair &c1 = *this; + return MyPair(-1 * c1.GetFirst(), + -1 * c1.GetSecond()); + } +}; + +int main() { + MyPair x(1, 2); + x = !x; + x.print(); // (-1,-2) + + return 0; +} diff --git a/19-object-oriented-programming/14_06.cpp b/19-object-oriented-programming/14_06.cpp new file mode 100644 index 0000000..e076d02 --- /dev/null +++ b/19-object-oriented-programming/14_06.cpp @@ -0,0 +1,59 @@ +#include +using namespace std; + +class MyPair { +private: + int first, second; + +public: + MyPair(int first, int second) : + first(first), second(second) { + } + + MyPair Add(const MyPair &c2) { + MyPair &c1 = *this; + return MyPair(c1.GetFirst() + c2.GetFirst(), c1.GetSecond() + c2.GetSecond()); + } + + void print() { + cout << "(" << first << "," << second << ")\n"; + } + int GetFirst() const { + return first; + } + void SetFirst(int first) { + this->first = first; + } + int GetSecond() const { + return second; + } + void SetSecond(int second) { + this->second = second; + } + + MyPair operator !() { + cout<<"Here\n"; + MyPair &c1 = *this; + return MyPair(-1 * c1.GetFirst(), + -1 * c1.GetSecond()); + } + + int operator[]( int pos) const { + if (pos == 0) + return GetFirst(); + return GetSecond(); + } +}; + +int main() { + MyPair x(10, 20); + cout< just a function that return temp var, e.g. g + // so u r doing g = 7 this has nothing with object x + // we need g points in memory to first when [0] + + return 0; +} diff --git a/19-object-oriented-programming/14_07.cpp b/19-object-oriented-programming/14_07.cpp new file mode 100644 index 0000000..114a523 --- /dev/null +++ b/19-object-oriented-programming/14_07.cpp @@ -0,0 +1,86 @@ +#include +using namespace std; + +class Employee { +public: + int id; + int salary; + string name; + + Employee(int id, int salary, string name) : + id(id), salary(salary), name(name) { + } + bool operator <(const Employee & c2) { + return std::tie(id, salary, name) < + std::tie(c2.id, c2.salary, c2.name); + } + + void print() { + cout << id << " " << name << " " << salary << "\n"; + } +}; + +void test1() { + vector emps; + + emps.push_back( { 9, 500, "ali" }); + emps.push_back( { 1, 1000, "mostafa" }); + emps.push_back( { 5, 700, "hani" }); + + sort(emps.begin(), emps.end()); // overloaded < + + for (auto &emp : emps) + emp.print(); +} + +class EmployeeComparatorId { +public: + bool operator ()(const Employee & c1, const Employee & c2) { + return c1.id < c2.id; + } +}; + +class EmployeeComparatorSalary { +public: + bool operator ()(const Employee & c1, + const Employee & c2) { + return c1.salary < c2.salary; + } +}; + +void test2() { + vector emps; + + emps.push_back( { 9, 500, "ali" }); + emps.push_back( { 1, 1000, "mostafa" }); + emps.push_back( { 5, 700, "hani" }); + + EmployeeComparatorSalary comparator = + EmployeeComparatorSalary(); + sort(emps.begin(), emps.end(), comparator); + + for (auto &emp : emps) + emp.print(); +} + +void test3() { + vector emps; + + emps.push_back( { 9, 500, "ali" }); + emps.push_back( { 1, 1000, "mostafa" }); + emps.push_back( { 5, 700, "hani" }); + + sort(emps.begin(), emps.end(), [](const Employee & c1, + const Employee & c2) { + return c1.salary < c2.salary; + }); + + for (auto &emp : emps) + emp.print(); +} + +int main() { + test3(); + + return 0; +} diff --git a/19-object-oriented-programming/14_homework_01_answer.cpp b/19-object-oriented-programming/14_homework_01_answer.cpp new file mode 100644 index 0000000..ba2c118 --- /dev/null +++ b/19-object-oriented-programming/14_homework_01_answer.cpp @@ -0,0 +1,27 @@ +#include +using namespace std; + +vector operator +(const vector &c1, const vector &c2) { + if(c1.size() > c2.size()) + return c2 + c1; + + vector c = c2; + for (int i = 0; i < (int)c1.size(); ++i) { + c[i] += c1[i]; + } + return c; +} + +int main() { + vector a = {1, 2, 3, 4}; + vector b = {10, 20}; + + vector c = a + b; + + for (int i = 0; i < (int)c.size(); ++i) + cout< +using namespace std; + +string operator *(const string &c1, int num) { + if(num <= 0) + return ""; + + string ret; + while(num--) + ret += c1; + return ret; +} + +int main() { + string a = "bad"; + string b = "I am " + a * 3 + ", right?"; + + cout< +using namespace std; + +class MyPair { +private: + int first, second; + +public: + MyPair(int first, int second) : + first(first), second(second) { + } + + void print() { + cout << "(" << first << "," << second << ")\n"; + } + int GetFirst() const { + return first; + } + void SetFirst(int first) { + this->first = first; + } + int GetSecond() const { + return second; + } + void SetSecond(int second) { + this->second = second; + } + + bool operator <(const MyPair &c2) { + MyPair &c1 = *this; + + if (c1.first == c2.first) + return c1.second < c2.second; + + return c1.first < c2.first; + } +}; + +int main() { + vector vec; + vec.push_back(MyPair(10, 20)); + vec.push_back(MyPair(10, 7)); + vec.push_back(MyPair(1, 200)); + + sort(vec.begin(), vec.end()); + + for (auto &pair : vec) + pair.print(); + // (1,200) (10,7) (10,20) + + return 0; +} diff --git a/19-object-oriented-programming/14_homework_04_answer.cpp b/19-object-oriented-programming/14_homework_04_answer.cpp new file mode 100644 index 0000000..bbe4f53 --- /dev/null +++ b/19-object-oriented-programming/14_homework_04_answer.cpp @@ -0,0 +1,74 @@ +#include +using namespace std; + +class MyPair { +private: + int first, second; + +public: + virtual ~MyPair() {} + MyPair(int first, int second) : + first(first), second(second) { + } + + virtual void print() { + cout << "(" << first << "," << second << ")\n"; + } + int GetFirst() const { + return first; + } + void SetFirst(int first) { + this->first = first; + } + int GetSecond() const { + return second; + } + void SetSecond(int second) { + this->second = second; + } + + bool operator <(const MyPair &c2) { + MyPair &c1 = *this; + + if (c1.first == c2.first) + return c1.second < c2.second; + + return c1.first < c2.first; + } +}; + +class NamedPair : public MyPair{ +private: + string name; +public: + NamedPair(string name, int first, int second) : MyPair(first, second), name(name) { + } + + bool operator <(const NamedPair &c2) { + NamedPair &c1 = *this; + + if (c1.name == c2.name) + return MyPair::operator <(c2); + + return c1.name < c2.name; + } + + virtual void print() { + cout << "(" << name<<": "< vec; + vec.push_back(NamedPair("A", 10, 20)); + vec.push_back(NamedPair("B", 10, 7)); + vec.push_back(NamedPair("B", 1, 200)); + + sort(vec.begin(), vec.end()); + + for (auto &pair : vec) + pair.print(); + // ((A: 10,20) (B: 1,200) (B: 10,7) + + return 0; +} diff --git a/19-object-oriented-programming/14_homework_05_answer.cpp b/19-object-oriented-programming/14_homework_05_answer.cpp new file mode 100644 index 0000000..85012ca --- /dev/null +++ b/19-object-oriented-programming/14_homework_05_answer.cpp @@ -0,0 +1,47 @@ +#include +using namespace std; + +class Boolean { +private: + bool is_true; + +public: + Boolean(bool is_true) : is_true(is_true) { } + bool operator &&(const Boolean &other) const { + return this->is_true && other.is_true; + } +}; + +bool T() { cout << "T\n"; return true; } +bool F() { cout << "F\n"; return false; } + +Boolean TC() { cout << "TC\n"; return Boolean(true); } +Boolean FC() { cout << "FC\n"; return Boolean(false); } + +int main() { + F() && T(); + FC() && TC(); + + return 0; +} + + +/* +F +TC +FC + + +======== +Clearly the first line just give F, because of short-circuit evaluation: As the first one is False, no need to continue (short) + +When operators such as &&, || are overloaded, they lose their special properties of short-circuit evaluation and sequencing. +     This means all of them will be evaluated + +Tip: DON'T override && || +    They will be misused. Programmers forget or don't know the short-circuit evaluation case for operator overloading  + +     +Tip: Operator overloading is great till you support it unwisely! + +*/ diff --git a/19-object-oriented-programming/14_homework_06_answer.cpp b/19-object-oriented-programming/14_homework_06_answer.cpp new file mode 100644 index 0000000..318759c --- /dev/null +++ b/19-object-oriented-programming/14_homework_06_answer.cpp @@ -0,0 +1,74 @@ +#include +using namespace std; + +class MyMap { +private: + vector vec_strs; + vector vec_ints; + + int pos = 0; +public: + int& operator[](const string& s) { + for (int i = 0; i < (int) vec_strs.size(); ++i) { + if (vec_strs[i] == s) + return vec_ints[i]; + } + vec_strs.push_back(s); + vec_ints.push_back(0); + return vec_ints.back(); + } + + vector operator[](int target) { + vector ret; + for (int i = 0; i < (int) vec_ints.size(); ++i) { + if (vec_ints[i] == target) + ret.push_back(vec_strs[i]); + } + sort(ret.begin(), ret.end()); + return ret; + } + void Reset_iterator() { + pos = 0; + } + + void Clear() { + vec_strs.clear(); + vec_ints.clear(); + pos = 0; + } + + bool HasNext() { + return pos < (int) vec_ints.size(); + } + pair GetNext() { + assert(HasNext()); + auto p = make_pair(vec_strs[pos], vec_ints[pos]); + pos++; + return p; + } + +}; + +int main() { + MyMap map; + + map["mostafa"] = 20; + map["mostafa"] = 40; + map["sayed"] = 20; + map["ali"] = 20; + + cout << map["mostafa"] << "\n"; // 40 + + vector v = map[20]; + for (auto s : v) + cout << s << "\n"; // ali sayed + + map.Reset_iterator(); + while (map.HasNext()) { + auto p = map.GetNext(); + cout << p.first << " " << p.second << "\n"; + } + map.Clear(); + + return 0; +} diff --git a/19-object-oriented-programming/14_homework_07_answer.cpp b/19-object-oriented-programming/14_homework_07_answer.cpp new file mode 100644 index 0000000..6f60cbf --- /dev/null +++ b/19-object-oriented-programming/14_homework_07_answer.cpp @@ -0,0 +1,55 @@ +#include +using namespace std; + +class Double { +private: + double d; + const double EPS = (1e-10); + + // return -1 if a < b, 0 if equal and 1 if a > b + int dcmp(double a, double b) const { + return fabs(a - b) <= EPS ? 0 : a < b ? -1 : 1; + } +public: + Double() : d(0) { + } + Double(double d) : d(d) { + } + bool operator <(const Double& D) const { + return dcmp(d, D.d) < 0; + } + bool operator >(const Double& D) const { + return dcmp(d, D.d) > 0; + } + bool operator ==(const Double& D) const { + return dcmp(d, D.d) == 0; + } + bool operator <=(const Double& D) const { + return !(*this > D); + } + bool operator >=(const Double& D) const { + return !(*this < D); + } +}; + +int main() { + double d1 = 1 + 3.0 / 7.0 -1; + double d2 = 3.0 / 7.0; + + // 0.428571 0.428571 0 + // If gave true, play with similar examples + cout< map; + map[cd1] = 10; + map[cd2] = 20; + + cout< +using namespace std; + +class ChessBoard { +private: + int rows; + int colums; + +public: + ChessBoard(int rows, int colums) : + rows(rows), colums(colums) { + } +}; + +int main() { + ChessBoard board(2, 3); // 2x3 grid + + board(0, 0) = 10; + board[0][1] = 20; + + cout << board[0][0] << " " << board(0, 1); + + return 0; +} diff --git a/19-object-oriented-programming/14_homework_08_answer.cpp b/19-object-oriented-programming/14_homework_08_answer.cpp new file mode 100644 index 0000000..725f845 --- /dev/null +++ b/19-object-oriented-programming/14_homework_08_answer.cpp @@ -0,0 +1,45 @@ +#include +using namespace std; + +class ChessBoard { +private: + int rows; + int colums; + + vector > board; + +public: + ChessBoard(int rows, int colums) : + rows(rows), colums(colums) { + board = vector >(rows, vector(colums)); + } + + /* + * There is no double subscript operator [][] + * overload operator[] to return an object that also overloads operator[]. This will enable [][]. + * + * If we used internally 2D vector + * and returned row for [] + * then return allows all operations on a single vector! + */ + vector& operator[](int row) { + // using board[row][col] + // then become row[col] + return board[row]; + } + + int& operator()(int row, int col) { + return board[row][col]; + } +}; + +int main() { + ChessBoard board(2, 3); // 2x3 grid + + board(0, 0) = 10; + board[0][1] = 20; + + cout << board[0][0] << " " << board(0, 1); + + return 0; +} diff --git a/19-object-oriented-programming/15_01.cpp b/19-object-oriented-programming/15_01.cpp new file mode 100644 index 0000000..c582f6b --- /dev/null +++ b/19-object-oriented-programming/15_01.cpp @@ -0,0 +1,55 @@ +#include +using namespace std; + +class MyPair { +private: + int first, second; + +public: + MyPair(int first, int second) : + first(first), second(second) { + } + + void print() { + cout << "(" << first << "," << second << ")\n"; + } + int GetFirst() const { + return first; + } + void SetFirst(int first) { + this->first = first; + } + int GetSecond() const { + return second; + } + void SetSecond(int second) { + this->second = second; + } + + // ++x prefix increment operator + MyPair& operator++() { + ++first, ++second; // increment first + return *this; // then return reference + } + + // x++ postfix increment operator + // DON'T return MyPair&: this is local var + MyPair operator++(int) { + MyPair cpy = *this; // Copy first + ++first, ++second; // Then increment + return cpy; + } +}; + + +int main() { + MyPair x1(1, 2); + (++x1).print(); // (2,3) + + MyPair x2(1, 2); + x2++.print(); // (1,2) + x2.print(); // (2,3) + + + return 0; +} diff --git a/19-object-oriented-programming/15_02.cpp b/19-object-oriented-programming/15_02.cpp new file mode 100644 index 0000000..e7c4948 --- /dev/null +++ b/19-object-oriented-programming/15_02.cpp @@ -0,0 +1,52 @@ +#include +using namespace std; + +class MyPair { +private: + int first, second; + +public: + MyPair() : // Empty constructor to allow using default + first(-1), second(-1) { + } + + MyPair(int first, int second) : + first(first), second(second) { + } + + void print() { + cout << "(" << first << "," << second << ")\n"; + } + int GetFirst() const { + return first; + } + void SetFirst(int first) { + this->first = first; + } + int GetSecond() const { + return second; + } + void SetSecond(int second) { + this->second = second; + } +}; + +void operator >>(istream &input, MyPair &pair) { + int a, b; + cin >> a >> b; + pair.SetFirst(a); + pair.SetSecond(b); +} + +int main() { + MyPair x, y; + cin >> x; + x.print(); + + // But we can't read several objects + // Recall cin>>x is function that return void + // What if it return cin object again! + //cin >> x >> y; + + return 0; +} diff --git a/19-object-oriented-programming/15_03.cpp b/19-object-oriented-programming/15_03.cpp new file mode 100644 index 0000000..7be8739 --- /dev/null +++ b/19-object-oriented-programming/15_03.cpp @@ -0,0 +1,52 @@ +#include +using namespace std; + +class MyPair { +private: + int first, second; + +public: + MyPair() : // Empty constructor to allow using default + first(-1), second(-1) { + } + + MyPair(int first, int second) : + first(first), second(second) { + } + + void print() { + cout << "(" << first << "," << second << ")\n"; + } + int GetFirst() const { + return first; + } + void SetFirst(int first) { + this->first = first; + } + int GetSecond() const { + return second; + } + void SetSecond(int second) { + this->second = second; + } + + friend istream & operator >>(istream &input, MyPair &pair); +}; + +istream & operator >>(istream &input, MyPair &pair) { + input >> pair.first >> pair.second; + return input; +} + +int main() { + MyPair x, y; + + cin >> x >> y; + + x.print(); + y.print(); + + + + return 0; +} diff --git a/19-object-oriented-programming/15_04.cpp b/19-object-oriented-programming/15_04.cpp new file mode 100644 index 0000000..63da760 --- /dev/null +++ b/19-object-oriented-programming/15_04.cpp @@ -0,0 +1,54 @@ +#include +using namespace std; + +class MyPair { +private: + int first, second; + +public: + MyPair() : // Empty constructor to allow using default + first(-1), second(-1) { + } + + MyPair(int first, int second) : + first(first), second(second) { + } + + void print() { + cout << "(" << first << "," << second << ")\n"; + } + int GetFirst() const { + return first; + } + void SetFirst(int first) { + this->first = first; + } + int GetSecond() const { + return second; + } + void SetSecond(int second) { + this->second = second; + } + + friend istream & operator >>(istream &input, MyPair &pair); + friend ostream & operator <<(ostream &output, const MyPair &pair); +}; + +istream& operator >>(istream &input, MyPair &pair) { + input >> pair.first >> pair.second; + return input; +} + +ostream& operator <<(ostream &output, const MyPair &pair) { + output << "("<> x >> y; + cout << x << y; + + return 0; +} diff --git a/19-object-oriented-programming/15_05.cpp b/19-object-oriented-programming/15_05.cpp new file mode 100644 index 0000000..2d2932f --- /dev/null +++ b/19-object-oriented-programming/15_05.cpp @@ -0,0 +1,52 @@ +#include +using namespace std; + +class MyPair { +private: + int first, second; +public: + void print() { + cout << "(" << first << "," << second << ")\n"; + } + int GetFirst() const { + return first; + } + void SetFirst(int first) { + this->first = first; + } + int GetSecond() const { + return second; + } + void SetSecond(int second) { + this->second = second; + } + + MyPair(int x) : MyPair(x, x) {} + + MyPair(int first, int second) : + first(first), second(second) { + } +}; + +MyPair operator +(const MyPair &c1, const MyPair &c2) { + return MyPair(c1.GetFirst() + c2.GetFirst(), + c1.GetSecond() + c2.GetSecond()); +} + +int main() { + MyPair x(1, 2); + MyPair y(3); + MyPair w = 5; // Converting constructor MyPair(int x) + + MyPair z1 = x + 5.3; + MyPair z2 = 3 + x; + MyPair z3 = 3 + x + 5; + + w.print(); + z1.print(); + z2.print(); + z3.print(); + + + return 0; +} diff --git a/19-object-oriented-programming/15_06.cpp b/19-object-oriented-programming/15_06.cpp new file mode 100644 index 0000000..57e9452 --- /dev/null +++ b/19-object-oriented-programming/15_06.cpp @@ -0,0 +1,55 @@ +#include +using namespace std; + +class MyPair { +private: + int first, second; +public: + void print() { + cout << "(" << first << "," << second << ")\n"; + } + int GetFirst() const { + return first; + } + void SetFirst(int first) { + this->first = first; + } + int GetSecond() const { + return second; + } + void SetSecond(int second) { + this->second = second; + } + + MyPair(int x) : + MyPair(x, x) { + } + + MyPair(int first, int second) : + first(first), second(second) { + } + + MyPair(pair p) : // Use explicit + first(p.first), second(p.second) { + } + + operator int() { + return first * second; + } + + operator pair() { + return make_pair(first, second); + } +}; + +int main() { + MyPair x(2, 3); + + int r = x; // 6 + pair p = x; // operator pair() + x = p; // MyPair(pair p) + + cout< +using namespace std; + +class Base { +public: +}; + +class B: public Base { +private: + int *val; + +public: + ~B() { + delete val; + val = nullptr; + } + + B(int x) : val(new int) { + *val = x; + } + B(const B &another) : val(new int) { + *val = *another.val; // copy constructor + } + + B &operator=(const B &another) { // assignment operator + if (this == &another) + return *this; // handle self assignment + + Base::operator= (another); // Assign @ Parent + + // Do remain of your assignment + *val = *another.val; + return *this; + } + + // Force no assignment operator + // B &operator=(const B &another) = delete; + +}; + +int main() { + B b1(10); + B b2 = b1; // copy + b2 = b1; // Assign + + return 0; +} diff --git a/19-object-oriented-programming/15_homework_01_answer.cpp b/19-object-oriented-programming/15_homework_01_answer.cpp new file mode 100644 index 0000000..b5aec1b --- /dev/null +++ b/19-object-oriented-programming/15_homework_01_answer.cpp @@ -0,0 +1,46 @@ +#include +using namespace std; + +class MyNumber { +public: + int num; + MyNumber(int num) : num(num) { } +}; + +MyNumber operator ^(const MyNumber &c1, int pow) { + int res = 1; + while (pow--) res *= c1.num; + return MyNumber(res); +} + +MyNumber operator +(const MyNumber &c1, const MyNumber &c2) { + return MyNumber(c1.num + c2.num); +} + +int main() { + MyNumber x(2); + MyNumber res1 = x^3; + MyNumber res2 = 1 + x^3; + cout< 4 + 9 => 13. +However, in C++, the arithmetic operators have higher precedence than operator^, so 4 + 3 ^ 2 resolves as (4 + 3) ^ 2 => 7 ^ 2 => 49. + +You’d need to explicitly parenthesize the exponent portion (e.g. 4 + (3 ^ 2)) every time you used it for this to work properly, which isn’t intuitive, and is potentially error-prone. + +Because of this precedence issue, it’s generally a good idea to use operators only in an analogous way to their original intent. + +Rule: When overloading operators, it’s best to keep the function of the operators as close to the original intent of the operators as possible. + +https://www.learncpp.com/cpp-tutorial/91-introduction-to-operator-overloading/ + + */ diff --git a/19-object-oriented-programming/15_homework_02_answer.cpp b/19-object-oriented-programming/15_homework_02_answer.cpp new file mode 100644 index 0000000..6e3639e --- /dev/null +++ b/19-object-oriented-programming/15_homework_02_answer.cpp @@ -0,0 +1,58 @@ +#include +using namespace std; + +class MyPair { +private: + int first, second; + +public: + MyPair() : // Empty constructor to allow using default + first(-1), second(-1) { + } + + MyPair(int first, int second) : + first(first), second(second) { + } + + void print() { + cout << "(" << first << "," << second << ")\n"; + } + int GetFirst() const { + return first; + } + void SetFirst(int first) { + this->first = first; + } + int GetSecond() const { + return second; + } + void SetSecond(int second) { + this->second = second; + } + + void operator >>(istream &input) { + input >> first >> second; + } + + void operator >>(ostream &output) { + output << first << second; + } +}; + + +int main() { + MyPair x, y; + + // Very weird to the used style! + x >> cin; + y >> cin; + + x >> cout; + y >> cout; + + // Tip 1: using non-member style allow us to extend normally to have cin >> + // Using >> for both input/output is wrong. Use operators as people expect + // E.g. don't overload + to do - operations! The code will be misused! + + return 0; +} diff --git a/19-object-oriented-programming/15_homework_03_answer.cpp b/19-object-oriented-programming/15_homework_03_answer.cpp new file mode 100644 index 0000000..91df34b --- /dev/null +++ b/19-object-oriented-programming/15_homework_03_answer.cpp @@ -0,0 +1,54 @@ +#include +using namespace std; + +// Original Src: https://en.cppreference.com/w/cpp/language/operators + +class Fraction { +private: + int n, d; + +public: + Fraction(int n, int d = 1) : + n(n / __gcd(n, d)), d(d / __gcd(n, d)) { + } + int num() const { + return n; + } + int den() const { + return d; + } + + Fraction& operator*=(const Fraction& rhs) { + // Some math to multiply and simplify + int new_n = n * rhs.n / __gcd(n * rhs.n, d * rhs.d); + d = d * rhs.d / __gcd(n * rhs.n, d * rhs.d); + n = new_n; + return *this; + } +}; +std::ostream& operator<<(std::ostream& out, const Fraction& f) { + return out << f.num() << '/' << f.den(); +} + +bool operator==(const Fraction& lhs, const Fraction& rhs) { + return lhs.num() == rhs.num() && lhs.den() == rhs.den(); +} + +bool operator!=(const Fraction& lhs, const Fraction& rhs) { + return !(lhs == rhs); +} + +Fraction operator*(Fraction lhs, const Fraction& rhs) { + // Notice first param without const/ref + return lhs *= rhs; // Don;t duplicate +} + +int main() { + Fraction f1(3, 8); + Fraction f2 = 2 * f1; + Fraction f3 = f1 * f2; + Fraction f4 = f3; + f4 *= f4; + + cout << f1 << "\n" << f2 << "\n" << f3 << "\n" << f4; +} diff --git a/19-object-oriented-programming/15_homework_04.cpp b/19-object-oriented-programming/15_homework_04.cpp new file mode 100644 index 0000000..8c28806 --- /dev/null +++ b/19-object-oriented-programming/15_homework_04.cpp @@ -0,0 +1,46 @@ +#include +using namespace std; + +class Array { +private: + int size; + int *ptr; + +public: +}; + +void test_Array() { + Array arr1(6); + + int counter = 0; + for (int i = 0; i < arr1.getSize(); ++i) + arr1[i] = counter++; + + cout< +using namespace std; + +/* + + Observe that: copy constructors and operators can directly access private variables + of another object of same class + https://stackoverflow.com/questions/4117002/why-can-i-access-private-variables-in-the-copy-constructor + */ + +class Array { +private: + int size; + int *ptr; + +public: + ~Array() { + delete[] ptr; + ptr = nullptr; + } + + explicit Array(int size = 100) : + size(size), ptr(new int[size]) { + for (int i = 0; i < size; ++i) + ptr[i] = 0; + } + Array(const Array &another) : // copy constructor + size(another.size), ptr(new int[size]) { + for (int i = 0; i < size; ++i) + ptr[i] = another.ptr[i]; + } + + int getSize() const { + return size; + } + + Array &operator=(const Array &another) { // assign operator + if (&another != this) { // Check self-assignment + if (size != another.size) { + delete[] ptr; + size = another.size; + ptr = new int[size]; + } + for (int i = 0; i < size; ++i) + ptr[i] = another.ptr[i]; + } + return *this; + } + + int &operator[](int pos) { + return ptr[pos]; + } + + int operator[](int pos) const { + return ptr[pos]; + } + + bool operator==(const Array &another) const { + if (size != another.size) + return false; + + for (int i = 0; i < size; ++i) + if (ptr[i] != another.ptr[i]) + return false; + + return true; + } + + bool operator!=(const Array &another) const { + // Don't duplicate. Call operator== + return !(*this == another); + } + + Array& operator++() { // prefix + for (int i = 0; i < size; ++i) + ++ptr[i]; + return *this; + } + + Array operator++(int) { // postfix + Array cpy = *this; + ++*this; // Don't duplicate. Call ++object + return cpy; + } + + friend istream &operator>>(istream &input, Array &arr); + friend ostream &operator<<(ostream &output, const Array &arr); +}; + +istream &operator>>(istream &input, Array &arr) { + for (int i = 0; i < arr.size; ++i) + input >> arr.ptr[i]; + return input; +} + +ostream &operator<<(ostream &output, const Array &arr) { + for (int i = 0; i < arr.size; ++i) + output << arr.ptr[i] << " "; + output << "\n"; + + return output; +} + +void test_Array() { + Array arr1(6); + + int counter = 0; + for (int i = 0; i < arr1.getSize(); ++i) + arr1[i] = counter++; + + cout< +using namespace std; + +class Array { +private: + int size; + int *ptr; + +}; + +class Array2D: public Array { +private: + int rows; + int cols; + +public: + +}; + + +void test_Array2d() { + Array2D arr1(2, 3); + + int counter = 0; + for (int i = 0; i < 2; ++i) { + for (int j = 0; j < 3; ++j) { + arr1(i, j) = counter++; + } + } + + cout< +using namespace std; + +/* + + Observe that: copy constructors and operators can directly access private variables + of another object of same class + https://stackoverflow.com/questions/4117002/why-can-i-access-private-variables-in-the-copy-constructor + */ + +class Array { +private: + int size; + int *ptr; + +public: + ~Array() { + delete[] ptr; + ptr = nullptr; + } + + explicit Array(int size = 100) : + size(size), ptr(new int[size]) { + for (int i = 0; i < size; ++i) + ptr[i] = 0; + } + Array(const Array &another) : // copy constructor + size(another.size), ptr(new int[size]) { + for (int i = 0; i < size; ++i) + ptr[i] = another.ptr[i]; + } + + int getSize() const { + return size; + } + + Array &operator=(const Array &another) { // assign operator + if (&another != this) { // Check self-assignment + if (size != another.size) { + delete[] ptr; + size = another.size; + ptr = new int[size]; + } + for (int i = 0; i < size; ++i) + ptr[i] = another.ptr[i]; + } + return *this; + } + + int &operator[](int pos) { + return ptr[pos]; + } + + int operator[](int pos) const { + return ptr[pos]; + } + + bool operator==(const Array &another) const { + if (size != another.size) + return false; + + for (int i = 0; i < size; ++i) + if (ptr[i] != another.ptr[i]) + return false; + + return true; + } + + bool operator!=(const Array &another) const { + // Don't duplicate. Call operator== + return !(*this == another); + } + + Array& operator++() { // prefix + for (int i = 0; i < size; ++i) + ++ptr[i]; + return *this; + } + + Array operator++(int) { // postfix + Array cpy = *this; + ++*this; // Don't duplicate. Call ++object + return cpy; + } + + friend istream &operator>>(istream &input, Array &arr); + friend ostream &operator<<(ostream &output, const Array &arr); +}; + +istream &operator>>(istream &input, Array &arr) { + for (int i = 0; i < arr.size; ++i) + input >> arr.ptr[i]; + return input; +} + +ostream &operator<<(ostream &output, const Array &arr) { + for (int i = 0; i < arr.size; ++i) + output << arr.ptr[i] << " "; + output << "\n"; + + return output; +} + +class Array2D: public Array { +private: + int rows; + int cols; + +public: + Array2D(int rows = 2, int cols = 5) : + Array(rows * cols), rows(rows), cols(cols) { + } + + int& operator()(int r, int c) { + int pos = r * cols + c; + return Array::operator[](pos); + } + + int operator()(int r, int c) const { + int pos = r * cols + c; + return Array::operator[](pos); + } + + // If we did not override ++, the return from parent will be baseclass! + Array2D& operator++() { // prefix + Array::operator ++(); + return *this; + } + + Array2D operator++(int) { // postfix + Array2D cpy = *this; + ++*this; + return cpy; + } + friend ostream &operator<<(ostream &output, const Array2D &arr); +}; + +ostream &operator<<(ostream &output, const Array2D &arr) { + for (int i = 0; i < arr.rows; ++i) { + for (int j = 0; j < arr.cols; ++j) { + output << arr(i, j) << " "; + } + output << "\n"; + } + return output; +} + +void test_Array2d() { + Array2D arr1(2, 3); + + int counter = 0; + for (int i = 0; i < 2; ++i) { + for (int j = 0; j < 3; ++j) { + arr1(i, j) = counter++; + } + } + + cout< +using namespace std; + +class Object { // make it a polymorphic class +public: + virtual string GetClassName() const = 0; + + virtual ~Object() { + } +}; + +class Cloneable: virtual public Object { +public: + virtual Object* Clone() const = 0; + virtual ~Cloneable() { + } +}; + +class Printable: virtual public Object { +public: + virtual void Print(ostream& out) const = 0; + + virtual ~Printable() { + } +}; + +// Inverse of control. We implement this operator here ONLY once +// Call the print function, which will be known in runtime! Cheers! +// This way we don't have to provide several overloaded versions of it! +ostream& operator <<(ostream& out, const Printable & p) { + p.Print(out); + return out; +} + +class Comparable: virtual public Object { +public: + virtual bool operator < (Object& obj) const = 0; + virtual ~Comparable() { + } +}; + +class Payable: public Cloneable, public Printable, public Comparable { +public: + virtual double GetAmountToPay() const = 0; + virtual ~Payable() { + } +}; + +class Employee: public Payable { +private: + double salary; + string name; +public: + Employee(double salary, string name) : + salary(salary), name(name) { + } + + virtual string GetClassName() const override { + return "Employee"; + } + + virtual Object* Clone() const override { + return new Employee(*this); // Default copy constructor is good, as no internal pointers so far + } + + virtual void Print(ostream& out) const override { + out << "Employee " << name << " has salary " << salary << "\n"; + } + + double GetAmountToPay() const override { + return salary; + } + + virtual bool operator < (Object& obj) const override { + if (GetClassName() != obj.GetClassName()) + return GetClassName() < obj.GetClassName(); + + Employee* another_ptr = nullptr; + if ((another_ptr = dynamic_cast(&obj))) + return tie(salary, name) < tie(another_ptr->salary, another_ptr->name); + else + return false; // Not an employee! + } +}; + +class Invoice: public Payable { +private: + double cost; +public: + Invoice(double cost) : + cost(cost) { + } + + virtual string GetClassName() const override { + return "Invoice"; + } + + virtual Object* Clone() const override { + return new Invoice(*this); + } + + virtual void Print(ostream& out) const override { + out << "Invoice cost " << cost << "\n"; + } + + double GetAmountToPay() const override { + return cost; + } + + virtual bool operator < (Object& obj) const override { + if (GetClassName() != obj.GetClassName()) + return GetClassName() < obj.GetClassName(); + + Invoice* another_ptr = nullptr; + if ((another_ptr = dynamic_cast(&obj))) + return cost < another_ptr->cost; + else + return false; + } +}; + +class Sortable: virtual public Object { +public: + virtual void OrderItems() = 0; + virtual ~Sortable() { + } +}; + +bool Compare(Payable* obj1, Payable* obj2) { + return *obj1 < *obj2; +} + +class CompanyPayroll: public Printable, public Sortable { +private: + vector payables; + +public: + CompanyPayroll() { + } + // Prevent copy constructor + CompanyPayroll(const CompanyPayroll&) = delete; + // Prevent assignment operator + void operator=(const CompanyPayroll&) = delete; + + void AddPayable(const Payable& payable) { + payables.push_back(dynamic_cast(payable.Clone())); + } + + virtual string GetClassName() const override { + return "CompanyPayroll"; + } + + virtual void Print(ostream& out) const override { + double to_pay_sum = 0; + + for (auto payable : payables) { + // Below is wrong. it prints address. Use * to print object + //out<GetAmountToPay(); + } + + out << "Total to be paid: " << to_pay_sum << "\n"; + } + + virtual void OrderItems() override { + sort(payables.begin(), payables.end(), Compare); + + // Below is wrong as it compares pointer address with pointer address + // If you did not use a function, it will compare ptr1 < ptr2 as pointers in memory NOT as actual objects + // sort(payables.begin(), payables.end()); + } + + ~CompanyPayroll() { + + for (auto payable : payables) + delete payable; + payables.clear(); + } +}; + +void test() { + CompanyPayroll payroll; + + payroll.AddPayable(Employee(50, "mostafa")); + payroll.AddPayable(Invoice(200)); + payroll.AddPayable(Employee(10, "ziad")); + payroll.AddPayable(Invoice(100)); + payroll.AddPayable(Employee(30, "belal")); + payroll.AddPayable(Invoice(300)); + + payroll.OrderItems(); + cout< +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace json { + +using std::map; +using std::deque; +using std::string; +using std::enable_if; +using std::initializer_list; +using std::is_same; +using std::is_convertible; +using std::is_integral; +using std::is_floating_point; + +namespace { + string json_escape( const string &str ) { + string output; + for( unsigned i = 0; i < str.length(); ++i ) + switch( str[i] ) { + case '\"': output += "\\\""; break; + case '\\': output += "\\\\"; break; + case '\b': output += "\\b"; break; + case '\f': output += "\\f"; break; + case '\n': output += "\\n"; break; + case '\r': output += "\\r"; break; + case '\t': output += "\\t"; break; + default : output += str[i]; break; + } + return std::move( output ); + } +} + +class JSON +{ + union BackingData { + BackingData( double d ) : Float( d ){} + BackingData( long l ) : Int( l ){} + BackingData( bool b ) : Bool( b ){} + BackingData( string s ) : String( new string( s ) ){} + BackingData() : Int( 0 ){} + + deque *List; + map *Map; + string *String; + double Float; + long Int; + bool Bool; + } Internal; + + public: + enum class Class { + Null, + Object, + Array, + String, + Floating, + Integral, + Boolean + }; + + template + class JSONWrapper { + Container *object; + + public: + JSONWrapper( Container *val ) : object( val ) {} + JSONWrapper( std::nullptr_t ) : object( nullptr ) {} + + typename Container::iterator begin() { return object ? object->begin() : typename Container::iterator(); } + typename Container::iterator end() { return object ? object->end() : typename Container::iterator(); } + typename Container::const_iterator begin() const { return object ? object->begin() : typename Container::iterator(); } + typename Container::const_iterator end() const { return object ? object->end() : typename Container::iterator(); } + }; + + template + class JSONConstWrapper { + const Container *object; + + public: + JSONConstWrapper( const Container *val ) : object( val ) {} + JSONConstWrapper( std::nullptr_t ) : object( nullptr ) {} + + typename Container::const_iterator begin() const { return object ? object->begin() : typename Container::const_iterator(); } + typename Container::const_iterator end() const { return object ? object->end() : typename Container::const_iterator(); } + }; + + JSON() : Internal(), Type( Class::Null ){} + + JSON( initializer_list list ) + : JSON() + { + SetType( Class::Object ); + for( auto i = list.begin(), e = list.end(); i != e; ++i, ++i ) + operator[]( i->ToString() ) = *std::next( i ); + } + + JSON( JSON&& other ) + : Internal( other.Internal ) + , Type( other.Type ) + { other.Type = Class::Null; other.Internal.Map = nullptr; } + + JSON& operator=( JSON&& other ) { + ClearInternal(); + Internal = other.Internal; + Type = other.Type; + other.Internal.Map = nullptr; + other.Type = Class::Null; + return *this; + } + + JSON( const JSON &other ) { + switch( other.Type ) { + case Class::Object: + Internal.Map = + new map( other.Internal.Map->begin(), + other.Internal.Map->end() ); + break; + case Class::Array: + Internal.List = + new deque( other.Internal.List->begin(), + other.Internal.List->end() ); + break; + case Class::String: + Internal.String = + new string( *other.Internal.String ); + break; + default: + Internal = other.Internal; + } + Type = other.Type; + } + + JSON& operator=( const JSON &other ) { + ClearInternal(); + switch( other.Type ) { + case Class::Object: + Internal.Map = + new map( other.Internal.Map->begin(), + other.Internal.Map->end() ); + break; + case Class::Array: + Internal.List = + new deque( other.Internal.List->begin(), + other.Internal.List->end() ); + break; + case Class::String: + Internal.String = + new string( *other.Internal.String ); + break; + default: + Internal = other.Internal; + } + Type = other.Type; + return *this; + } + + ~JSON() { + switch( Type ) { + case Class::Array: + delete Internal.List; + break; + case Class::Object: + delete Internal.Map; + break; + case Class::String: + delete Internal.String; + break; + default:; + } + } + + template + JSON( T b, typename enable_if::value>::type* = 0 ) : Internal( b ), Type( Class::Boolean ){} + + template + JSON( T i, typename enable_if::value && !is_same::value>::type* = 0 ) : Internal( (long)i ), Type( Class::Integral ){} + + template + JSON( T f, typename enable_if::value>::type* = 0 ) : Internal( (double)f ), Type( Class::Floating ){} + + template + JSON( T s, typename enable_if::value>::type* = 0 ) : Internal( string( s ) ), Type( Class::String ){} + + JSON( std::nullptr_t ) : Internal(), Type( Class::Null ){} + + static JSON Make( Class type ) { + JSON ret; ret.SetType( type ); + return ret; + } + + static JSON Load( const string & ); + + template + void append( T arg ) { + SetType( Class::Array ); Internal.List->emplace_back( arg ); + } + + template + void append( T arg, U... args ) { + append( arg ); append( args... ); + } + + template + typename enable_if::value, JSON&>::type operator=( T b ) { + SetType( Class::Boolean ); Internal.Bool = b; return *this; + } + + template + typename enable_if::value && !is_same::value, JSON&>::type operator=( T i ) { + SetType( Class::Integral ); Internal.Int = i; return *this; + } + + template + typename enable_if::value, JSON&>::type operator=( T f ) { + SetType( Class::Floating ); Internal.Float = f; return *this; + } + + template + typename enable_if::value, JSON&>::type operator=( T s ) { + SetType( Class::String ); *Internal.String = string( s ); return *this; + } + + JSON& operator[]( const string &key ) { + SetType( Class::Object ); return Internal.Map->operator[]( key ); + } + + JSON& operator[]( unsigned index ) { + SetType( Class::Array ); + if( index >= Internal.List->size() ) Internal.List->resize( index + 1 ); + return Internal.List->operator[]( index ); + } + + JSON &at( const string &key ) { + return operator[]( key ); + } + + const JSON &at( const string &key ) const { + return Internal.Map->at( key ); + } + + JSON &at( unsigned index ) { + return operator[]( index ); + } + + const JSON &at( unsigned index ) const { + return Internal.List->at( index ); + } + + int length() const { + if( Type == Class::Array ) + return Internal.List->size(); + else + return -1; + } + + bool hasKey( const string &key ) const { + if( Type == Class::Object ) + return Internal.Map->find( key ) != Internal.Map->end(); + return false; + } + + int size() const { + if( Type == Class::Object ) + return Internal.Map->size(); + else if( Type == Class::Array ) + return Internal.List->size(); + else + return -1; + } + + Class JSONType() const { return Type; } + + /// Functions for getting primitives from the JSON object. + bool IsNull() const { return Type == Class::Null; } + + string ToString() const { bool b; return std::move( ToString( b ) ); } + string ToString( bool &ok ) const { + ok = (Type == Class::String); + return ok ? std::move( json_escape( *Internal.String ) ): string(""); + } + + double ToFloat() const { bool b; return ToFloat( b ); } + double ToFloat( bool &ok ) const { + ok = (Type == Class::Floating); + return ok ? Internal.Float : 0.0; + } + + long ToInt() const { bool b; return ToInt( b ); } + long ToInt( bool &ok ) const { + ok = (Type == Class::Integral); + return ok ? Internal.Int : 0; + } + + bool ToBool() const { bool b; return ToBool( b ); } + bool ToBool( bool &ok ) const { + ok = (Type == Class::Boolean); + return ok ? Internal.Bool : false; + } + + JSONWrapper> ObjectRange() { + if( Type == Class::Object ) + return JSONWrapper>( Internal.Map ); + return JSONWrapper>( nullptr ); + } + + JSONWrapper> ArrayRange() { + if( Type == Class::Array ) + return JSONWrapper>( Internal.List ); + return JSONWrapper>( nullptr ); + } + + JSONConstWrapper> ObjectRange() const { + if( Type == Class::Object ) + return JSONConstWrapper>( Internal.Map ); + return JSONConstWrapper>( nullptr ); + } + + + JSONConstWrapper> ArrayRange() const { + if( Type == Class::Array ) + return JSONConstWrapper>( Internal.List ); + return JSONConstWrapper>( nullptr ); + } + + string dump( int depth = 1, string tab = " ") const { + string pad = ""; + for( int i = 0; i < depth; ++i, pad += tab ); + + switch( Type ) { + case Class::Null: + return "null"; + case Class::Object: { + string s = "{\n"; + bool skip = true; + for( auto &p : *Internal.Map ) { + if( !skip ) s += ",\n"; + s += ( pad + "\"" + p.first + "\" : " + p.second.dump( depth + 1, tab ) ); + skip = false; + } + s += ( "\n" + pad.erase( 0, 2 ) + "}" ) ; + return s; + } + case Class::Array: { + string s = "["; + bool skip = true; + for( auto &p : *Internal.List ) { + if( !skip ) s += ", "; + s += p.dump( depth + 1, tab ); + skip = false; + } + s += "]"; + return s; + } + case Class::String: + return "\"" + json_escape( *Internal.String ) + "\""; + case Class::Floating: + return std::to_string( Internal.Float ); + case Class::Integral: + return std::to_string( Internal.Int ); + case Class::Boolean: + return Internal.Bool ? "true" : "false"; + default: + return ""; + } + return ""; + } + + friend std::ostream& operator<<( std::ostream&, const JSON & ); + + private: + void SetType( Class type ) { + if( type == Type ) + return; + + ClearInternal(); + + switch( type ) { + case Class::Null: Internal.Map = nullptr; break; + case Class::Object: Internal.Map = new map(); break; + case Class::Array: Internal.List = new deque(); break; + case Class::String: Internal.String = new string(); break; + case Class::Floating: Internal.Float = 0.0; break; + case Class::Integral: Internal.Int = 0; break; + case Class::Boolean: Internal.Bool = false; break; + } + + Type = type; + } + + private: + /* beware: only call if YOU know that Internal is allocated. No checks performed here. + This function should be called in a constructed JSON just before you are going to + overwrite Internal... + */ + void ClearInternal() { + switch( Type ) { + case Class::Object: delete Internal.Map; break; + case Class::Array: delete Internal.List; break; + case Class::String: delete Internal.String; break; + default:; + } + } + + private: + + Class Type = Class::Null; +}; + +JSON Array() { + return std::move( JSON::Make( JSON::Class::Array ) ); +} + +template +JSON Array( T... args ) { + JSON arr = JSON::Make( JSON::Class::Array ); + arr.append( args... ); + return std::move( arr ); +} + +JSON Object() { + return std::move( JSON::Make( JSON::Class::Object ) ); +} + +std::ostream& operator<<( std::ostream &os, const JSON &json ) { + os << json.dump(); + return os; +} + +namespace { + JSON parse_next( const string &, size_t & ); + + void consume_ws( const string &str, size_t &offset ) { + while( isspace( str[offset] ) ) ++offset; + } + + JSON parse_object( const string &str, size_t &offset ) { + JSON Object = JSON::Make( JSON::Class::Object ); + + ++offset; + consume_ws( str, offset ); + if( str[offset] == '}' ) { + ++offset; return std::move( Object ); + } + + while( true ) { + JSON Key = parse_next( str, offset ); + consume_ws( str, offset ); + if( str[offset] != ':' ) { + std::cerr << "Error: Object: Expected colon, found '" << str[offset] << "'\n"; + break; + } + consume_ws( str, ++offset ); + JSON Value = parse_next( str, offset ); + Object[Key.ToString()] = Value; + + consume_ws( str, offset ); + if( str[offset] == ',' ) { + ++offset; continue; + } + else if( str[offset] == '}' ) { + ++offset; break; + } + else { + std::cerr << "ERROR: Object: Expected comma, found '" << str[offset] << "'\n"; + break; + } + } + + return std::move( Object ); + } + + JSON parse_array( const string &str, size_t &offset ) { + JSON Array = JSON::Make( JSON::Class::Array ); + unsigned index = 0; + + ++offset; + consume_ws( str, offset ); + if( str[offset] == ']' ) { + ++offset; return std::move( Array ); + } + + while( true ) { + Array[index++] = parse_next( str, offset ); + consume_ws( str, offset ); + + if( str[offset] == ',' ) { + ++offset; continue; + } + else if( str[offset] == ']' ) { + ++offset; break; + } + else { + std::cerr << "ERROR: Array: Expected ',' or ']', found '" << str[offset] << "'\n"; + return std::move( JSON::Make( JSON::Class::Array ) ); + } + } + + return std::move( Array ); + } + + JSON parse_string( const string &str, size_t &offset ) { + JSON String; + string val; + for( char c = str[++offset]; c != '\"' ; c = str[++offset] ) { + if( c == '\\' ) { + switch( str[ ++offset ] ) { + case '\"': val += '\"'; break; + case '\\': val += '\\'; break; + case '/' : val += '/' ; break; + case 'b' : val += '\b'; break; + case 'f' : val += '\f'; break; + case 'n' : val += '\n'; break; + case 'r' : val += '\r'; break; + case 't' : val += '\t'; break; + case 'u' : { + val += "\\u" ; + for( unsigned i = 1; i <= 4; ++i ) { + c = str[offset+i]; + if( (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') ) + val += c; + else { + std::cerr << "ERROR: String: Expected hex character in unicode escape, found '" << c << "'\n"; + return std::move( JSON::Make( JSON::Class::String ) ); + } + } + offset += 4; + } break; + default : val += '\\'; break; + } + } + else + val += c; + } + ++offset; + String = val; + return std::move( String ); + } + + JSON parse_number( const string &str, size_t &offset ) { + JSON Number; + string val, exp_str; + char c; + bool isDouble = false; + long exp = 0; + while( true ) { + c = str[offset++]; + if( (c == '-') || (c >= '0' && c <= '9') ) + val += c; + else if( c == '.' ) { + val += c; + isDouble = true; + } + else + break; + } + if( c == 'E' || c == 'e' ) { + c = str[ offset++ ]; + if( c == '-' ){ ++offset; exp_str += '-';} + while( true ) { + c = str[ offset++ ]; + if( c >= '0' && c <= '9' ) + exp_str += c; + else if( !isspace( c ) && c != ',' && c != ']' && c != '}' ) { + std::cerr << "ERROR: Number: Expected a number for exponent, found '" << c << "'\n"; + return std::move( JSON::Make( JSON::Class::Null ) ); + } + else + break; + } + exp = std::stol( exp_str ); + } + else if( !isspace( c ) && c != ',' && c != ']' && c != '}' ) { + std::cerr << "ERROR: Number: unexpected character '" << c << "'\n"; + return std::move( JSON::Make( JSON::Class::Null ) ); + } + --offset; + + if( isDouble ) + Number = std::stod( val ) * std::pow( 10, exp ); + else { + if( !exp_str.empty() ) + Number = std::stol( val ) * std::pow( 10, exp ); + else + Number = std::stol( val ); + } + return std::move( Number ); + } + + JSON parse_bool( const string &str, size_t &offset ) { + JSON Bool; + if( str.substr( offset, 4 ) == "true" ) + Bool = true; + else if( str.substr( offset, 5 ) == "false" ) + Bool = false; + else { + std::cerr << "ERROR: Bool: Expected 'true' or 'false', found '" << str.substr( offset, 5 ) << "'\n"; + return std::move( JSON::Make( JSON::Class::Null ) ); + } + offset += (Bool.ToBool() ? 4 : 5); + return std::move( Bool ); + } + + JSON parse_null( const string &str, size_t &offset ) { + JSON Null; + if( str.substr( offset, 4 ) != "null" ) { + std::cerr << "ERROR: Null: Expected 'null', found '" << str.substr( offset, 4 ) << "'\n"; + return std::move( JSON::Make( JSON::Class::Null ) ); + } + offset += 4; + return std::move( Null ); + } + + JSON parse_next( const string &str, size_t &offset ) { + char value; + consume_ws( str, offset ); + value = str[offset]; + switch( value ) { + case '[' : return std::move( parse_array( str, offset ) ); + case '{' : return std::move( parse_object( str, offset ) ); + case '\"': return std::move( parse_string( str, offset ) ); + case 't' : + case 'f' : return std::move( parse_bool( str, offset ) ); + case 'n' : return std::move( parse_null( str, offset ) ); + default : if( ( value <= '9' && value >= '0' ) || value == '-' ) + return std::move( parse_number( str, offset ) ); + } + std::cerr << "ERROR: Parse: Unknown starting character '" << value << "'\n"; + return JSON(); + } +} + +JSON JSON::Load( const string &str ) { + size_t offset = 0; + return std::move( parse_next( str, offset ) ); +} + +} // End Namespace json diff --git a/19-object-oriented-programming/external/json_test.cpp b/19-object-oriented-programming/external/json_test.cpp new file mode 100644 index 0000000..e20cbad --- /dev/null +++ b/19-object-oriented-programming/external/json_test.cpp @@ -0,0 +1,39 @@ +#include +using namespace std; + +#include "json.hpp" +using namespace json; + +int main() { + json::JSON obj; + // Create a new Array as a field of an Object. + obj["array"] = json::Array(true, "Two", 3, 4.0); + // Create a new Object as a field of another Object. + obj["obj"] = Object(); + // Assign to one of the inner object's fields + obj["obj"]["inner"] = "Inside"; + + // We don't need to specify the type of the JSON object: + obj["new"]["some"]["deep"]["key"] = "Value"; + obj["array2"].append(false, "three"); + + // We can also parse a string into a JSON object: + obj["parsed"] = JSON::Load("[ { \"Key\" : \"Value\" }, false ]"); + + ////////////////////////////// + + // We can directly print to screen + cout<