Added step undo and table reshuffle
This commit is contained in:
parent
ee2df44b63
commit
8f5f7472a8
@ -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<vector<CardT>>(drawer.gridSize.x, vector<CardT>(drawer.gridSize.y, -2)));
|
||||
table = TLVec(drawer.gridSize.z, vector<vector<CardT>>(drawer.gridSize.x, vector<CardT>(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<ThreePoint> 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);
|
||||
|
||||
drawer.initScreen(table);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
31
Controller.h
31
Controller.h
@ -3,6 +3,7 @@
|
||||
|
||||
#include <array>
|
||||
#include <list>
|
||||
#include <stack>
|
||||
|
||||
#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::array<uint8_t, TILE_IMAGES_N>cardsCounter;
|
||||
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<ThreePoint> positions, int past_pos, std::list<ThreePoint>::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::array<uint8_t, TILE_IMAGES_N>cardsCounter;
|
||||
|
||||
std::stack<std::array<CardEntry, 2>> steps;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -14,6 +14,9 @@ public:
|
||||
|
||||
void Start(const wxString& path, bool solveable);
|
||||
|
||||
void undo();
|
||||
void reshuffle(bool solveable);
|
||||
|
||||
private:
|
||||
Drawer drawer;
|
||||
Controller controller;
|
||||
|
@ -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() {
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
}
|
||||
|
17
utils.h
17
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<vector<vector<CardT>>>;
|
||||
|
||||
enum Values {
|
||||
MATCHED = -3,
|
||||
EMPTY,
|
||||
FREE
|
||||
};
|
||||
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user