Init
This commit is contained in:
commit
b42f2c6eaf
|
@ -0,0 +1 @@
|
||||||
|
*.user
|
|
@ -0,0 +1,87 @@
|
||||||
|
#include <SFML/Window/Event.hpp>
|
||||||
|
#include "application.h"
|
||||||
|
|
||||||
|
constexpr int SCREEN_WIDTH = 1280;
|
||||||
|
constexpr int SCREEN_HEIGHT = 720;
|
||||||
|
const sf::Time TIME_PER_SECOND = sf::seconds(1.f / 60.f);
|
||||||
|
|
||||||
|
Application::Application() :
|
||||||
|
render_window({SCREEN_WIDTH, SCREEN_HEIGHT}, "Sliding Puzzle")
|
||||||
|
{}
|
||||||
|
|
||||||
|
void Application::run()
|
||||||
|
{
|
||||||
|
render_window.setFramerateLimit(60);
|
||||||
|
render_window.display();
|
||||||
|
|
||||||
|
while (render_window.isOpen())
|
||||||
|
{
|
||||||
|
processInput();
|
||||||
|
draw();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::draw()
|
||||||
|
{
|
||||||
|
render_window.clear();
|
||||||
|
board.draw(render_window);
|
||||||
|
render_window.setView(render_window.getDefaultView());
|
||||||
|
render_window.display();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Application::processInput()
|
||||||
|
{
|
||||||
|
sf::Event event;
|
||||||
|
while (render_window.pollEvent(event))
|
||||||
|
{
|
||||||
|
switch (event.type)
|
||||||
|
{
|
||||||
|
case sf::Event::Closed:
|
||||||
|
render_window.close();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case sf::Event::KeyPressed:
|
||||||
|
if (board.isWinCondition())
|
||||||
|
return true;
|
||||||
|
if (event.key.code == sf::Keyboard::Z)
|
||||||
|
board.onSelectionMode();
|
||||||
|
else
|
||||||
|
board.moveSelection(getDirection(event.key.code));
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
DIRECTION Application::getDirection(sf::Keyboard::Key &key) const
|
||||||
|
{
|
||||||
|
switch (key)
|
||||||
|
{
|
||||||
|
case sf::Keyboard::A:
|
||||||
|
case sf::Keyboard::Left:
|
||||||
|
case sf::Keyboard::Num4:
|
||||||
|
return DIRECTION::LEFT;
|
||||||
|
|
||||||
|
case sf::Keyboard::W:
|
||||||
|
case sf::Keyboard::Up:
|
||||||
|
case sf::Keyboard::Num8:
|
||||||
|
return DIRECTION::UP;
|
||||||
|
|
||||||
|
case sf::Keyboard::D:
|
||||||
|
case sf::Keyboard::Right:
|
||||||
|
case sf::Keyboard::Num6:
|
||||||
|
return DIRECTION::RIGHT;
|
||||||
|
|
||||||
|
case sf::Keyboard::S:
|
||||||
|
case sf::Keyboard::Down:
|
||||||
|
case sf::Keyboard::Num2:
|
||||||
|
return DIRECTION::DOWN;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return DIRECTION::NONE;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <SFML/Window/Keyboard.hpp>
|
||||||
|
#include "board.h"
|
||||||
|
|
||||||
|
class Application
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit Application();
|
||||||
|
|
||||||
|
void run();
|
||||||
|
void draw();
|
||||||
|
bool processInput();
|
||||||
|
|
||||||
|
private:
|
||||||
|
DIRECTION getDirection(sf::Keyboard::Key &key) const;
|
||||||
|
|
||||||
|
Board board;
|
||||||
|
sf::RenderWindow render_window;
|
||||||
|
};
|
|
@ -0,0 +1,216 @@
|
||||||
|
#include "board.h"
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
const std::string picture_dest = "art.png";
|
||||||
|
|
||||||
|
Board::Board(int splitting) :
|
||||||
|
selection_index(0),
|
||||||
|
on_selection(false)
|
||||||
|
{
|
||||||
|
// PREPARING INITIAL BOARD STATE //
|
||||||
|
|
||||||
|
if (!global_texture.loadFromFile(picture_dest) )
|
||||||
|
return;
|
||||||
|
|
||||||
|
const float width = global_texture.getSize().x;
|
||||||
|
const float 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);
|
||||||
|
vec_ref.reserve(vec_field.size());
|
||||||
|
|
||||||
|
/* 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(y, x);
|
||||||
|
|
||||||
|
vec_field.push_back({index, index, sp});
|
||||||
|
vec_ref.push_back(index);
|
||||||
|
++index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SHUFFLING //
|
||||||
|
|
||||||
|
srand(static_cast<unsigned int>(time(nullptr)));
|
||||||
|
for (Cells::iterator curr_it = vec_field.begin(); curr_it != vec_field.end(); ++curr_it)
|
||||||
|
{
|
||||||
|
bool success = false;
|
||||||
|
while (!success)
|
||||||
|
{
|
||||||
|
Cells::iterator swap_it = cellByCurrentIndex(rand() & (vec_field.size() - 1));
|
||||||
|
if (curr_it->current_index == swap_it->current_index)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
swapCells(curr_it, swap_it);
|
||||||
|
success = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setSelectionVertex(selection_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
Board::~Board()
|
||||||
|
{
|
||||||
|
for (Cell& cell : vec_field)
|
||||||
|
delete cell.sprite;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Board::draw(sf::RenderWindow& window)
|
||||||
|
{
|
||||||
|
for (const Cell& cell : vec_field)
|
||||||
|
window.draw(*cell.sprite);
|
||||||
|
|
||||||
|
window.draw(rect_selection);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Board::moveSelection(const DIRECTION &direction)
|
||||||
|
{
|
||||||
|
if (!on_selection)
|
||||||
|
{
|
||||||
|
switch (direction) {
|
||||||
|
case DIRECTION::UP:
|
||||||
|
if (selection_index < cells_on_width) // if upper row
|
||||||
|
return false;
|
||||||
|
selection_index -= cells_on_width;
|
||||||
|
setSelectionVertex(selection_index);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DIRECTION::DOWN:
|
||||||
|
if (selection_index > (cells_on_width * (cells_on_height - 1))) // if bottom row
|
||||||
|
return false;
|
||||||
|
selection_index += cells_on_width;
|
||||||
|
setSelectionVertex(selection_index);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DIRECTION::RIGHT:
|
||||||
|
++selection_index;
|
||||||
|
if (selection_index == vec_field.size()) // if the last cell of right bottom corner
|
||||||
|
selection_index = 0; // move to the first cell of upper left corner
|
||||||
|
setSelectionVertex(selection_index);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DIRECTION::LEFT:
|
||||||
|
if (selection_index == 0) // if the first cell of of upper left corner
|
||||||
|
selection_index = vec_field.size() - 1; // move to the last cell of right bottom corner
|
||||||
|
else
|
||||||
|
--selection_index;
|
||||||
|
setSelectionVertex(selection_index);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (direction) {
|
||||||
|
case DIRECTION::UP:
|
||||||
|
if (selection_index < cells_on_width) // if upper row
|
||||||
|
return false;
|
||||||
|
swapCells(cellByCurrentIndex(selection_index), cellByCurrentIndex(selection_index - cells_on_width));
|
||||||
|
selection_index -= cells_on_width;
|
||||||
|
setSelectionVertex(selection_index);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DIRECTION::DOWN:
|
||||||
|
if (selection_index > (cells_on_width * (cells_on_height - 1))) // if bottom row
|
||||||
|
return false;
|
||||||
|
swapCells(cellByCurrentIndex(selection_index), cellByCurrentIndex(selection_index + cells_on_width));
|
||||||
|
selection_index += cells_on_width;
|
||||||
|
setSelectionVertex(selection_index);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DIRECTION::RIGHT:
|
||||||
|
if ((selection_index + 1) % cells_on_width == 0)
|
||||||
|
return false;
|
||||||
|
swapCells(cellByCurrentIndex(selection_index), cellByCurrentIndex(selection_index + 1));
|
||||||
|
++selection_index;
|
||||||
|
setSelectionVertex(selection_index);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DIRECTION::LEFT:
|
||||||
|
if (((selection_index % cells_on_width == 0) && (selection_index > cells_on_width)) || selection_index == 0)
|
||||||
|
return false;
|
||||||
|
swapCells(cellByCurrentIndex(selection_index), cellByCurrentIndex(selection_index - 1));
|
||||||
|
--selection_index;
|
||||||
|
setSelectionVertex(selection_index);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
on_selection = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Board::onSelectionMode()
|
||||||
|
{
|
||||||
|
on_selection = !on_selection;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Board::setSelectionVertex(Cells::size_type index)
|
||||||
|
{
|
||||||
|
const auto& cell = cellByCurrentIndex(index);
|
||||||
|
const auto& pos = cell->sprite->getPosition();
|
||||||
|
const auto& x = pos.x;
|
||||||
|
const auto& y = pos.y;
|
||||||
|
const float length = static_cast<float>(Cell::side_length);
|
||||||
|
|
||||||
|
rect_selection = sf::VertexArray(sf::LinesStrip, 5);
|
||||||
|
rect_selection[0].position = pos;
|
||||||
|
rect_selection[0].color = sf::Color::Red;
|
||||||
|
rect_selection[1].position = sf::Vector2f(x + length, y);
|
||||||
|
rect_selection[1].color = sf::Color::Red;
|
||||||
|
rect_selection[2].position = sf::Vector2f(x + length, y + length);
|
||||||
|
rect_selection[2].color = sf::Color::Red;
|
||||||
|
rect_selection[3].position = sf::Vector2f(x, y + length);
|
||||||
|
rect_selection[3].color = sf::Color::Red;
|
||||||
|
rect_selection[4].position = pos;
|
||||||
|
rect_selection[4].color = sf::Color::Red;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Board::swapCells(Cells::size_type curr_cell_ind, Cells::size_type swap_cell_ind)
|
||||||
|
{
|
||||||
|
auto& curr_cell = vec_field[curr_cell_ind];
|
||||||
|
auto& swap_cell = vec_field[swap_cell_ind];
|
||||||
|
const sf::Vector2f temp_pos = curr_cell.sprite->getPosition();
|
||||||
|
const Cells::size_type temp_cell_index = curr_cell.current_index;
|
||||||
|
|
||||||
|
curr_cell.sprite->setPosition(vec_field[swap_cell_ind].sprite->getPosition());
|
||||||
|
curr_cell.current_index = vec_field[swap_cell_ind].current_index;
|
||||||
|
|
||||||
|
swap_cell.sprite->setPosition(temp_pos);
|
||||||
|
swap_cell.current_index = temp_cell_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
Board::Cells::iterator Board::cellByCurrentIndex(Cells::size_type index)
|
||||||
|
{
|
||||||
|
return std::find_if(vec_field.begin(), vec_field.end(), [&](const Cell& cell) { return cell.current_index == index; });
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Board::isWinCondition() const
|
||||||
|
{
|
||||||
|
return std::all_of(vec_field.begin(), vec_field.end(), [](const Cell& cell){ return cell.current_index == cell.inital_index; });
|
||||||
|
}
|
||||||
|
|
||||||
|
int Board::Cell::side_length = 0;
|
|
@ -0,0 +1,58 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <SFML/Graphics/RenderWindow.hpp>
|
||||||
|
#include <SFML/Graphics/VertexArray.hpp>
|
||||||
|
#include <SFML/Graphics/Texture.hpp>
|
||||||
|
#include <SFML/Graphics/Sprite.hpp>
|
||||||
|
#include <array>
|
||||||
|
|
||||||
|
using pos = std::pair<int, int>;
|
||||||
|
|
||||||
|
enum class DIRECTION
|
||||||
|
{
|
||||||
|
UP,
|
||||||
|
DOWN,
|
||||||
|
RIGHT,
|
||||||
|
LEFT,
|
||||||
|
|
||||||
|
NONE
|
||||||
|
};
|
||||||
|
|
||||||
|
class Board
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit Board(int splitting = 6);
|
||||||
|
~Board();
|
||||||
|
|
||||||
|
void draw(sf::RenderWindow& window);
|
||||||
|
bool moveSelection(const DIRECTION& direction);
|
||||||
|
void onSelectionMode();
|
||||||
|
bool isWinCondition() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
struct Cell
|
||||||
|
{
|
||||||
|
std::vector<Cell>::size_type inital_index;
|
||||||
|
std::vector<Cell>::size_type current_index;
|
||||||
|
sf::Sprite *sprite;
|
||||||
|
static float side_length;
|
||||||
|
};
|
||||||
|
|
||||||
|
using Cells = std::vector<Cell>;
|
||||||
|
using RefCells = std::vector<Cells::size_type>;
|
||||||
|
|
||||||
|
sf::VertexArray rect_selection;
|
||||||
|
Cells::size_type selection_index;
|
||||||
|
|
||||||
|
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 vec_field;
|
||||||
|
RefCells vec_ref; // map to actual index
|
||||||
|
sf::Texture global_texture;
|
||||||
|
bool on_selection;
|
||||||
|
|
||||||
|
void setSelectionVertex(Cells::size_type index);
|
||||||
|
void swapCells(Cells::size_type curr_cell_ind, Cells::size_type swap_cell_ind);
|
||||||
|
Cells::iterator cellByCurrentIndex(Cells::size_type index);
|
||||||
|
};
|
|
@ -0,0 +1,16 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <numeric>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <vector>
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
|
static std::tuple<std::filesystem::path, std::filesystem::file_status, size_t> file_info(const std::filesystem::directory_entry& entry)
|
||||||
|
{
|
||||||
|
const auto fs (std::filesystem::status(entry));
|
||||||
|
return {entry.path(),
|
||||||
|
fs,
|
||||||
|
std::filesystem::is_regular_file(fs) ? std::filesystem::file_size(entry.path()) : 0u};
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
#include "gamestate.h"
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
GameState game;
|
||||||
|
game.run();
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
TEMPLATE = app
|
||||||
|
QMAKE_CXXFLAGS = -Wall -Werror -Wextra -Wpedantic -Wconversion -std=c++17 -O2 -g
|
||||||
|
CONFIG += c++17
|
||||||
|
CONFIG -= app_bundle
|
||||||
|
CONFIG -= qt
|
||||||
|
|
||||||
|
SOURCES += \
|
||||||
|
board.cpp \
|
||||||
|
application.cpp \
|
||||||
|
main.cpp
|
||||||
|
|
||||||
|
HEADERS += \
|
||||||
|
board.h \
|
||||||
|
filepath_util.h \
|
||||||
|
application.h
|
||||||
|
|
||||||
|
unix:LIBS += -lsfml-graphics -lsfml-audio -lsfml-window -lsfml-system
|
Loading…
Reference in New Issue