Implement basic terminal output parsing
This commit is contained in:
parent
f76da9f5bc
commit
ea4aa3c36c
|
@ -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();
|
||||||
|
|
|
@ -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
128
board.cpp
|
@ -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
11
board.h
|
@ -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;
|
||||||
|
|
69
main.cpp
69
main.cpp
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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";
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue