Improve shuffling

This commit is contained in:
NaiJi ✨ 2020-12-14 22:22:52 +03:00
parent b42f2c6eaf
commit f76da9f5bc
5 changed files with 75 additions and 53 deletions

View File

@ -1,6 +1,7 @@
#include <SFML/Window/Event.hpp> #include <SFML/Window/Event.hpp>
#include "application.h" #include "application.h"
// Hardcoded for now
constexpr int SCREEN_WIDTH = 1280; constexpr int SCREEN_WIDTH = 1280;
constexpr int SCREEN_HEIGHT = 720; constexpr int SCREEN_HEIGHT = 720;
const sf::Time TIME_PER_SECOND = sf::seconds(1.f / 60.f); const sf::Time TIME_PER_SECOND = sf::seconds(1.f / 60.f);
@ -14,6 +15,7 @@ void Application::run()
render_window.setFramerateLimit(60); render_window.setFramerateLimit(60);
render_window.display(); render_window.display();
// Main game cycle
while (render_window.isOpen()) while (render_window.isOpen())
{ {
processInput(); processInput();
@ -29,7 +31,7 @@ void Application::draw()
render_window.display(); render_window.display();
} }
bool Application::processInput() void Application::processInput()
{ {
sf::Event event; sf::Event event;
while (render_window.pollEvent(event)) while (render_window.pollEvent(event))
@ -41,11 +43,13 @@ bool Application::processInput()
break; break;
case sf::Event::KeyPressed: case sf::Event::KeyPressed:
// If already won, do nothing
if (board.isWinCondition()) if (board.isWinCondition())
return true; return;
// Go to selection mode
if (event.key.code == sf::Keyboard::Z) if (event.key.code == sf::Keyboard::Z)
board.onSelectionMode(); board.onSelectionMode();
else else // or just move cursor to next tile
board.moveSelection(getDirection(event.key.code)); board.moveSelection(getDirection(event.key.code));
break; break;
@ -53,8 +57,6 @@ bool Application::processInput()
break; break;
} }
} }
return true;
} }
DIRECTION Application::getDirection(sf::Keyboard::Key &key) const DIRECTION Application::getDirection(sf::Keyboard::Key &key) const

View File

@ -8,11 +8,17 @@ class Application
public: public:
explicit Application(); explicit Application();
// Launch game
void run(); void run();
// Refresh render_window to actual state
void draw(); void draw();
bool processInput();
// Handle keyboard commands
void processInput();
private: private:
// Convert keyboard keys into moving direction
DIRECTION getDirection(sf::Keyboard::Key &key) const; DIRECTION getDirection(sf::Keyboard::Key &key) const;
Board board; Board board;

View File

@ -13,15 +13,21 @@ Board::Board(int splitting) :
if (!global_texture.loadFromFile(picture_dest) ) if (!global_texture.loadFromFile(picture_dest) )
return; return;
const float width = global_texture.getSize().x; if (splitting <= 1) // If it's 1, the game is already over
const float height = global_texture.getSize().y; {
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; Cell::side_length = (width < height) ? width / splitting : height / splitting;
cells_on_height = height / Cell::side_length; cells_on_height = height / Cell::side_length;
cells_on_width = width / Cell::side_length; cells_on_width = width / Cell::side_length;
vec_field.reserve(cells_on_height * cells_on_width); vec_field.reserve(cells_on_height * cells_on_width);
vec_ref.reserve(vec_field.size());
/* Iterating board cells' screen positions. /* Iterating board cells' screen positions.
* The initial image after this would look exactly like the loaded picture, not shuffled yet. */ * The initial image after this would look exactly like the loaded picture, not shuffled yet. */
@ -35,10 +41,9 @@ Board::Board(int splitting) :
if ((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)); sf::Sprite* sp = new sf::Sprite(global_texture, sf::IntRect(y, x, Cell::side_length, Cell::side_length));
sp->setPosition(y, x); sp->setPosition(static_cast<float>(y), static_cast<float>(x));
vec_field.push_back({index, index, sp}); vec_field.push_back(new Cell({index, index, sp}));
vec_ref.push_back(index);
++index; ++index;
} }
} }
@ -48,18 +53,15 @@ Board::Board(int splitting) :
// SHUFFLING // // SHUFFLING //
srand(static_cast<unsigned int>(time(nullptr))); srand(static_cast<unsigned int>(time(nullptr)));
for (Cells::iterator curr_it = vec_field.begin(); curr_it != vec_field.end(); ++curr_it) for (Cells::size_type curr_i = 0; curr_i < vec_field.size(); ++curr_i)
{ {
bool success = false; Cells::size_type swap_i;
while (!success) do
{ { // find two different tiles
Cells::iterator swap_it = cellByCurrentIndex(rand() & (vec_field.size() - 1)); swap_i = rand() & (vec_field.size() - 1);
if (curr_it->current_index == swap_it->current_index) } while (curr_i == swap_i);
continue;
swapCells(curr_it, swap_it); swapCells(curr_i, swap_i);
success = true;
}
} }
setSelectionVertex(selection_index); setSelectionVertex(selection_index);
@ -67,14 +69,17 @@ Board::Board(int splitting) :
Board::~Board() Board::~Board()
{ {
for (Cell& cell : vec_field) for (Cell *cell : vec_field)
delete cell.sprite; {
delete cell->sprite;
delete cell;
}
} }
void Board::draw(sf::RenderWindow& window) void Board::draw(sf::RenderWindow& window)
{ {
for (const Cell& cell : vec_field) for (const Cell *cell : vec_field)
window.draw(*cell.sprite); window.draw(*cell->sprite);
window.draw(rect_selection); window.draw(rect_selection);
} }
@ -125,7 +130,7 @@ bool Board::moveSelection(const DIRECTION &direction)
case DIRECTION::UP: case DIRECTION::UP:
if (selection_index < cells_on_width) // if upper row if (selection_index < cells_on_width) // if upper row
return false; return false;
swapCells(cellByCurrentIndex(selection_index), cellByCurrentIndex(selection_index - cells_on_width)); swapCells(selection_index, selection_index - cells_on_width);
selection_index -= cells_on_width; selection_index -= cells_on_width;
setSelectionVertex(selection_index); setSelectionVertex(selection_index);
break; break;
@ -133,7 +138,7 @@ bool Board::moveSelection(const DIRECTION &direction)
case DIRECTION::DOWN: case DIRECTION::DOWN:
if (selection_index > (cells_on_width * (cells_on_height - 1))) // if bottom row if (selection_index > (cells_on_width * (cells_on_height - 1))) // if bottom row
return false; return false;
swapCells(cellByCurrentIndex(selection_index), cellByCurrentIndex(selection_index + cells_on_width)); swapCells(selection_index, selection_index + cells_on_width);
selection_index += cells_on_width; selection_index += cells_on_width;
setSelectionVertex(selection_index); setSelectionVertex(selection_index);
break; break;
@ -141,7 +146,7 @@ bool Board::moveSelection(const DIRECTION &direction)
case DIRECTION::RIGHT: case DIRECTION::RIGHT:
if ((selection_index + 1) % cells_on_width == 0) if ((selection_index + 1) % cells_on_width == 0)
return false; return false;
swapCells(cellByCurrentIndex(selection_index), cellByCurrentIndex(selection_index + 1)); swapCells(selection_index, selection_index + 1);
++selection_index; ++selection_index;
setSelectionVertex(selection_index); setSelectionVertex(selection_index);
break; break;
@ -149,7 +154,7 @@ bool Board::moveSelection(const DIRECTION &direction)
case DIRECTION::LEFT: case DIRECTION::LEFT:
if (((selection_index % cells_on_width == 0) && (selection_index > cells_on_width)) || selection_index == 0) if (((selection_index % cells_on_width == 0) && (selection_index > cells_on_width)) || selection_index == 0)
return false; return false;
swapCells(cellByCurrentIndex(selection_index), cellByCurrentIndex(selection_index - 1)); swapCells(selection_index, selection_index - 1);
--selection_index; --selection_index;
setSelectionVertex(selection_index); setSelectionVertex(selection_index);
break; break;
@ -170,7 +175,7 @@ void Board::onSelectionMode()
void Board::setSelectionVertex(Cells::size_type index) void Board::setSelectionVertex(Cells::size_type index)
{ {
const auto& cell = cellByCurrentIndex(index); const auto& cell = vec_field[index];
const auto& pos = cell->sprite->getPosition(); const auto& pos = cell->sprite->getPosition();
const auto& x = pos.x; const auto& x = pos.x;
const auto& y = pos.y; const auto& y = pos.y;
@ -189,28 +194,27 @@ void Board::setSelectionVertex(Cells::size_type index)
rect_selection[4].color = sf::Color::Red; rect_selection[4].color = sf::Color::Red;
} }
void Board::swapCells(Cells::size_type curr_cell_ind, Cells::size_type swap_cell_ind) void Board::swapCells(Cells::size_type curr_index, Cells::size_type swap_index)
{ {
auto& curr_cell = vec_field[curr_cell_ind]; Cell *curr_cell = vec_field[curr_index];
auto& swap_cell = vec_field[swap_cell_ind]; Cell *swap_cell = vec_field[swap_index];
const sf::Vector2f temp_pos = curr_cell.sprite->getPosition(); const sf::Vector2f temp_pos = curr_cell->sprite->getPosition();
const Cells::size_type temp_cell_index = curr_cell.current_index; const Cells::size_type temp_cell_index = curr_cell->current_index;
curr_cell.sprite->setPosition(vec_field[swap_cell_ind].sprite->getPosition()); curr_cell->sprite->setPosition(swap_cell->sprite->getPosition());
curr_cell.current_index = vec_field[swap_cell_ind].current_index; curr_cell->current_index = swap_cell->current_index;
swap_cell.sprite->setPosition(temp_pos); swap_cell->sprite->setPosition(temp_pos);
swap_cell.current_index = temp_cell_index; swap_cell->current_index = temp_cell_index;
}
Board::Cells::iterator Board::cellByCurrentIndex(Cells::size_type index) Cell* temp = vec_field[curr_index];
{ vec_field[curr_index] = vec_field[swap_index];
return std::find_if(vec_field.begin(), vec_field.end(), [&](const Cell& cell) { return cell.current_index == index; }); vec_field[swap_index] = temp;
} }
bool Board::isWinCondition() const 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; });
} }
int Board::Cell::side_length = 0; int Board::Cell::side_length = 0;

22
board.h
View File

@ -18,28 +18,38 @@ enum class DIRECTION
NONE NONE
}; };
//////////////////////////////////
class Board class Board
{ {
public: public:
explicit Board(int splitting = 6); explicit Board(int splitting = 1);
~Board(); ~Board();
// Output current graphical state on application window
void draw(sf::RenderWindow& window); void draw(sf::RenderWindow& window);
// Move cursor to next tile by given direction
bool moveSelection(const DIRECTION& direction); bool moveSelection(const DIRECTION& direction);
// Go to or leave from selection mode
void onSelectionMode(); void onSelectionMode();
// Did player win the game
bool isWinCondition() const; bool isWinCondition() const;
private: private:
// 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 float side_length; static int side_length;
}; };
using Cells = std::vector<Cell>; using Cells = std::vector<Cell*>;
using RefCells = std::vector<Cells::size_type>; using RefCells = std::vector<Cells::size_type>;
sf::VertexArray rect_selection; sf::VertexArray rect_selection;
@ -48,11 +58,11 @@ private:
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;
RefCells vec_ref; // map to actual index
sf::Texture global_texture; sf::Texture global_texture;
bool on_selection; bool on_selection;
void swapCells(Cells::size_type curr_index, Cells::size_type swap_index);
// Draw selection cursor on given tile
void setSelectionVertex(Cells::size_type index); 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);
}; };

View File

@ -1,7 +1,7 @@
#include "gamestate.h" #include "application.h"
int main() int main()
{ {
GameState game; Application game;
game.run(); game.run();
} }