You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

295 lines
9.3 KiB
C++

#include "board.h"
#include <cstdlib>
#include <iostream>
Board::Board() :
selection_index(0),
solved_tiles(0),
on_selection(false),
is_cursor_visible(true)
{
std::size_t rect_size = 5;
rect_selection = sf::VertexArray(sf::LinesStrip, rect_size);
for (std::size_t i = 0; i < rect_size; ++i)
rect_selection[i].color = sf::Color::Red;
rect_filling.setFillColor(sf::Color(255, 0, 0, 128));
}
Board::~Board()
{
for (Cell *cell : vec_field)
{
delete cell->sprite;
delete cell;
}
}
bool Board::init(const std::string& path, int splitting, const sf::RenderWindow &window)
{
// PREPARING INITIAL BOARD STATE //
if (!global_texture.loadFromFile(path) )
return false;
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;
}
}
}
}
// SCALING //
float scaling = 0.;
if (width >= height && width > static_cast<int>(window.getSize().x))
scaling = static_cast<float>(window.getSize().x) / static_cast<float>(width);
if (height >= width && height > static_cast<int>(window.getSize().y))
scaling = static_cast<float>(window.getSize().y) / static_cast<float>(height);
if (scaling != 0.)
{
// Calculating new size of each tile
int old_side_length = Cell::side_length;
Cell::side_length = static_cast<int>(static_cast<float>(Cell::side_length) * scaling);
int shift = Cell::side_length - old_side_length;
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;
// The first column isn't allowed to move by x
if (!(((i % cells_on_width == 0) && (i >= cells_on_width))))
move_x = static_cast<float>(shift) * static_cast<float>((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<float>(shift) * static_cast<float>(i / cells_on_width);
vec_field[i]->sprite->scale(scaling, scaling);
vec_field[i]->sprite->move(move_x, move_y);
}
}
// SHUFFLING //
solved_tiles = vec_field.size(); // all tiles are solved for now
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 true;
}
void Board::draw(sf::RenderWindow& window)
{
for (const Cell *cell : vec_field)
window.draw(*cell->sprite);
if (on_selection)
window.draw(rect_filling);
if (is_cursor_visible)
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(selection_index, 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(selection_index, 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(selection_index, 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(selection_index, 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;
if (on_selection)
{
rect_filling.setPosition(rect_selection[0].position);
rect_filling.setSize(sf::Vector2f(static_cast<float>(rect_selection[1].position.x - rect_selection[0].position.x),
static_cast<float>(rect_selection[2].position.y - rect_selection[1].position.y)));
}
}
void Board::setSelectionVertex(Cells::size_type index)
{
const auto& cell = vec_field[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[0].position = pos;
rect_selection[1].position = sf::Vector2f(x + length, y);
rect_selection[2].position = sf::Vector2f(x + length, y + length);
rect_selection[3].position = sf::Vector2f(x, y + length);
rect_selection[4].position = pos;
}
void Board::swapCells(Cells::size_type curr_index, Cells::size_type swap_index)
{
// Check if the pair of cells for swapping was initially solved
bool curr_solved = (vec_field[curr_index]->inital_index == vec_field[curr_index]->current_index);
bool swap_solved = (vec_field[swap_index]->inital_index == vec_field[swap_index]->current_index);
Cell *curr_cell = vec_field[curr_index];
Cell *swap_cell = vec_field[swap_index];
const sf::Vector2f temp_pos = curr_cell->sprite->getPosition();
const Cells::size_type temp_cell_index = curr_cell->current_index;
curr_cell->sprite->setPosition(swap_cell->sprite->getPosition());
curr_cell->current_index = swap_cell->current_index;
swap_cell->sprite->setPosition(temp_pos);
swap_cell->current_index = temp_cell_index;
Cell *temp = vec_field[curr_index];
vec_field[curr_index] = vec_field[swap_index];
vec_field[swap_index] = temp;
if ((vec_field[curr_index]->inital_index == vec_field[curr_index]->current_index) && !curr_solved)
// Wasn't solved and NOW is solved
++solved_tiles;
if ((vec_field[curr_index]->inital_index != vec_field[curr_index]->current_index) && curr_solved)
// Was solved and NOW is unsolved
--solved_tiles;
if ((vec_field[swap_index]->inital_index == vec_field[swap_index]->current_index) && !swap_solved)
// Wasn't solved and NOW is solved
++solved_tiles;
if ((vec_field[swap_index]->inital_index != vec_field[swap_index]->current_index) && swap_solved)
// Was solved and NOW is unsolved
--solved_tiles;
}
bool Board::isWinCondition() const
{
return (solved_tiles == vec_field.size());
}
void Board::setCursorVisibility(bool visible)
{
is_cursor_visible = visible;
}
int Board::Cell::side_length = 0;