#include "puzzle.hpp" #include "gameplay.hpp" #include "image_converter/resources.hpp" #include #include #include #include #include #include #include #include #include #include #include GameParams* GameParams::instance = nullptr; void GameParams::CalculateStandardPuzzlePos() { coordinates tmp; int i, j, k = 0; for(i = 0; i < puzzles_per_side; ++i) for(j = 0; j < puzzles_per_side; ++j, ++k) { tmp.x = i * (puzzle_size + spacing) + spacing; tmp.y = j * (puzzle_size + spacing) + spacing + 30; standard_puzzle_coordinates[k] = tmp; } } void GameParams::ResetFreePuzzles() { for(int i = 0; i < puzzle_pieces; ++i) free_puzzles[i] = 1; } static void find_path_to_picture(std::string& path, const std::string& cur_directory, int number) { path = cur_directory + std::to_string(number / puzzles_per_side) + std::to_string(number % puzzles_per_side) + ".png"; } Fl_PNG_Image *GameParams::LoadPictureParts(std::unique_ptr& tmp_puzzle) { Fl_PNG_Image *img = nullptr; /* * if loading from Resources dir */ if(cur_directory.size()) { find_path_to_picture(tmp_puzzle->path, cur_directory, tmp_puzzle->sequence_number); img = new Fl_PNG_Image(tmp_puzzle->path.c_str()); /* * loading a standard image from RAM (image_converter/resources.cpp) */ } else { int offset = 0; for(int i = 0; i < tmp_puzzle->sequence_number; ++i) offset += image_sizes[i]; unsigned char *image_buffer = image_data + offset; img = new Fl_PNG_Image(nullptr, image_buffer, image_sizes[tmp_puzzle->sequence_number]); } return img; } void GameParams::NextUntestedPuzzles() { int idx_random_puzzle; std::unique_ptr tmp_puzzle; /* * check if puzzles already were created */ if(puzzles.size() != 0) { puzzles.clear(); Fl::do_widget_deletion(); } /* * ======== creating puzzles =========== */ win->begin(); for(int i = 0; i < puzzle_pieces; ++i) { idx_random_puzzle = 0 + (int)((double)puzzle_pieces * rand()/(RAND_MAX + 1.0)); while(!free_puzzles[idx_random_puzzle]) idx_random_puzzle = 0 + (int)((double)puzzle_pieces * rand()/(RAND_MAX + 1.0)); free_puzzles[idx_random_puzzle] = 0; /* empty puzzle */ if(idx_random_puzzle == puzzle_pieces-1) { SetXYEmptyBox(standard_puzzle_coordinates[i].x, standard_puzzle_coordinates[i].y); continue; } /* common puzzle */ tmp_puzzle = std::unique_ptr(new Puzzle(standard_puzzle_coordinates[i].x, standard_puzzle_coordinates[i].y)); tmp_puzzle->sequence_number = idx_random_puzzle; Fl_PNG_Image *img = LoadPictureParts(tmp_puzzle); switch (img->fail()) { case Fl_Image::ERR_NO_IMAGE: case Fl_Image::ERR_FILE_ACCESS: fl_alert("%s: %s", tmp_puzzle->path.c_str(), strerror(errno)); exit(1); case Fl_Image::ERR_FORMAT: fl_alert("couldn't decode image"); exit(1); } tmp_puzzle->image(img); tmp_puzzle->stored_img_pointer = img; tmp_puzzle->callback(press_button_callback, this); puzzles.push_back(std::move(tmp_puzzle)); } ResetFreePuzzles(); /* * Checking image shuffling */ bool shuffled_img = false; for(int i = 0; i < puzzle_pieces-1; ++i) if(puzzles[i]->sequence_number != i) { shuffled_img = true; break; } if(!shuffled_img) NextUntestedPuzzles(); win->end(); } bool GameParams::IsSolvability() { int counter = 0; for(size_t i = 0; i < puzzles.size(); ++i) for(size_t j = i+1; j < puzzles.size(); ++j) if(puzzles[i]->sequence_number > puzzles[j]->sequence_number) ++counter; return counter % 2 == 0; } void GameParams::CreateNewPuzzles() { do { NextUntestedPuzzles(); } while(!IsSolvability()); } void GameParams::SelectRandomPicture() { std::filesystem::path res_path = std::string("resources"); bool res_path_exists = std::filesystem::exists(res_path); if(res_path_exists) { std::vector choices; for (const auto& entry : std::filesystem::directory_iterator("resources")) { choices.emplace_back(entry.path().string()); } choices.emplace_back("standard"); std::random_device rd; std::mt19937 g(rd()); std::shuffle(choices.begin(), choices.end(), g); if(choices[0] == "standard") cur_directory.clear(); else { cur_directory = choices[0]; #if defined(_WIN32) cur_directory.append("\\"); #else cur_directory.append("/"); } } #endif }