diff --git a/application.cpp b/application.cpp index dc1a944..e91accb 100644 --- a/application.cpp +++ b/application.cpp @@ -4,14 +4,14 @@ // Hardcoded for now const sf::Time TIME_PER_SECOND = sf::seconds(1.f / 60.f); -Application::Application() : - render_window({SCREEN_WIDTH, SCREEN_HEIGHT}, "Sliding Puzzle") +Application::Application(unsigned int window_width, unsigned int window_height) : + render_window({window_width, window_height}, "Sliding Puzzle") {} bool Application::init(const std::string &path, int splitting) { render_window.setFramerateLimit(60); - return board.init(path, splitting); + return board.init(path, splitting, render_window); } void Application::run() diff --git a/application.h b/application.h index 5f26532..710d9ba 100644 --- a/application.h +++ b/application.h @@ -6,7 +6,7 @@ class Application { public: - explicit Application(); + explicit Application(unsigned int window_width, unsigned int window_height); // Init game bool init(const std::string& path, int splitting); diff --git a/board.cpp b/board.cpp index 85c843f..a45989e 100644 --- a/board.cpp +++ b/board.cpp @@ -157,7 +157,7 @@ bool Board::isWinCondition() const return std::all_of(vec_field.begin(), vec_field.end(), [](const Cell *cell){ return cell->current_index == cell->inital_index; }); } -bool Board::init(const std::string& path, int splitting) +bool Board::init(const std::string& path, int splitting, const sf::RenderWindow &window) { // PREPARING INITIAL BOARD STATE // @@ -197,24 +197,27 @@ bool Board::init(const std::string& path, int splitting) // SCALING // float scaling = 0.; - if (width > height && width > SCREEN_WIDTH) - scaling = static_cast(SCREEN_WIDTH) / static_cast(width); - if (height > width && height > SCREEN_HEIGHT) - scaling = static_cast(SCREEN_HEIGHT) / static_cast(height); + if (width >= height && width > static_cast(window.getSize().x)) + scaling = static_cast(window.getSize().x) / static_cast(width); + if (height >= width && height > static_cast(window.getSize().y)) + scaling = static_cast(window.getSize().y) / static_cast(height); if (scaling != 0.) { + // Calculating new size of each tile int old_side_length = Cell::side_length; Cell::side_length = static_cast(static_cast(Cell::side_length) * scaling); int shift = Cell::side_length - old_side_length; - float move_x = 0.f; - float move_y = 0.f; + float move_x, move_y; + // Moving all scaled tiles up and left, to remove spacing for (Cells::size_type i = 0; i < vec_field.size(); ++i) { move_x = 0.f; move_y = 0.f; - if (!(((i % cells_on_width == 0) && (i >= cells_on_width)) || i == 0)) + // The first column isn't allowed to move by x + if (!(((i % cells_on_width == 0) && (i >= cells_on_width)))) move_x = static_cast(shift) * static_cast((i < cells_on_width) ? i : i % cells_on_width); + // The first row isn't allowed to move by y if (i >= cells_on_width) move_y = static_cast(shift) * static_cast(i / cells_on_width); diff --git a/board.h b/board.h index cd22b84..532a5da 100644 --- a/board.h +++ b/board.h @@ -8,9 +8,6 @@ using pos = std::pair; -constexpr int SCREEN_WIDTH = 1600; -constexpr int SCREEN_HEIGHT = 900; - enum class DIRECTION { UP, @@ -42,7 +39,7 @@ public: bool isWinCondition() const; // Set play image - bool init(const std::string& path, int splitting); + bool init(const std::string& path, int splitting, const sf::RenderWindow& window); private: diff --git a/filepath_util.h b/filepath_util.h index f11f852..d4fc857 100644 --- a/filepath_util.h +++ b/filepath_util.h @@ -11,13 +11,13 @@ namespace filepath { - static std::tuple getFileInfo(const std::filesystem::directory_entry& entry) + std::tuple getFileInfo(const std::filesystem::directory_entry& entry) { const auto file_status (std::filesystem::status(entry)); return {entry.path(), file_status}; } - static bool endsWith(const std::string& string, const std::string& ending) + bool endsWith(const std::string& string, const std::string& ending) { if (ending.size() > string.size()) return false; @@ -25,7 +25,7 @@ namespace filepath return std::equal(ending.rbegin(), ending.rend(), string.rbegin()); } - static std::tuple parsePath(const std::string &argv) + std::tuple parsePath(const std::string &argv) { std::filesystem::path path(argv); if (!std::filesystem::exists(path)) @@ -67,4 +67,16 @@ namespace filepath srand(static_cast(time(nullptr))); return {EXIT_SUCCESS, dir_image_items[rand() & (dir_image_items.size() - 1)]}; } + + std::vector split(const std::string &s, char delim) + { + std::vector result; + std::stringstream ss (s); + std::string item; + + while (getline(ss, item, delim)) + result.push_back(item); + + return result; + } } diff --git a/main.cpp b/main.cpp index fea8335..cbcfb6b 100644 --- a/main.cpp +++ b/main.cpp @@ -6,96 +6,103 @@ ///////////////////////////////////////////////////////////////////////// -static constexpr int NO_ARGC = 1; -static constexpr int MIN_ARGC = 2; -static constexpr int MAX_ARGC = 4; -static constexpr int DEFAULT_SPLITTING = 5; +static constexpr int DEFAULT_SCREEN_WIDTH = 1280; +static constexpr int DEFAULT_SCREEN_HEIGHT = 720; +static constexpr int DEFAULT_SPLITTING = 4; static const std::string DEFAULT_PATH = "."; // current folder, I guess ///////////////////////////////////////////////////////////////////////// -static std::tuple error(const char* msg) +std::tuple error(const char* msg) { std::cout << msg; - return {EXIT_FAILURE, -1, {}}; + return {EXIT_FAILURE, -1, {}, {}}; } -static std::tuple parseInput(int argc, char **argv) +std::tuple parseInput(int argc, char **argv) { int splitting = DEFAULT_SPLITTING; + sf::Vector2i resolution(DEFAULT_SCREEN_WIDTH, DEFAULT_SCREEN_HEIGHT); std::string path = DEFAULT_PATH; - switch (argc) + for (int current_arg = 1; current_arg < argc; ++current_arg) // current_arg = 0 is executable name { - default: - return error(output::NO_ARG_MSG); + if (strcmp(argv[current_arg], output::HELP_FLAG) == 0) // --help + return error(output::HELP_MSG); - case NO_ARGC: - { - // Just launch the application with default parameters - std::cout << "No arguments given. Launching at \"" << DEFAULT_PATH << "\" with splitting " << std::to_string(DEFAULT_SPLITTING) << "\n" - << "--help for more information.\n"; - const auto &[ret_code, ret_path] = filepath::parsePath(DEFAULT_PATH); + if (strcmp(argv[current_arg], output::SPLITTING_FLAG) == 0) // -s num + { + const int value_rg = current_arg + 1; + if (value_rg == argc) // is '-s' is the last argument + return error(output::SPLITTING_MSG); - if (ret_code) - return error(output::IMG_FAIL_MSG); + splitting = -1; // here assuming user is providing it on their own + if (std::isdigit(*argv[value_rg])) + splitting = std::stoi(argv[value_rg]); - path = ret_path; - break; - } + if (splitting < 2) + return error(output::SPLITTING_MSG); - case MIN_ARGC: - { - // maybe --help - if (strcmp(argv[1], output::HELP_FLAG) == 0) - return error(output::HELP_MSG); + ++current_arg; // skipping value after flag to not check it once again + continue; + } + + if (strcmp(argv[current_arg], output::RESOLUTION_FLAG) == 0) // -r numxnum + { + const int value_rg = current_arg + 1; + if (value_rg == argc) // is '-s' is the last argument + return error(output::RESOLUTION_MSG); + + std::vector res = filepath::split(argv[value_rg], 'x'); // splitting argument by 'x' as in 600x900 - const auto &[ret_code, ret_path] = filepath::parsePath(argv[1]); + if (res.size() < 2) + return error(output::RESOLUTION_MSG); + + resolution = {-1, -1}; + + if (std::isdigit(*res[0].c_str()) && std::isdigit(*res[1].c_str())) + resolution = {std::stoi(res[0].c_str()), std::stoi(res[1].c_str())}; + + if (resolution.x < 1 || resolution.y < 1) + return error(output::RESOLUTION_MSG); + + ++current_arg; // skipping value after flag to not check it once again + continue; + } + + // nothing else, then assuming it's filepath or folderpath + const auto &[ret_code, ret_path] = filepath::parsePath(argv[current_arg]); if (ret_code) return error(output::IMG_FAIL_MSG); path = ret_path; - break; } - case (MAX_ARGC - 1): - case MAX_ARGC: + if (path == DEFAULT_PATH) { - // full stack - if (strcmp(argv[1], output::SPLITTING_FLAG) == 0) - { - splitting = -1; // here assuming user is providing it on their own - if (std::isdigit(*argv[2])) - splitting = std::stoi(argv[2]); + // no path was give, loading random image from '.' + const auto &[ret_code, ret_path] = filepath::parsePath(path); - if (splitting < 2) - return error(output::SPLITTING_MSG); - - const auto &[ret_code, ret_path] = filepath::parsePath(argc == MAX_ARGC ? argv[3] : DEFAULT_PATH); - - if (ret_code) - return error(output::IMG_FAIL_MSG); + if (ret_code) + return error(output::IMG_FAIL_MSG); - path = ret_path; - } - break; - } + path = ret_path; } - return {EXIT_SUCCESS, splitting, path}; + return {EXIT_SUCCESS, splitting, resolution, path}; } ///////////////////////////////////////////////////////////////////////// int main(int argc, char **argv) { - const auto&[ret_code, splitting, path] = parseInput(argc, argv); + const auto&[ret_code, splitting, resolution, path] = parseInput(argc, argv); if (ret_code) // Error code is EXIT_FAILURE return ret_code; - Application app; + Application app(resolution.x, resolution.y); if (app.init(path, splitting)) { app.run(); diff --git a/output_util.h b/output_util.h index 0088792..8f1ce98 100644 --- a/output_util.h +++ b/output_util.h @@ -4,6 +4,7 @@ namespace output { const char* HELP_FLAG = "--help"; const char* SPLITTING_FLAG = "-s"; + const char* RESOLUTION_FLAG = "-r"; const char* NO_ARG_MSG = "Please at least provide a path to a target image. --help for more information.\n"; const char* HELP_MSG = "usage: sliding-puzzle [-OPTIONS...] FILE-OR-DIRECTORY\n\n" @@ -18,4 +19,6 @@ namespace output " will be num * num.\n"; const char* SPLITTING_MSG = "-s should be given with a positive num >= 2 as in [-s num].\n"; const char* IMG_FAIL_MSG = "Couldn't load image from given path.\n"; + const char* RESOLUTION_MSG = "Couldn't recognize given screen resolution.\n" + "Please it provide as in [NUMxNUM], 1280x720, 1600x900, etc.\n"; }