diff --git a/Controller.cpp b/Controller.cpp index dd98d36..91e9336 100644 --- a/Controller.cpp +++ b/Controller.cpp @@ -10,7 +10,7 @@ void Controller::resize(const wxSize& tableSize) { resolution = tableSize; if (stopwatch >= 0) { - int gridPoint = min(resolution.x / (gridSize.x * TILE_WIDTH), + int gridPoint = mmin(resolution.x / (gridSize.x * TILE_WIDTH), resolution.y / (gridSize.y * TILE_HEIGHT)); if (gridPoint > 2) { @@ -32,7 +32,7 @@ void Controller::loadLayout(const wxString& path) { drawer.gridSize = layout.getDimensions(); - table = TLVec(drawer.gridSize.z, vector>(drawer.gridSize.x, vector(drawer.gridSize.y, -2))); + table = TLVec(drawer.gridSize.z, vector>(drawer.gridSize.x, vector(drawer.gridSize.y, EMPTY))); layout.readLayout(table); @@ -50,6 +50,13 @@ TLVec& Controller::getTable() { return table; } +void Controller::fill(bool solveable) { + if (solveable) + fillSolveableTable(); + else + fillRandom(); +} + void Controller::fillSolveableTable() { time_t start_time = time(NULL); @@ -65,7 +72,7 @@ void Controller::fillSolveableTable() { z = pos / (gridSize.x * gridSize.y); x = (pos / gridSize.y) % gridSize.x; y = pos % gridSize.y; - } while (table[z][x][y] != -1); + } while (table[z][x][y] != FREE); positions.push_back({z, x, y}); @@ -111,21 +118,40 @@ int Controller::emplace_rand(int id, std::list positions, int past_p return 0; } +void Controller::free_table() { + for (int z = 0; z < drawer.gridSize.z; z++) + for (int x = 0; x < drawer.gridSize.x; x++) + for (int y = 0; y < drawer.gridSize.y; y++) { + CardT id = table[z][x][y]; + + if (id >= 0) { + cardsCounter[id]++; + + table[z][x][y] = FREE; + } + } + + steps = decltype(steps)(); +} + void Controller::fillRandom() { srand(time(NULL)); - int not_end = remaining; + + wxLogDebug(wxString::Format("%i", remaining)); + + auto not_end = remaining; for (int z = 0; z < drawer.gridSize.z && not_end; z++) for (int x = 0; x < drawer.gridSize.x && not_end; x++) for (int y = 0; y < drawer.gridSize.y && not_end; y++) - if (table[z][x][y] == -1) { + if (table[z][x][y] == FREE) { table[z][x][y] = genRandId(); not_end--; } } -int Controller::genRandId() { - int id; +CardT Controller::genRandId() { + CardT id; int w = 0; @@ -246,19 +272,34 @@ bool Controller::sideFree(const ThreePoint& point) { return lfree || rfree; } -void Controller::select(CardT* card) { - wxLogDebug(wxString::Format("%i %p", *card, card)); +void Controller::handleClick(const wxPoint& point) { + wxPoint posPlain = drawer.toGrid(point); - if (selected != nullptr && sameValues(*card, *selected) && selected != card) { - *selected = -3; - *card = -3; - selected = nullptr; + ThreePoint pos = {-1, posPlain.x, posPlain.y}; - drawer.marked = {-1, -1, -1}; - } else - selected = card; + if (pos.x > -1) { + auto card = getCardByPosition(pos); + + if (pos.z >= 0 && available(pos)) { + if (selected != nullptr && sameValues(*card, *selected) && selected != card) { + steps.push({CardEntry{drawer.marked, *selected}, CardEntry{pos, *card}}); + + *selected = MATCHED; + *card = MATCHED; + + selected = nullptr; + + remaining -= 2; + + drawer.marked = {-1, -1, -1}; + } else { + selected = card; + drawer.marked = pos; + } - drawer.initScreen(table); + drawer.initScreen(table); + } + } } bool Controller::sameValues(CardT a, CardT b) { @@ -270,3 +311,15 @@ bool Controller::sameValues(CardT a, CardT b) { return false; } + +void Controller::undo() { + if (steps.size()) { + for (const CardEntry& entry : steps.top()) { + table[entry.pos.z][entry.pos.x][entry.pos.y] = entry.id; + cardsCounter[entry.id]++; + } + + remaining += 2; + steps.pop(); + } +} diff --git a/Controller.h b/Controller.h index 5049391..966b71a 100644 --- a/Controller.h +++ b/Controller.h @@ -3,6 +3,7 @@ #include #include +#include #include "wxw.h" @@ -19,22 +20,17 @@ public: void loadLayout(const wxString& path); - bool available(const ThreePoint& point); - bool upFree(const ThreePoint& point); - bool sideFree(const ThreePoint& point); - - void select(CardT* card); + void handleClick(const wxPoint& point); TLVec& getTable(); - void fillSolveableTable(); - void fillRandom(); + void free_table(); - CardT* getCardByPosition(ThreePoint& point); - - std::arraycardsCounter; + void fill(bool solveable); uint8_t remaining; + + void undo(); private: Drawer& drawer; XmlLayout layout; @@ -43,11 +39,24 @@ private: CardT* selected = nullptr; + void fillSolveableTable(); + void fillRandom(); + int emplace_rand(int id, std::list positions, int past_pos, std::list::iterator past_ptr); - int genRandId(); + CardT genRandId(); + + CardT* getCardByPosition(ThreePoint& point); + + bool available(const ThreePoint& point); + bool upFree(const ThreePoint& point); + bool sideFree(const ThreePoint& point); bool sameValues(CardT a, CardT b); + + std::arraycardsCounter; + + std::stack> steps; }; #endif diff --git a/GamePanel.cpp b/GamePanel.cpp index 7015b16..7656cf0 100644 --- a/GamePanel.cpp +++ b/GamePanel.cpp @@ -21,16 +21,16 @@ GamePanel::GamePanel(wxFrame* parent) : wxPanel(parent), controller(drawer) { void GamePanel::Start(const wxString& path, bool solveable) { controller.stopwatch = 0; controller.loadLayout(path); - if (solveable) - controller.fillSolveableTable(); - else - controller.fillRandom(); + controller.fill(solveable); timer->Start(1000, wxTIMER_CONTINUOUS); if (sb == nullptr) sb = ((wxFrame*)this->GetParent())->GetStatusBar(); - sb->SetStatusText(LTimeToStr(controller.stopwatch)); + sb->SetStatusText(LTimeToStr(controller.stopwatch), 0); + sb->SetStatusText(PRemaining(controller.remaining), 1); + + drawer.initScreen(controller.getTable()); } void GamePanel::OnPaint(wxPaintEvent& _) { @@ -41,22 +41,28 @@ void GamePanel::OnPaint(wxPaintEvent& _) { void GamePanel::OnTimer(wxTimerEvent& _) { controller.stopwatch += 1; - sb->SetStatusText(LTimeToStr(controller.stopwatch)); + sb->SetStatusText(LTimeToStr(controller.stopwatch), 0); } void GamePanel::OnClick(wxMouseEvent& _) { - wxPoint posPlain = drawer.toGrid(ScreenToClient(wxGetMousePosition())); - - ThreePoint pos = {-1, posPlain.x, posPlain.y}; - - if (pos.x > -1) { - auto card = controller.getCardByPosition(pos); - - drawer.marked = pos; - - if (pos.z >= 0 && controller.available(pos)) - controller.select(card); - } + controller.handleClick(ScreenToClient(wxGetMousePosition())); + sb->SetStatusText(PRemaining(controller.remaining), 1); + + Refresh(); +} + +void GamePanel::undo() { + controller.undo(); + + drawer.initScreen(controller.getTable()); + + Refresh(); +} + +void GamePanel::reshuffle(bool solveable) { + controller.free_table(); + controller.fill(solveable); + drawer.initScreen(controller.getTable()); Refresh(); } diff --git a/GamePanel.h b/GamePanel.h index 9056a45..fe7d89d 100644 --- a/GamePanel.h +++ b/GamePanel.h @@ -14,6 +14,9 @@ public: void Start(const wxString& path, bool solveable); + void undo(); + void reshuffle(bool solveable); + private: Drawer drawer; Controller controller; diff --git a/MainFrame.cpp b/MainFrame.cpp index a727450..decccb6 100644 --- a/MainFrame.cpp +++ b/MainFrame.cpp @@ -11,7 +11,7 @@ MainFrame::MainFrame() initMenu(); bindMenu(); - CreateStatusBar(); + CreateStatusBar(2); panel = new GamePanel(this); panel->SetFocus(); @@ -25,6 +25,9 @@ void MainFrame::initMenu() { menuGame->Append(IDM_Open, _("Открыть карту")); menuGame->AppendCheckItem(IDM_Solveable, _("Генерировать решаемую карту")); menuGame->AppendSeparator(); + menuGame->Append(IDM_Undo, _("Отменить ход")); + menuGame->Append(IDM_Reshuffle, _("Перемешать поле")); + menuGame->AppendSeparator(); menuGame->Append(IDM_Exit, _("Выход")); wxMenu *menuHelp = new wxMenu; @@ -72,6 +75,14 @@ void MainFrame::bindMenu() { Bind(wxEVT_MENU, [this](wxCommandEvent& _) -> void { solveable = _.IsChecked(); }, IDM_Solveable); + + Bind(wxEVT_MENU, [this](wxCommandEvent& _) -> void { + panel->undo(); + }, IDM_Undo); + + Bind(wxEVT_MENU, [this](wxCommandEvent& _) -> void { + panel->reshuffle(solveable); + }, IDM_Reshuffle); } void MainFrame::openLayout() { diff --git a/MainFrame.h b/MainFrame.h index 226ae91..4419365 100644 --- a/MainFrame.h +++ b/MainFrame.h @@ -36,7 +36,9 @@ enum IDM_About = wxID_ABOUT, IDM_Rules = wxID_HIGHEST + 1, IDM_New_Game, - IDM_Solveable + IDM_Solveable, + IDM_Undo, + IDM_Reshuffle }; #endif diff --git a/XmlLayout.cpp b/XmlLayout.cpp index c959f20..283bc99 100644 --- a/XmlLayout.cpp +++ b/XmlLayout.cpp @@ -32,7 +32,7 @@ void XmlLayout::readLayout(TLVec& table) { y = wxAtoi(tilePtr->GetAttribute("y")); l = wxAtoi(tilePtr->GetAttribute("layer")) - 1; - table[l][x][y] = -1; + table[l][x][y] = FREE; } tilePtr = tilePtr->GetNext(); diff --git a/utils.cpp b/utils.cpp index d950e43..b8a1e45 100644 --- a/utils.cpp +++ b/utils.cpp @@ -11,3 +11,7 @@ int upDiv(int a, int b) { wxString itowxS(int a) { return wxString::Format("%i", a); } + +wxString PRemaining(uint8_t remaining) { + return wxString::Format("%i%%", remaining*100 / 144); +} diff --git a/utils.h b/utils.h index 38e7958..eda1116 100644 --- a/utils.h +++ b/utils.h @@ -10,9 +10,10 @@ using std::vector; wxString LTimeToStr(int time); int upDiv(int a, int b); wxString itowxS(int a); +wxString PRemaining(uint8_t remaining); -#define min(a, b) (a + b - abs(a - b)) / 2 -#define max(a, b) (a + b + abs(a - b)) / 2 +#define mmin(a, b) (a + b - abs(a - b)) / 2 +#define mmax(a, b) (a + b + abs(a - b)) / 2 using CardT = int16_t; @@ -32,6 +33,18 @@ public: int z; }; +class CardEntry { +public: + ThreePoint pos; + CardT id; +}; + using TLVec = vector>>; +enum Values { + MATCHED = -3, + EMPTY, + FREE +}; + #endif