#include "board.h" #include #include 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) { std::cout << path << '\n'; if (!global_texture.loadFromFile(path) ) return false; calculateBoardProperties(splitting); splitImageIntoTiles(Cell::side_length); scaleImageToWindow(window); shuffleTiles(); setSelectionVertex(selection_index); return true; } void Board::calculateBoardProperties(int splitting) { 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; } void Board::splitImageIntoTiles(int tile_length) { const int width = global_texture.getSize().x; const int height = global_texture.getSize().y; Cells::size_type index = 0; for (int x = 0; x < height; x += tile_length) { if ((height - x) >= tile_length) { for (int y = 0; y < width; y += tile_length) { if ((width - y) >= tile_length) { sf::Sprite* sp = new sf::Sprite(global_texture, sf::IntRect(y, x, tile_length, tile_length)); sp->setPosition(static_cast(y), static_cast(x)); vec_field.push_back(new Cell({index, index, sp})); ++index; } } } } } void Board::scaleImageToWindow(const sf::RenderWindow &window) { float scaling = calculateScalingToWindow(window); scaleTiles(scaling); } float Board::calculateScalingToWindow(const sf::RenderWindow &window) const { int texture_width = global_texture.getSize().x; int texture_height = global_texture.getSize().y; float scaling = 0.; if (texture_width >= texture_height && texture_width > static_cast(window.getSize().x)) scaling = static_cast(window.getSize().x) / static_cast(texture_width); if (texture_height >= texture_width && texture_height > static_cast(window.getSize().y)) scaling = static_cast(window.getSize().y) / static_cast(texture_height); return scaling; } void Board::scaleTiles(float scaling) { if (scaling == 0.) return; int old_side_length = Cell::side_length; Cell::side_length = static_cast(static_cast(Cell::side_length) * scaling); int shift = Cell::side_length - old_side_length; for (Cells::size_type i = 0; i < vec_field.size(); ++i) { vec_field[i]->sprite->scale(scaling, scaling); const auto shift_vector = calculateTileShiftVector(i, shift); vec_field[i]->sprite->move(shift_vector.first, shift_vector.second); } } std::pair Board::calculateTileShiftVector(Cells::size_type tile_index, int shift) const { float move_x = 0.f, move_y = 0.f; // The first column isn't allowed to move by x if (!(((tile_index % cells_on_width == 0) && (tile_index >= cells_on_width)))) move_x = static_cast(shift) * static_cast((tile_index < cells_on_width) ? tile_index : tile_index % cells_on_width); // The first row isn't allowed to move by y if (tile_index >= cells_on_width) move_y = static_cast(shift) * static_cast(tile_index / cells_on_width); return {move_x, move_y}; } void Board::shuffleTiles() { solved_tiles = vec_field.size(); // all tiles are solved for now srand(static_cast(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); } } 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::tryProcessDirection(const DIRECTION &direction) { if (on_selection) return swapOnSelection(direction); return moveSelection(direction); } bool Board::moveSelection(const DIRECTION &direction) { 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; } bool Board::swapOnSelection(const DIRECTION &direction) { 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(rect_selection[1].position.x - rect_selection[0].position.x), static_cast(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(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 = 1;