Implement basic terminal output parsing

This commit is contained in:
NaiJi ✨ 2020-12-17 01:13:49 +03:00
parent f76da9f5bc
commit ea4aa3c36c
7 changed files with 171 additions and 72 deletions

View File

@ -10,12 +10,16 @@ Application::Application() :
render_window({SCREEN_WIDTH, SCREEN_HEIGHT}, "Sliding Puzzle") render_window({SCREEN_WIDTH, SCREEN_HEIGHT}, "Sliding Puzzle")
{} {}
void Application::run() bool Application::init(int splitting, const std::string &path)
{ {
render_window.setFramerateLimit(60); render_window.setFramerateLimit(60);
render_window.display(); return board.init(splitting, path);
}
void Application::run()
{
// Main game cycle // Main game cycle
render_window.display();
while (render_window.isOpen()) while (render_window.isOpen())
{ {
processInput(); processInput();

View File

@ -8,6 +8,9 @@ class Application
public: public:
explicit Application(); explicit Application();
// Init game
bool init(int splitting, const std::string& path);
// Launch game // Launch game
void run(); void run();

128
board.cpp
View File

@ -2,70 +2,10 @@
#include <cstdlib> #include <cstdlib>
#include <iostream> #include <iostream>
const std::string picture_dest = "art.png"; Board::Board() :
Board::Board(int splitting) :
selection_index(0), selection_index(0),
on_selection(false) on_selection(false)
{ {}
// PREPARING INITIAL BOARD STATE //
if (!global_texture.loadFromFile(picture_dest) )
return;
if (splitting <= 1) // If it's 1, the game is already over
{
sf::Sprite* sp = new sf::Sprite(global_texture);
vec_field.push_back(new Cell{0, 0, sp});
return;
}
const int width = global_texture.getSize().x;
const int height = global_texture.getSize().y;
Cell::side_length = (width < height) ? width / splitting : height / splitting;
cells_on_height = height / Cell::side_length;
cells_on_width = width / Cell::side_length;
vec_field.reserve(cells_on_height * cells_on_width);
/* Iterating board cells' screen positions.
* The initial image after this would look exactly like the loaded picture, not shuffled yet. */
Cells::size_type index = 0;
for (int x = 0; x < height; x += Cell::side_length)
{
if ((height - x) >= Cell::side_length)
{
for (int y = 0; y < width; y += Cell::side_length)
{
if ((width - y) >= Cell::side_length)
{
sf::Sprite* sp = new sf::Sprite(global_texture, sf::IntRect(y, x, Cell::side_length, Cell::side_length));
sp->setPosition(static_cast<float>(y), static_cast<float>(x));
vec_field.push_back(new Cell({index, index, sp}));
++index;
}
}
}
}
// SHUFFLING //
srand(static_cast<unsigned int>(time(nullptr)));
for (Cells::size_type curr_i = 0; curr_i < vec_field.size(); ++curr_i)
{
Cells::size_type swap_i;
do
{ // find two different tiles
swap_i = rand() & (vec_field.size() - 1);
} while (curr_i == swap_i);
swapCells(curr_i, swap_i);
}
setSelectionVertex(selection_index);
}
Board::~Board() Board::~Board()
{ {
@ -217,4 +157,68 @@ bool Board::isWinCondition() const
return std::all_of(vec_field.begin(), vec_field.end(), [](const Cell *cell){ return cell->current_index == cell->inital_index; }); return std::all_of(vec_field.begin(), vec_field.end(), [](const Cell *cell){ return cell->current_index == cell->inital_index; });
} }
bool Board::init(int splitting, const std::string& path)
{
// PREPARING INITIAL BOARD STATE //
if (!global_texture.loadFromFile(path) )
return EXIT_FAILURE;
if (splitting <= 1) // If it's 1, the game is already over
{
sf::Sprite* sp = new sf::Sprite(global_texture);
vec_field.push_back(new Cell{0, 0, sp});
return EXIT_SUCCESS; // why not
}
const int width = global_texture.getSize().x;
const int height = global_texture.getSize().y;
Cell::side_length = (width < height) ? width / splitting : height / splitting;
cells_on_height = height / Cell::side_length;
cells_on_width = width / Cell::side_length;
vec_field.reserve(cells_on_height * cells_on_width);
/* Iterating board cells' screen positions.
* The initial image after this would look exactly like the loaded picture, not shuffled yet. */
Cells::size_type index = 0;
for (int x = 0; x < height; x += Cell::side_length)
{
if ((height - x) >= Cell::side_length)
{
for (int y = 0; y < width; y += Cell::side_length)
{
if ((width - y) >= Cell::side_length)
{
sf::Sprite* sp = new sf::Sprite(global_texture, sf::IntRect(y, x, Cell::side_length, Cell::side_length));
sp->setPosition(static_cast<float>(y), static_cast<float>(x));
vec_field.push_back(new Cell({index, index, sp}));
++index;
}
}
}
}
// SHUFFLING //
srand(static_cast<unsigned int>(time(nullptr)));
for (Cells::size_type curr_i = 0; curr_i < vec_field.size(); ++curr_i)
{
Cells::size_type swap_i;
do
{ // find two different tiles
swap_i = rand() & (vec_field.size() - 1);
} while (curr_i == swap_i);
swapCells(curr_i, swap_i);
}
// Set initial position of cursor
setSelectionVertex(selection_index);
return EXIT_SUCCESS;
}
int Board::Cell::side_length = 0; int Board::Cell::side_length = 0;

11
board.h
View File

@ -23,7 +23,7 @@ enum class DIRECTION
class Board class Board
{ {
public: public:
explicit Board(int splitting = 1); explicit Board();
~Board(); ~Board();
// Output current graphical state on application window // Output current graphical state on application window
@ -38,25 +38,28 @@ public:
// Did player win the game // Did player win the game
bool isWinCondition() const; bool isWinCondition() const;
// Set play image
bool init(int splitting, const std::string& path);
private: private:
// Game tile // Game tile
struct Cell struct Cell
{ {
std::vector<Cell>::size_type inital_index; std::vector<Cell*>::size_type inital_index;
std::vector<Cell>::size_type current_index; std::vector<Cell*>::size_type current_index;
sf::Sprite *sprite; sf::Sprite *sprite;
static int side_length; static int side_length;
}; };
using Cells = std::vector<Cell*>; using Cells = std::vector<Cell*>;
using RefCells = std::vector<Cells::size_type>;
sf::VertexArray rect_selection; sf::VertexArray rect_selection;
Cells::size_type selection_index; Cells::size_type selection_index;
Cells::size_type cells_on_width; // amount of cells on horizontal side of board Cells::size_type cells_on_width; // amount of cells on horizontal side of board
Cells::size_type cells_on_height; // amount of cells on vertical side of board Cells::size_type cells_on_height; // amount of cells on vertical side of board
Cells vec_field; Cells vec_field;
sf::Texture global_texture; sf::Texture global_texture;
bool on_selection; bool on_selection;

View File

@ -1,7 +1,70 @@
#include "application.h" #include "application.h"
#include "output_util.h"
#include <iostream>
#include <cstring>
#include <cctype>
int main() constexpr static int MIN_ARGC = 2;
constexpr static int MAX_ARGC = 4;
static std::tuple<int, int, std::string> error(const char* msg)
{ {
Application game; std::cout << msg;
game.run(); return {EXIT_FAILURE, 0, {}};
}
static std::tuple<int, int, std::string> parseInput(int argc, char **argv)
{
int splitting = -1;
std::string path;
switch (argc)
{
default:
return error(output::NO_ARG_MSG);
case MIN_ARGC:
// maybe --help
if (strcmp(argv[1], output::HELP_FLAG) == 0)
return error(output::HELP_MSG);
/* HERE PARSE FILEPATH INSTEAD */ return error(output::NO_ARG_MSG);
break;
case (MAX_ARGC - 1):
case MAX_ARGC:
// full stack
if (strcmp(argv[1], output::SPLITTING_FLAG) == 0)
{
if (std::isdigit(*argv[2]))
splitting = std::stoi(argv[2]);
if (splitting < 1)
return error(output::SPLITTING_MSG);
/* HERE PARSE FILEPATH INSTEAD */ return error(output::NO_ARG_MSG);
}
return error(output::NO_ARG_MSG);
break;
}
return {EXIT_SUCCESS, splitting, path};
}
int main(int argc, char **argv)
{
auto[ret_code, splitting, path] = parseInput(argc, argv);
if (ret_code) // Error code is EXIT_FAILURE
return ret_code;
Application app;
if (app.init(splitting, path))
{
app.run();
return EXIT_SUCCESS;
}
return EXIT_FAILURE;
} }

21
output_util.h Normal file
View File

@ -0,0 +1,21 @@
#pragma once
namespace output {
const char* HELP_FLAG = "--help";
const char* SPLITTING_FLAG = "-s";
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"
" Necessarily provide the latter variable as path to either a directory\n"
" which contains arts (one will be picked randomly) or a specific\n"
" image file of .bmp, .dds, .jpg, .png, .tga, or .psd format.\n\n"
" Options:\n"
" [-s num] Provide it if you want to explicitly define\n"
" qualifier for image slicing, it's counted\n"
" by the smallest side of given source texture.\n"
" Hence, if your image is square, the amount of tiles\n"
" will be num * num.\n";
const char* SPLITTING_MSG = "-s should be given with a positive num as in [-s num].\n";
}

View File

@ -12,6 +12,7 @@ SOURCES += \
HEADERS += \ HEADERS += \
board.h \ board.h \
filepath_util.h \ filepath_util.h \
application.h application.h \
output_util.h
unix:LIBS += -lsfml-graphics -lsfml-audio -lsfml-window -lsfml-system unix:LIBS += -lsfml-graphics -lsfml-audio -lsfml-window -lsfml-system