From 9efb8a2b19f22d013491da7c019f10713a04970f Mon Sep 17 00:00:00 2001 From: Sangbum Kim Date: Fri, 12 Oct 2018 13:01:03 +0900 Subject: [PATCH 1/3] added: theme feature Added Themes class to handle theming and applied to game --- src/game.cpp | 8 +++++--- src/headers/game.hpp | 2 ++ src/headers/scores.hpp | 4 ++-- src/headers/themes.hpp | 29 ++++++++++++++++++++++++++++ src/scores.cpp | 4 ++-- src/themes.cpp | 43 ++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 83 insertions(+), 7 deletions(-) create mode 100644 src/headers/themes.hpp create mode 100644 src/themes.cpp diff --git a/src/game.cpp b/src/game.cpp index 28b9b3d2..c5fed472 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -207,7 +207,8 @@ void Game::drawBoard() { std::cout << " "; } else { std::cout << currentTile.tileColor(currentTile.value) << bold_on - << std::setw(4) << currentTile.value << bold_off << def; + << std::setw(4) << themes.themedOutput(currentTile.value) + << bold_off << def; } } @@ -544,7 +545,7 @@ void Game::statistics() { endl(); std::cout << " Final score: " << bold_on << score << bold_off; endl(); - std::cout << " Largest Tile: " << bold_on << largestTile << bold_off; + std::cout << " Largest Tile: " << bold_on << themes.themedOutput(largestTile) << bold_off; endl(); std::cout << " Number of moves: " << bold_on << moveCount << bold_off; endl(); @@ -577,7 +578,7 @@ void Game::saveScore() { s.score = score; s.win = win; s.moveCount = moveCount; - s.largestTile = largestTile; + s.largestTile = themes.themedOutput(largestTile); s.duration = duration; s.save(); } @@ -688,6 +689,7 @@ void Game::startGame() { } setBoardSize(); + themes.chooseTheme(); initialiseBoardArray(); addTile(); diff --git a/src/headers/game.hpp b/src/headers/game.hpp index 185d09a8..e1961243 100644 --- a/src/headers/game.hpp +++ b/src/headers/game.hpp @@ -5,6 +5,7 @@ #include "global.hpp" #include "scores.hpp" #include "statistics.hpp" +#include "themes.hpp" #include #include #include @@ -62,6 +63,7 @@ class Game { RandInt randInt; bool stateSaved; bool noSave; + Themes themes; enum ContinueStatus { STATUS_END_GAME = 0, STATUS_CONTINUE = 1 }; enum KeyInputErrorStatus { STATUS_INPUT_VALID = 0, STATUS_INPUT_ERROR = 1 }; diff --git a/src/headers/scores.hpp b/src/headers/scores.hpp index 0197b8b7..b4073cdc 100644 --- a/src/headers/scores.hpp +++ b/src/headers/scores.hpp @@ -14,7 +14,7 @@ struct Score { std::string name; ull score; bool win; - ull largestTile; + std::string largestTile; long long moveCount; double duration; }; @@ -31,7 +31,7 @@ class Scoreboard { public: ull score = 0; bool win; - ull largestTile; + std::string largestTile; long long moveCount; double duration; void printScore(); diff --git a/src/headers/themes.hpp b/src/headers/themes.hpp new file mode 100644 index 00000000..db8ff773 --- /dev/null +++ b/src/headers/themes.hpp @@ -0,0 +1,29 @@ +#ifndef THEMES_H +#define THEMES_H + +#include "color.hpp" +#include "global.hpp" +#include +#include +#include + +class Themes { +public: + Themes() + : fibonacci_numbers{1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 377, 610}, + elements{"H", "He", "Li", "Be", "B", "C", "N", + "O", "F", "Ne", "Na", "Ca", "Sc"}, + programming_languages{"C", "C++", "PHP", "C#", "Py", "Bash", "Java", + "SQL", "CSS", "HTML", "JS", "Go", "Rust"} {} + std::string themedOutput(ull value); + void chooseTheme(); + +private: + int themeCode = 0; + const int themeCount = 4; + std::vector elements; + std::vector programming_languages; + std::vector fibonacci_numbers; +}; + +#endif diff --git a/src/scores.cpp b/src/scores.cpp index 552ad5f9..4f191485 100644 --- a/src/scores.cpp +++ b/src/scores.cpp @@ -40,7 +40,7 @@ void Scoreboard::printScore() { ull playerScore = scoreList[i].score; std::string won = scoreList[i].win ? "Yes" : "No"; long long moveCount = scoreList[i].moveCount; - ull largestTile = scoreList[i].largestTile; + std::string largestTile = scoreList[i].largestTile; double duration = scoreList[i].duration; if (i == size - 1) { @@ -143,7 +143,7 @@ void Scoreboard::readFile() { std::string playerName; ull playerScore; bool win; - ull largestTile; + std::string largestTile; long long moveCount; double duration; diff --git a/src/themes.cpp b/src/themes.cpp new file mode 100644 index 00000000..dced5120 --- /dev/null +++ b/src/themes.cpp @@ -0,0 +1,43 @@ +#include "themes.hpp" +#include "menu.hpp" + +std::string Themes::themedOutput(ull value) { + switch (themeCode) { + case 1: + return std::to_string(value); + case 2: + return elements[log2(value) - 1]; + case 3: + return std::to_string(fibonacci_numbers[log2(value) - 1]); + case 4: + return programming_languages[log2(value) - 1]; + default: + return "ERR"; + } +} + +void Themes::chooseTheme() { + bool err = false; + while ((themeCode > themeCount || themeCode < 1)) { + clearScreen(); + drawAscii(); + + if (err) { + std::cout << red + << " Invalid input. Theme number should range from 1 to " + << themeCount << "." << def; + endl(2); + } + + std::cout << bold_on << " 1. Standard: 2, 4, 8, ..." << std::endl + << " 2. Elements: H, He, Li, ..." << std::endl + << " 3. Fibonacci Numbers: 1, 2, 3, ..." << std::endl + << " 4. Programming Languages: C, C++, PHP, ..." << std::endl + << " Enter theme number: " << bold_off; + + std::cin >> themeCode; + std::cin.clear(); + std::cin.ignore(std::numeric_limits::max(), '\n'); + err = true; + } +} \ No newline at end of file From b9920fe5489c427f9112d2216210de1a86afb82a Mon Sep 17 00:00:00 2001 From: Sangbum Kim Date: Thu, 18 Oct 2018 11:50:45 +0900 Subject: [PATCH 2/3] fix: seperate Theme and ThemeController Seperated class Themes into Theme and ThemeController to make it more generic and easily expandable --- src/game.cpp | 9 +++--- src/headers/game.hpp | 3 +- src/headers/themes.hpp | 44 ++++++++++++++++++-------- src/themes.cpp | 71 +++++++++++++++++++++++++++++------------- 4 files changed, 88 insertions(+), 39 deletions(-) diff --git a/src/game.cpp b/src/game.cpp index c5fed472..a3d099be 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -207,7 +207,7 @@ void Game::drawBoard() { std::cout << " "; } else { std::cout << currentTile.tileColor(currentTile.value) << bold_on - << std::setw(4) << themes.themedOutput(currentTile.value) + << std::setw(4) << theme.themedOutput(currentTile.value) << bold_off << def; } } @@ -545,7 +545,7 @@ void Game::statistics() { endl(); std::cout << " Final score: " << bold_on << score << bold_off; endl(); - std::cout << " Largest Tile: " << bold_on << themes.themedOutput(largestTile) << bold_off; + std::cout << " Largest Tile: " << bold_on << theme.themedOutput(largestTile) << bold_off; endl(); std::cout << " Number of moves: " << bold_on << moveCount << bold_off; endl(); @@ -578,7 +578,7 @@ void Game::saveScore() { s.score = score; s.win = win; s.moveCount = moveCount; - s.largestTile = themes.themedOutput(largestTile); + s.largestTile = theme.themedOutput(largestTile); s.duration = duration; s.save(); } @@ -689,7 +689,8 @@ void Game::startGame() { } setBoardSize(); - themes.chooseTheme(); + loadThemes(themeController); + theme = themeController.chooseTheme(); initialiseBoardArray(); addTile(); diff --git a/src/headers/game.hpp b/src/headers/game.hpp index e1961243..31bd37e3 100644 --- a/src/headers/game.hpp +++ b/src/headers/game.hpp @@ -63,7 +63,8 @@ class Game { RandInt randInt; bool stateSaved; bool noSave; - Themes themes; + Theme theme; + ThemeController themeController; enum ContinueStatus { STATUS_END_GAME = 0, STATUS_CONTINUE = 1 }; enum KeyInputErrorStatus { STATUS_INPUT_VALID = 0, STATUS_INPUT_ERROR = 1 }; diff --git a/src/headers/themes.hpp b/src/headers/themes.hpp index db8ff773..855d5693 100644 --- a/src/headers/themes.hpp +++ b/src/headers/themes.hpp @@ -6,24 +6,42 @@ #include #include #include +#include +#include -class Themes { +std::vector intv_to_strv(std::vector intv); + +class Theme { public: - Themes() - : fibonacci_numbers{1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 377, 610}, - elements{"H", "He", "Li", "Be", "B", "C", "N", - "O", "F", "Ne", "Na", "Ca", "Sc"}, - programming_languages{"C", "C++", "PHP", "C#", "Py", "Bash", "Java", - "SQL", "CSS", "HTML", "JS", "Go", "Rust"} {} + Theme() = default; + Theme(std::string _theme_name, std::vector _themed_output) + : theme_name(std::move(_theme_name)), + themed_output(std::move(_themed_output)){}; + Theme(std::string _theme_name, std::vector _themed_output) + : theme_name(std::move(_theme_name)), + themed_output(intv_to_strv(_themed_output)){}; + bool operator==(const Theme &t) const { + return themed_output == t.themed_output; + } std::string themedOutput(ull value); - void chooseTheme(); + std::string menuentry(); private: - int themeCode = 0; - const int themeCount = 4; - std::vector elements; - std::vector programming_languages; - std::vector fibonacci_numbers; + std::string theme_name; + std::vector themed_output; }; +class ThemeController { +public: + ThemeController() = default; + Theme chooseTheme(); + void addTheme(Theme xTheme); + +private: + int theme_code = 0; + std::vector registry; +}; + +void loadThemes(ThemeController &controller); + #endif diff --git a/src/themes.cpp b/src/themes.cpp index dced5120..4a22f215 100644 --- a/src/themes.cpp +++ b/src/themes.cpp @@ -1,24 +1,23 @@ #include "themes.hpp" #include "menu.hpp" -std::string Themes::themedOutput(ull value) { - switch (themeCode) { - case 1: - return std::to_string(value); - case 2: - return elements[log2(value) - 1]; - case 3: - return std::to_string(fibonacci_numbers[log2(value) - 1]); - case 4: - return programming_languages[log2(value) - 1]; - default: - return "ERR"; - } +std::string Theme::themedOutput(ull value) { + return themed_output[log2(value) - 1]; +} + +std::string Theme::menuentry() { + std::ostringstream ret; + ret << theme_name << ": "; + for (int i = 0; i < 3; ++i) + ret << themed_output[i] << ", "; + ret << "..."; + return ret.str(); } -void Themes::chooseTheme() { +Theme ThemeController::chooseTheme() { bool err = false; - while ((themeCode > themeCount || themeCode < 1)) { + ull themeCount = registry.size(); + while ((theme_code > themeCount || theme_code < 1)) { clearScreen(); drawAscii(); @@ -29,15 +28,45 @@ void Themes::chooseTheme() { endl(2); } - std::cout << bold_on << " 1. Standard: 2, 4, 8, ..." << std::endl - << " 2. Elements: H, He, Li, ..." << std::endl - << " 3. Fibonacci Numbers: 1, 2, 3, ..." << std::endl - << " 4. Programming Languages: C, C++, PHP, ..." << std::endl - << " Enter theme number: " << bold_off; + std::cout << bold_on; + for (int i = 1; i <= themeCount; ++i) + std::cout << " " << i << ". " << registry[i - 1].menuentry() + << std::endl; + std::cout << " Enter theme number: " << bold_off; - std::cin >> themeCode; + std::cin >> theme_code; std::cin.clear(); std::cin.ignore(std::numeric_limits::max(), '\n'); err = true; } + return registry[theme_code - 1]; +} + +void ThemeController::addTheme(Theme xTheme) { + for (auto &r : registry) + if (r == xTheme) + return; + registry.push_back(xTheme); +} + +std::vector intv_to_strv(std::vector intv) { + std::vector strv; + strv.reserve(intv.size()); + for (auto &i : intv) { + strv.push_back(std::to_string(i)); + } + return strv; +} + +void loadThemes(ThemeController &controller) { + controller.addTheme(Theme("Standard", {2, 4, 8, 16, 32, 64, 128, 256, 512, + 1024, 2048, 4096, 8192})); + + controller.addTheme(Theme("Elements", {"H", "He", "Li", "Be", "B", "C", "N", + "O", "F", "Ne", "Na", "Ca", "Sc"})); + controller.addTheme(Theme( + "Fibonacci Numbers", {1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 377, 610})); + controller.addTheme(Theme("Programming Languages", + {"C", "C++", "PHP", "C#", "Py", "Bash", "Java", + "SQL", "CSS", "HTML", "JS", "Go", "Rust"})); } \ No newline at end of file From 895ed243b536146ecea6bde7df2f74987971b231 Mon Sep 17 00:00:00 2001 From: Sangbum Kim Date: Fri, 19 Oct 2018 16:14:53 +0900 Subject: [PATCH 3/3] Enhancement: make Theme constructor accept function This patch allows to create themes that has infinitely-long sequence with function, instead of a vector with finite length --- src/headers/themes.hpp | 20 +++++++++++++------- src/themes.cpp | 25 +++++++++++++++++++------ 2 files changed, 32 insertions(+), 13 deletions(-) diff --git a/src/headers/themes.hpp b/src/headers/themes.hpp index 855d5693..3071f549 100644 --- a/src/headers/themes.hpp +++ b/src/headers/themes.hpp @@ -4,10 +4,11 @@ #include "color.hpp" #include "global.hpp" #include +#include #include -#include #include #include +#include std::vector intv_to_strv(std::vector intv); @@ -16,19 +17,24 @@ class Theme { Theme() = default; Theme(std::string _theme_name, std::vector _themed_output) : theme_name(std::move(_theme_name)), - themed_output(std::move(_themed_output)){}; - Theme(std::string _theme_name, std::vector _themed_output) - : theme_name(std::move(_theme_name)), - themed_output(intv_to_strv(_themed_output)){}; + themed_output_vector(std::move(_themed_output)){}; + Theme(std::string _theme_name, + std::function _themed_output_function) + : theme_name(std::move(_theme_name)), themed_output_vector(), + themed_output_function(std::move(_themed_output_function)){}; bool operator==(const Theme &t) const { - return themed_output == t.themed_output; + if (!themed_output_vector.empty()) + return themed_output_vector == t.themed_output_vector; + return false; } std::string themedOutput(ull value); + std::string themedOutputByIndex(int index); std::string menuentry(); private: std::string theme_name; - std::vector themed_output; + std::vector themed_output_vector; + std::function themed_output_function; }; class ThemeController { diff --git a/src/themes.cpp b/src/themes.cpp index 4a22f215..f69f24f8 100644 --- a/src/themes.cpp +++ b/src/themes.cpp @@ -1,15 +1,22 @@ #include "themes.hpp" #include "menu.hpp" +#include std::string Theme::themedOutput(ull value) { - return themed_output[log2(value) - 1]; + return themedOutputByIndex(int(log2(value) - 1)); +} + +std::string Theme::themedOutputByIndex(int index) { + if (!themed_output_vector.empty()) + return themed_output_vector[index]; + return themed_output_function(index); } std::string Theme::menuentry() { std::ostringstream ret; ret << theme_name << ": "; for (int i = 0; i < 3; ++i) - ret << themed_output[i] << ", "; + ret << themedOutputByIndex(i) << ", "; ret << "..."; return ret.str(); } @@ -59,13 +66,19 @@ std::vector intv_to_strv(std::vector intv) { } void loadThemes(ThemeController &controller) { - controller.addTheme(Theme("Standard", {2, 4, 8, 16, 32, 64, 128, 256, 512, - 1024, 2048, 4096, 8192})); + controller.addTheme(Theme( + "Standard", [](int index) { return std::to_string(ull(2) << index); })); controller.addTheme(Theme("Elements", {"H", "He", "Li", "Be", "B", "C", "N", "O", "F", "Ne", "Na", "Ca", "Sc"})); - controller.addTheme(Theme( - "Fibonacci Numbers", {1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 377, 610})); + controller.addTheme(Theme("Fibonacci Numbers", [](int index) { + ull DP[index + 2]; + DP[0] = 1; + DP[1] = 2; + for (int i = 2; i <= index; ++i) + DP[i] = DP[i - 1] + DP[i - 2]; + return std::to_string(DP[index]); + })); controller.addTheme(Theme("Programming Languages", {"C", "C++", "PHP", "C#", "Py", "Bash", "Java", "SQL", "CSS", "HTML", "JS", "Go", "Rust"}));