From f80c95e75eb9814357d5a8a98b9aff258a94dcbd Mon Sep 17 00:00:00 2001 From: dm1sh Date: Mon, 30 May 2022 01:45:43 +0300 Subject: [PATCH] Finished generation of solveable map (rev 1) --- Controller.cpp | 166 ++++++++++++++++++++++++++++++++++++------------- Controller.h | 9 ++- MainFrame.cpp | 2 - utils.h | 12 +++- 4 files changed, 141 insertions(+), 48 deletions(-) diff --git a/Controller.cpp b/Controller.cpp index 9593175..d538d7d 100644 --- a/Controller.cpp +++ b/Controller.cpp @@ -35,65 +35,147 @@ void Controller::fill(bool solveable) { } void Controller::fillSolveableTable() { - time_t start_time = time(NULL); + srand(time(NULL)); - std::list positions; + auto not_end = remaining; - int overall = gridSize.z * gridSize.x * gridSize.y; - int pos = rand() % overall; - int z, x, y; + std::set positions; - do { - z = pos / (gridSize.x * gridSize.y); - x = (pos / gridSize.y) % gridSize.x; - y = pos % gridSize.y; - } while (table[z][x][y] != FREE); + positions.insert(getRandLowest()); - positions.push_back({z, x, y}); + auto next_ptr = positions.begin(); - int past_pos = 0; - auto past_ptr = positions.begin(); - - while (!positions.empty()) { + while (!positions.empty() || (not_end && !(positions.insert(getRandLowest()), positions.empty()))) { int id = genRandId(); if (id < 34) { - past_pos = emplace_rand(id, positions, past_pos, past_ptr); - past_pos = emplace_rand(id, positions, past_pos, past_ptr); + emplace_rand(id, positions, next_ptr, true); + emplace_rand(id, positions, next_ptr, false); cardsCounter[id]--; - } else - emplace_rand(id, positions, past_pos, past_ptr); + not_end -= 2; + } else { + emplace_rand(id, positions, next_ptr, true); + not_end--; + } } - - wxLogInfo( - wxString::Format("Filling took %i seconds", start_time - time(NULL))); } -int Controller::emplace_rand(int id, std::list positions, - int past_pos, - std::list::iterator past_ptr) { - int d = rand() % positions.size() - past_pos; +wxPoint Controller::getRandLowest() { + int overall = gridSize.x * gridSize.y; + int x, y; - if (d > 0) - for (int i = 0; i < d; i++) - past_ptr++; - else - for (int i = 0; i > d; i--) - past_ptr--; + do { + int pos = rand() % overall; + x = (pos / gridSize.y) % gridSize.x; + y = pos % gridSize.y; + } while (table[0][x][y] != FREE); - past_pos += d; + return {x, y}; +} - table[past_ptr->z][past_ptr->x][past_ptr->y] = id; +#include - // if () - // positions.push_back({}) +void print_list(const std::set& positions) { + wxFile f("tmp.txt", wxFile::write_append); + + for (const auto& el : positions) + f.Write(itowxS(el.z) + " " + itowxS(el.x) + " " + itowxS(el.y) + "\n"); + + f.Write("_ size: " + itowxS(positions.size()) + "\n"); +} - /** - * TODO: random move and positions adding - */ +void Controller::emplace_rand(int id, std::set& positions, + std::set::iterator& next_ptr, + bool canBeUp) { + print_list(positions); - return 0; + table[next_ptr->z][next_ptr->x][next_ptr->y] = id; + + push_available(positions, *next_ptr); + + auto prev_ptr = next_ptr; + auto prev = *next_ptr; + + do { + next_ptr++; + + if (next_ptr == positions.end()) + next_ptr = positions.begin(); + } while (!canBeUp && !wouldBeUpFree(prev, *next_ptr)); + + positions.erase(prev_ptr); +} + +bool Controller::wouldBeUpFree(const ThreePoint& prev, const ThreePoint& next) { + table[next.z][next.x][next.y] = 1; + + bool res = upFree(prev); + + table[next.z][next.x][next.y] = FREE; + + return res; +} + +void Controller::push_available(std::set& positions, + const ThreePoint& pos) { + int z = pos.z, x = pos.x, y = pos.y; + + if (x >= 2 && table[z][x-2][y] == FREE) // left + positions.emplace(z, x-2, y); + if (x + 2 < gridSize.x && table[z][x+2][y] == FREE) // right + positions.emplace(z, x+2, y); + + if (y >= 1 && (y < 2 || table[z][x][y-2] != FREE)) { // half bottom + if (x >= 2 && table[z][x-2][y-1] == FREE) // left + positions.emplace(z, x-2, y-1); + if (x + 2 < gridSize.x && table[z][x+2][y-1] == FREE) // right + positions.emplace(z, x+2, y-1); + } + + if (y + 1 < gridSize.y && (y + 2 >= gridSize.y || table[z][x][y+2] != FREE)) { // half bottom + if (x >= 2 && table[z][x-2][y+1] == FREE) // left + positions.emplace(z, x-2, y+1); + if (x + 2 < gridSize.x && table[z][x+2][y+1] == FREE) // right + positions.emplace(z, x+2, y+1); + } + + if (y >= 2 && table[z][x][y-2] == FREE) // up + positions.emplace(z, x, y-2); + if (y + 2 < gridSize.y && table[z][x][y+2] == FREE) // bottom + positions.emplace(z, x, y+2); + + if (z + 1 < gridSize.z) { // higher + if (table[z+1][x][y] == FREE) // straight + positions.emplace(z+1, x, y); + + if (y >= 1 && (y < 2 || table[z][x][y-2] != FREE) && table[z+1][x][y-1] == FREE) // half top + positions.emplace(z+1, x, y-1); + if (y + 1 < gridSize.y && (y + 2 >= gridSize.y || table[z][x][y+2] != FREE) && table[z+1][x][y+1] == FREE) // half bottom + positions.emplace(z+1, x, y+1); + + if (x >= 1 && (x < 2 || table[z][x-2][y] != FREE)) {// half left + if (table[z+1][x-1][y] == FREE) // straight + positions.emplace(z+1, x-1, y); + + if (y >= 1 && (x < 2 || table[z][x-2][y-1] != FREE) && table[z+1][x-1][y-1] == FREE) // half top + positions.emplace(z+1, x-1, y-1); + + if (y + 1 < gridSize.y && (x < 2 || table[z][x-2][y+1] != FREE) && table[z+1][x-1][y+1] == FREE) //half bottom + positions.emplace(z+1, x-1, y+1); + } + + if (x + 1 < gridSize.x && (x + 2 >= gridSize.x || table[z][x+2][y] != FREE)) { // half right + if (table[z+1][x+1][y] == FREE) // straight + positions.emplace(z+1, x+1, y); + + if (y >= 1 && (x + 2 >= gridSize.x || table[z][x+2][y-1] != FREE) && table[z+1][x+1][y-1] == FREE) // half top + positions.emplace(z+1, x+1, y-1); + + if (y + 1 < gridSize.y && (x + 2 >= gridSize.x || table[z][x+2][y+1] != FREE) && table[z+1][x+1][y+1] == FREE) //half bottom + positions.emplace(z+1, x+1, y+1); + } + } } void Controller::free_table() { @@ -115,7 +197,7 @@ void Controller::free_table() { void Controller::fillRandom() { srand(time(NULL)); - wxLogDebug(wxString::Format("%i", remaining)); + wxLogDebug(itowxS(remaining)); auto not_end = remaining; @@ -261,7 +343,7 @@ void Controller::handleClick(const wxPoint& point) { ThreePoint pos = {-1, posPlain.x, posPlain.y}; if (pos.x > -1) { - auto card = getCardByPosition(pos); + CardT* card = getCardByPosition(pos); if (pos.z >= 0 && available(pos)) { if (selected != nullptr && sameValues(*card, *selected) && diff --git a/Controller.h b/Controller.h index aba9834..9fa05aa 100644 --- a/Controller.h +++ b/Controller.h @@ -2,7 +2,7 @@ #define CONTROLLER_H #include -#include +#include #include #include "wxw.h" @@ -43,8 +43,11 @@ private: CardT* selected = nullptr; void fillSolveableTable(); - int emplace_rand(int id, std::list positions, int past_pos, - std::list::iterator past_ptr); + wxPoint getRandLowest(); + void emplace_rand(int id, std::set& positions, + std::set::iterator& next_ptr, bool canBeUp); + bool wouldBeUpFree(const ThreePoint& prev, const ThreePoint& next); + void push_available(std::set& positions, const ThreePoint& pos); void fillRandom(); diff --git a/MainFrame.cpp b/MainFrame.cpp index 46a1ebf..03aec2e 100644 --- a/MainFrame.cpp +++ b/MainFrame.cpp @@ -49,8 +49,6 @@ void MainFrame::initMenu() { menuGame->Append(IDM_New_Game, _("Начать сначала")); menuGame->Append(IDM_Open, _("Открыть карту")); menuGame->AppendCheckItem(IDM_Solveable, _("Генерировать решаемую карту")); - menuGame->Enable(IDM_Solveable, - false); // TODO: finish solveable table generation menuGame->AppendSeparator(); menuGame->Append(IDM_Undo, _("Отменить ход")); menuGame->Append(IDM_Reshuffle, _("Перемешать поле")); diff --git a/utils.h b/utils.h index f8c8444..650602a 100644 --- a/utils.h +++ b/utils.h @@ -26,8 +26,18 @@ public: class ThreePoint { public: - ThreePoint(int _z, int _x, int _y) : x(_x), y(_y), z(_z){}; + constexpr ThreePoint(int _z, int _x, int _y) : x(_x), y(_y), z(_z){}; + ThreePoint(const wxPoint& a) : x(a.x), y(a.y), z(0){}; ThreePoint() : x(0), y(0), z(0){}; + + bool operator<(const ThreePoint& b) const { + return z*144*144+x*144+y < b.z*144*144+b.x*144+b.y; + } + + bool operator==(const ThreePoint& b) { + return z == b.z && x == b.x && y == b.y; + } + int x; int y; int z;