Compare commits

...

2 Commits

10 changed files with 426 additions and 276 deletions

View File

@ -2,37 +2,14 @@
Controller::Controller(Drawer& drawer) : drawer(drawer){}; Controller::Controller(Drawer& drawer) : drawer(drawer){};
void Controller::resize(const wxSize& tableSize) {
wxSize& resolution = drawer.resolution;
Dimensions& gridSize = drawer.gridSize;
wxRect& tablePixelRect = drawer.tablePixelRect;
resolution = tableSize;
if (stopwatch >= 0) {
int gridPoint = mmin(resolution.x / (gridSize.x * TILE_WIDTH),
resolution.y / (gridSize.y * TILE_HEIGHT));
if (gridPoint > 2) {
tablePixelRect.SetSize({gridPoint * TILE_WIDTH * gridSize.x, gridPoint * TILE_HEIGHT * gridSize.y});
drawer.tilePixelSize.Set(gridPoint * TILE_WIDTH, gridPoint * TILE_HEIGHT);
}
tablePixelRect.SetPosition({(resolution.x - tablePixelRect.width) / 2,
(resolution.y - tablePixelRect.height) / 2});
}
drawer.setBG(tableSize);
drawer.initScreen(table);
}
void Controller::loadLayout(const wxString& path) { void Controller::loadLayout(const wxString& path) {
layout.openFile(path); layout.openFile(path);
drawer.gridSize = layout.getDimensions(); gridSize = layout.getDimensions();
table = TLVec(drawer.gridSize.z, vector<vector<CardT>>(drawer.gridSize.x, vector<CardT>(drawer.gridSize.y, EMPTY))); table = TLVec(
gridSize.z,
vector<vector<CardT>>(gridSize.x, vector<CardT>(gridSize.y, EMPTY)));
layout.readLayout(table); layout.readLayout(table);
@ -60,8 +37,6 @@ void Controller::fill(bool solveable) {
void Controller::fillSolveableTable() { void Controller::fillSolveableTable() {
time_t start_time = time(NULL); time_t start_time = time(NULL);
auto& gridSize = drawer.gridSize;
std::list<ThreePoint> positions; std::list<ThreePoint> positions;
int overall = gridSize.z * gridSize.x * gridSize.y; int overall = gridSize.z * gridSize.x * gridSize.y;
@ -91,10 +66,13 @@ void Controller::fillSolveableTable() {
emplace_rand(id, positions, past_pos, past_ptr); emplace_rand(id, positions, past_pos, past_ptr);
} }
wxLogInfo(wxString::Format("Filling took %i seconds", start_time - time(NULL))); wxLogInfo(
wxString::Format("Filling took %i seconds", start_time - time(NULL)));
} }
int Controller::emplace_rand(int id, std::list<ThreePoint> positions, int past_pos, std::list<ThreePoint>::iterator past_ptr) { int Controller::emplace_rand(int id, std::list<ThreePoint> positions,
int past_pos,
std::list<ThreePoint>::iterator past_ptr) {
int d = rand() % positions.size() - past_pos; int d = rand() % positions.size() - past_pos;
if (d > 0) if (d > 0)
@ -119,9 +97,9 @@ int Controller::emplace_rand(int id, std::list<ThreePoint> positions, int past_p
} }
void Controller::free_table() { void Controller::free_table() {
for (int z = 0; z < drawer.gridSize.z; z++) for (int z = 0; z < gridSize.z; z++)
for (int x = 0; x < drawer.gridSize.x; x++) for (int x = 0; x < gridSize.x; x++)
for (int y = 0; y < drawer.gridSize.y; y++) { for (int y = 0; y < gridSize.y; y++) {
CardT id = table[z][x][y]; CardT id = table[z][x][y];
if (id >= 0) { if (id >= 0) {
@ -141,9 +119,9 @@ void Controller::fillRandom() {
auto not_end = remaining; auto not_end = remaining;
for (int z = 0; z < drawer.gridSize.z && not_end; z++) for (int z = 0; z < gridSize.z && not_end; z++)
for (int x = 0; x < drawer.gridSize.x && not_end; x++) for (int x = 0; x < gridSize.x && not_end; x++)
for (int y = 0; y < drawer.gridSize.y && not_end; y++) for (int y = 0; y < gridSize.y && not_end; y++)
if (table[z][x][y] == FREE) { if (table[z][x][y] == FREE) {
table[z][x][y] = genRandId(); table[z][x][y] = genRandId();
not_end--; not_end--;
@ -229,45 +207,50 @@ CardT* Controller::getCardByPosition(ThreePoint& point) {
return res; return res;
} }
bool Controller::available(const ThreePoint& point) { bool Controller::available(const ThreePoint& point) const {
return upFree(point) && sideFree(point); return upFree(point) && sideFree(point);
} }
bool Controller::upFree(const ThreePoint& point) { bool Controller::upFree(const ThreePoint& point) const {
if (point.z == table.size() - 1) if (point.z == table.size() - 1)
return true; return true;
return !( return !((table[point.z + 1][point.x][point.y] >= 0) ||
(table[point.z + 1][point.x][point.y] >= 0) ||
(point.x > 0 && table[point.z + 1][point.x - 1][point.y] >= 0) || (point.x > 0 && table[point.z + 1][point.x - 1][point.y] >= 0) ||
(point.y > 0 && table[point.z + 1][point.x][point.y - 1] >= 0) || (point.y > 0 && table[point.z + 1][point.x][point.y - 1] >= 0) ||
(point.x > 0 && point.y > 0 && table[point.z + 1][point.x - 1][point.y - 1] >= 0) || (point.x > 0 && point.y > 0 &&
(point.x < table[point.z].size() - 1 && table[point.z + 1][point.x + 1][point.y] >= 0) || table[point.z + 1][point.x - 1][point.y - 1] >= 0) ||
(point.y < table[point.z][point.x].size() - 1 && table[point.z + 1][point.x][point.y + 1] >= 0) || (point.x < table[point.z].size() - 1 &&
(point.x < table[point.z].size() - 1 && point.y < table[point.z][point.x].size() - 1 && table[point.z + 1][point.x + 1][point.y + 1] >= 0) || table[point.z + 1][point.x + 1][point.y] >= 0) ||
(point.x > 0 && point.y < table[point.z][point.x].size() - 1 && table[point.z + 1][point.x - 1][point.y + 1] >= 0) || (point.y < table[point.z][point.x].size() - 1 &&
(point.x < table[point.z].size() - 1 && point.y > 0 && table[point.z + 1][point.x + 1][point.y - 1] >= 0) table[point.z + 1][point.x][point.y + 1] >= 0) ||
); (point.x < table[point.z].size() - 1 &&
point.y < table[point.z][point.x].size() - 1 &&
table[point.z + 1][point.x + 1][point.y + 1] >= 0) ||
(point.x > 0 && point.y < table[point.z][point.x].size() - 1 &&
table[point.z + 1][point.x - 1][point.y + 1] >= 0) ||
(point.x < table[point.z].size() - 1 && point.y > 0 &&
table[point.z + 1][point.x + 1][point.y - 1] >= 0));
} }
bool Controller::sideFree(const ThreePoint& point) { bool Controller::sideFree(const ThreePoint& point) const {
bool lfree = true; bool lfree = true;
bool rfree = true; bool rfree = true;
if (point.x > 1) if (point.x > 1)
lfree = !( lfree =
(point.y > 0 && table[point.z][point.x-2][point.y-1] >= 0) || !((point.y > 0 && table[point.z][point.x - 2][point.y - 1] >= 0) ||
(table[point.z][point.x - 2][point.y] >= 0) || (table[point.z][point.x - 2][point.y] >= 0) ||
(point.y < table[point.z][point.x].size() - 1 && table[point.z][point.x-2][point.y+1] >= 0) (point.y < table[point.z][point.x].size() - 1 &&
); table[point.z][point.x - 2][point.y + 1] >= 0));
if (point.x < table[point.z].size() - 2) if (point.x < table[point.z].size() - 2)
rfree = !( rfree =
(point.y > 0 && table[point.z][point.x+2][point.y-1] >= 0) || !((point.y > 0 && table[point.z][point.x + 2][point.y - 1] >= 0) ||
(table[point.z][point.x + 2][point.y] >= 0) || (table[point.z][point.x + 2][point.y] >= 0) ||
(point.y < table[point.z][point.x].size() - 1 && table[point.z][point.x+2][point.y+1] >= 0) (point.y < table[point.z][point.x].size() - 1 &&
); table[point.z][point.x + 2][point.y + 1] >= 0));
return lfree || rfree; return lfree || rfree;
} }
@ -281,8 +264,10 @@ void Controller::handleClick(const wxPoint& point) {
auto card = getCardByPosition(pos); auto card = getCardByPosition(pos);
if (pos.z >= 0 && available(pos)) { if (pos.z >= 0 && available(pos)) {
if (selected != nullptr && sameValues(*card, *selected) && selected != card) { if (selected != nullptr && sameValues(*card, *selected) &&
steps.push({CardEntry{drawer.marked, *selected}, CardEntry{pos, *card}}); selected != card) {
steps.push({CardEntry{drawer.marked, *selected},
CardEntry{pos, *card}});
*selected = MATCHED; *selected = MATCHED;
*card = MATCHED; *card = MATCHED;
@ -296,14 +281,13 @@ void Controller::handleClick(const wxPoint& point) {
selected = card; selected = card;
drawer.marked = pos; drawer.marked = pos;
} }
drawer.initScreen(table);
} }
} }
} }
bool Controller::sameValues(CardT a, CardT b) { bool Controller::sameValues(CardT a, CardT b) const {
if (a == b) return true; if (a == b)
return true;
else if (a >= 38 && b >= 38) else if (a >= 38 && b >= 38)
return true; return true;
else if (a >= 34 && a <= 37 && b >= 34 && b <= 37) else if (a >= 34 && a <= 37 && b >= 34 && b <= 37)
@ -323,3 +307,7 @@ void Controller::undo() {
steps.pop(); steps.pop();
} }
} }
bool Controller::gameStarted() const {
return stopwatch > 0;
}

View File

@ -16,8 +16,6 @@ public:
int stopwatch = -1; int stopwatch = -1;
void resize(const wxSize& tableSize);
void loadLayout(const wxString& path); void loadLayout(const wxString& path);
void handleClick(const wxPoint& point); void handleClick(const wxPoint& point);
@ -31,6 +29,11 @@ public:
uint8_t remaining; uint8_t remaining;
void undo(); void undo();
bool gameStarted() const;
Dimensions gridSize;
private: private:
Drawer& drawer; Drawer& drawer;
XmlLayout layout; XmlLayout layout;
@ -40,19 +43,20 @@ private:
CardT* selected = nullptr; CardT* selected = nullptr;
void fillSolveableTable(); void fillSolveableTable();
void fillRandom(); int emplace_rand(int id, std::list<ThreePoint> positions, int past_pos,
std::list<ThreePoint>::iterator past_ptr);
int emplace_rand(int id, std::list<ThreePoint> positions, int past_pos, std::list<ThreePoint>::iterator past_ptr); void fillRandom();
CardT genRandId(); CardT genRandId();
CardT* getCardByPosition(ThreePoint& point); CardT* getCardByPosition(ThreePoint& point);
bool available(const ThreePoint& point); bool available(const ThreePoint& point) const;
bool upFree(const ThreePoint& point); bool upFree(const ThreePoint& point) const;
bool sideFree(const ThreePoint& point); bool sideFree(const ThreePoint& point) const;
bool sameValues(CardT a, CardT b); bool sameValues(CardT a, CardT b) const;
std::array<uint8_t, TILE_IMAGES_N> cardsCounter; std::array<uint8_t, TILE_IMAGES_N> cardsCounter;

View File

@ -1,66 +1,60 @@
#include "Drawer.h" #include "Drawer.h"
static const char* tileImageNames[] = { "Pin1", "Pin2", "Pin3", "Pin4", "Pin5", "Pin6", "Pin7", "Pin8", "Pin9", "Sou1", "Sou2", "Sou3", "Sou4", "Sou5", "Sou6", "Sou7", "Sou8", "Sou9", "Man1", "Man2", "Man3", "Man4", "Man5", "Man6", "Man7", "Man8", "Man9", "Chun", "Haku", "Hatsu", "Nan", "Pei", "Shaa", "Ton", "Flower1", "Flower2", "Flower3", "Flower4", "Season1", "Season2", "Season3", "Season4" }; static const char* tileImageNames[] = {
// clang-format off
"Pin1", "Pin2", "Pin3", "Pin4", "Pin5", "Pin6", "Pin7", "Pin8", "Pin9",
"Sou1", "Sou2", "Sou3", "Sou4", "Sou5", "Sou6", "Sou7", "Sou8", "Sou9",
"Man1", "Man2", "Man3", "Man4", "Man5", "Man6", "Man7", "Man8", "Man9",
"Chun", "Haku", "Hatsu",
"Nan", "Pei", "Shaa", "Ton",
"Flower1", "Flower2", "Flower3", "Flower4",
"Season1", "Season2", "Season3", "Season4"
// clang-format on
};
static const wxColor lGreen{0x07, 0x55, 0x2b};
static const wxColor dGreen{0x01, 0x2d, 0x16};
Drawer::Drawer() : marked{-1, -1, -1} { Drawer::Drawer() : marked{-1, -1, -1} {
for (int i = 0; i < TILE_IMAGES_N; i++) { for (int i = 0; i < TILE_IMAGES_N; i++) {
if (!tileImages[i].LoadFile(_("./resources/tiles/") + _(tileImageNames[i]) + _(".png"), wxBITMAP_TYPE_PNG)) bool succeed = tileImages[i].LoadFile(
wxLogDebug(_("./resources/tiles/") + _(tileImageNames[i]) + _(".png ") + wxString::Format(wxT("%i"), i)); _("./resources/tiles/") + _(tileImageNames[i]) + _(".png"),
wxBITMAP_TYPE_PNG);
if (!succeed)
wxLogDebug(_("failed to load tile ./resources/tiles/") +
_(tileImageNames[i]) + _(".png with index") +
wxString::Format("%i", i));
} }
} }
void Drawer::drawTable(wxDC& dc) { void Drawer::drawTable(wxDC& dc) {
if (isScreenReady) dc.DrawBitmap(bgBitmap, 0, 0, false);
dc.DrawBitmap(screenBitmap, 0, 0, false); if (boardBitmap.IsOk()) {
wxLogDebug("Drawing board");
dc.DrawBitmap(boardBitmap, tablePixelRect.GetPosition(), true);
}
} }
wxBitmap copyBitmap(const wxBitmap& old) { void Drawer::composeBG() {
return old.GetSubBitmap(wxRect(0, 0, old.GetWidth(), old.GetHeight())); bgBitmap = wxBitmap(resolution);
}
void Drawer::setBG(const wxSize& tableSize) { wxLogDebug(
bgBitmap = wxBitmap(tableSize); wxString::Format("Rebuild bg %i %i", resolution.x, resolution.y));
wxMemoryDC dc; wxMemoryDC dc;
dc.SelectObject(bgBitmap); dc.SelectObject(bgBitmap);
dc.GradientFillConcentric(wxRect(wxPoint(0, 0), tableSize), wxColor(7, 85, 45), wxColor(1, 45, 22)); dc.GradientFillConcentric(wxRect(wxPoint(0, 0), resolution), lGreen,
dGreen);
isBgReady = true;
} }
wxPoint Drawer::toGrid(const wxPoint& point) { void Drawer::composeBoard(const TLVec& layout, const Dimensions& gridSize) {
wxPoint out(-1, -1); boardBitmap = wxBitmap(tablePixelRect.GetSize());
if (point.x >= tablePixelRect.x && wxLogDebug(_("Rebuild board"));
point.x <= tablePixelRect.x + tablePixelRect.width &&
point.y >= tablePixelRect.y &&
point.y <= tablePixelRect.y + tablePixelRect.height)
{
out.x = (point.x - tablePixelRect.x) / tilePixelSize.x;
out.y = (point.y - tablePixelRect.y) / tilePixelSize.y;
}
return out;
}
wxPoint Drawer::fromGrid(int x, int y) {
return { tablePixelRect.x + x * tilePixelSize.x,
tablePixelRect.y + y * tilePixelSize.y };
}
wxPoint Drawer::fromGrid(const wxPoint& point) {
return fromGrid(point.x, point.y);
}
void Drawer::initScreen(const TLVec& layout) {
if (isBgReady) {
screenBitmap = copyBitmap(bgBitmap);
wxLogDebug(_("Reinit"));
wxMemoryDC dc; wxMemoryDC dc;
dc.SelectObject(screenBitmap); dc.SelectObject(boardBitmap);
for (int z = 0; z < gridSize.z; z++) for (int z = 0; z < gridSize.z; z++)
for (int x = 0; x < gridSize.x; x++) for (int x = 0; x < gridSize.x; x++)
@ -70,35 +64,125 @@ void Drawer::initScreen(const TLVec& layout) {
drawTile(dc, c, fromGrid(x, y), z); drawTile(dc, c, fromGrid(x, y), z);
} }
isScreenReady = true; wxMask* mask = new wxMask(boardBitmap, wxColor(0x00, 0x00, 0x00));
} boardBitmap.SetMask(mask);
} }
void Drawer::drawTile(wxDC& dc, int8_t index, const wxPoint& position, uint8_t zIndex) { void Drawer::drawTile(wxDC& dc, int8_t index, const wxPoint& position,
uint8_t zIndex) const {
wxBrush _bgColor = dc.GetBrush(); wxBrush _bgColor = dc.GetBrush();
wxBrush front = wxColor(255, 255, 255); wxBrush front = wxColor(0xff, 0xff, 0xff);
wxBrush back = wxColor(200, 200, 200); wxBrush back = wxColor(0xc8, 0xc8, 0xc8);
if (position == fromGrid({marked.x, marked.y}) && marked.z == zIndex) { if (position == fromGrid({marked.x, marked.y}) && marked.z == zIndex) {
front = wxColor(200, 255, 200); front = wxColor(0xc8, 0xff, 0xc8);
back = wxColor(190, 220, 190); back = wxColor(0xbe, 0xdc, 0xbe);
} }
dc.SetBrush(back); dc.SetBrush(back);
dc.DrawRoundedRectangle(position.x + (tilePixelSize.GetWidth()/10 + 3) - (tilePixelSize.GetWidth()/10 + 3)*zIndex, position.y + (tilePixelSize.GetHeight()/10 + 3) - (tilePixelSize.GetHeight()/10 + 3)*zIndex, tilePixelSize.GetWidth() * 2, tilePixelSize.GetHeight() * 2, 10); dc.DrawRoundedRectangle(position.x + (tilePixelSize.GetWidth() / 10 + 3) -
(tilePixelSize.GetWidth() / 10 + 3) * zIndex,
position.y + (tilePixelSize.GetHeight() / 10 + 3) -
(tilePixelSize.GetHeight() / 10 + 3) * zIndex,
tilePixelSize.GetWidth() * 2,
tilePixelSize.GetHeight() * 2, 10);
dc.SetBrush(front); dc.SetBrush(front);
dc.DrawRoundedRectangle(position.x - (tilePixelSize.GetWidth()/10 + 3)*zIndex, position.y - (tilePixelSize.GetHeight()/10 + 3)*zIndex, tilePixelSize.GetWidth() * 2, tilePixelSize.GetHeight() * 2, 10); dc.DrawRoundedRectangle(
position.x - (tilePixelSize.GetWidth() / 10 + 3) * zIndex,
position.y - (tilePixelSize.GetHeight() / 10 + 3) * zIndex,
tilePixelSize.GetWidth() * 2, tilePixelSize.GetHeight() * 2, 10);
dc.SetBrush(_bgColor); dc.SetBrush(_bgColor);
if (tileImages[index].IsOk()) { if (tileImages[index].IsOk()) {
wxPoint pos;
pos.x = position.x + 10 - (tilePixelSize.GetWidth() / 10 + 3) * zIndex;
pos.y = position.y + 10 - (tilePixelSize.GetHeight() / 10 + 3) * zIndex;
if (tileImages[index].GetWidth() != tilePixelSize.x * 2) if (tileImages[index].GetWidth() != tilePixelSize.x * 2)
dc.DrawBitmap(tileImages[index].Scale(tilePixelSize.x * 2 - 20, tilePixelSize.y * 2 - 20), {position.x + 10 - (tilePixelSize.GetWidth()/10 + 3)*zIndex, position.y + 10 - (tilePixelSize.GetHeight()/10 + 3)*zIndex}); dc.DrawBitmap(tileImages[index].Scale(tilePixelSize.x * 2 - 20,
tilePixelSize.y * 2 - 20),
pos);
else else
dc.DrawBitmap(tileImages[index], {position.x + 10 - (tilePixelSize.GetWidth()/10 + 3)*zIndex, position.y + 10 - (tilePixelSize.GetHeight()/10 + 3)*zIndex}); dc.DrawBitmap(tileImages[index], pos);
} }
} }
void Drawer::resizeBg(const wxSize& resolution) {
if (this->resolution != resolution) {
this->resolution = resolution;
composeBG();
}
}
/**
* Resizes tile and whole board bitmap size to the resolution, set in this
* instance
*/
bool Drawer::resizeBoard(const TLVec& layout, const Dimensions& gridSize) {
bool res = false;
const int gridPoint = mmin(resolution.x / (gridSize.x * TILE_WIDTH),
resolution.y / (gridSize.y * TILE_HEIGHT));
wxLogDebug(wxString::Format("Resize board: %i", gridPoint));
if (gridPoint >= MIN_GRID_POINT) {
if (gridPoint != prevGridPoint) {
tablePixelRect.SetSize({gridPoint * TILE_WIDTH * gridSize.x,
gridPoint * TILE_HEIGHT * gridSize.y});
tilePixelSize.Set(gridPoint * TILE_WIDTH, gridPoint * TILE_HEIGHT);
}
tablePixelRect.SetPosition(
{(resolution.x - tablePixelRect.width) / 2,
(resolution.y - tablePixelRect.height) / 2});
if (gridPoint != prevGridPoint) {
composeBoard(layout, gridSize);
res = true;
}
prevGridPoint = gridPoint;
}
return res;
}
wxPoint Drawer::toGrid(const wxPoint& point) const {
wxPoint out(-1, -1);
if (point.x >= tablePixelRect.x &&
point.x <= tablePixelRect.x + tablePixelRect.width &&
point.y >= tablePixelRect.y &&
point.y <= tablePixelRect.y + tablePixelRect.height) {
out.x = (point.x - tablePixelRect.x) / tilePixelSize.x;
out.y = (point.y - tablePixelRect.y) / tilePixelSize.y;
}
return out;
}
wxPoint Drawer::fromGrid(int x, int y) const {
return {x * tilePixelSize.x, y * tilePixelSize.y};
}
wxPoint Drawer::fromGrid(const wxPoint& point) const {
return fromGrid(point.x, point.y);
}
wxSize Drawer::composeMinSize(const wxSize& gridSize) {
wxSize ms;
ms.SetWidth(MIN_GRID_POINT * TILE_WIDTH * gridSize.x);
ms.SetHeight(MIN_GRID_POINT * TILE_HEIGHT * gridSize.y);
wxLogDebug(wxString::Format("MinSize %i %i", ms.x, ms.y));
return ms;
}

View File

@ -10,39 +10,44 @@
#define TILE_IMAGES_N 42 #define TILE_IMAGES_N 42
#define MIN_GRID_POINT 3
class Drawer { class Drawer {
public: public:
Drawer(); Drawer();
void drawTable(wxDC& dc); void drawTable(wxDC& dc);
void composeBG();
void composeBoard(const TLVec& layout, const Dimensions& gridSize);
void resizeBg(const wxSize& tableSize);
bool resizeBoard(const TLVec& layout, const Dimensions& gridSize);
wxPoint toGrid(const wxPoint& point) const;
wxPoint fromGrid(int x, int y) const;
wxPoint fromGrid(const wxPoint& point) const;
wxSize composeMinSize(const wxSize& gridSize);
wxSize tableSize; wxSize tableSize;
wxSize tilePixelSize; // кратно 600x800 wxSize tilePixelSize; // кратно 3x4, по умолчанию 600x800
wxSize resolution; wxSize resolution;
Dimensions gridSize;
wxRect tablePixelRect; wxRect tablePixelRect;
void setBG(const wxSize& tableSize);
void initScreen(const TLVec& layout);
wxPoint toGrid(const wxPoint& point);
wxPoint fromGrid(int x, int y);
wxPoint fromGrid(const wxPoint& point);
ThreePoint marked; ThreePoint marked;
private: private:
void drawScreen(wxDC& dc); void drawTile(wxDC& dc, int8_t index, const wxPoint& position,
void drawTile(wxDC& dc, int8_t index, const wxPoint& position, uint8_t zIndex); uint8_t zIndex) const;
wxImage tileImages[TILE_IMAGES_N]; wxImage tileImages[TILE_IMAGES_N];
wxBitmap bgBitmap; wxBitmap bgBitmap;
wxBitmap screenBitmap; wxBitmap boardBitmap;
bool isBgReady = false; int prevGridPoint;
bool isScreenReady = false;
}; };
#endif #endif

View File

@ -4,65 +4,96 @@
#include "utils.h" #include "utils.h"
GamePanel::GamePanel(wxFrame* parent) : wxPanel(parent), controller(drawer) { // clang-format off
wxBEGIN_EVENT_TABLE(GamePanel, wxPanel)
EVT_PAINT(GamePanel::OnPaint)
EVT_SIZE(GamePanel::OnResize)
EVT_TIMER(TIMER_ID, GamePanel::OnTimer)
EVT_LEFT_DOWN(GamePanel::OnClick)
wxEND_EVENT_TABLE();
// clang-format on
GamePanel::GamePanel(wxFrame* parent)
: wxPanel(parent), controller(drawer),
sb(((wxFrame*)this->GetParent())->GetStatusBar()), timer(this, TIMER_ID) {
SetBackgroundStyle(wxBG_STYLE_PAINT); SetBackgroundStyle(wxBG_STYLE_PAINT);
Bind(wxEVT_PAINT, &GamePanel::OnPaint, this);
Bind(wxEVT_SIZE, [this](wxSizeEvent& evt) -> void {
this->controller.resize(evt.GetSize());
});
timer = new wxTimer(this, 1);
Bind(wxEVT_TIMER, &GamePanel::OnTimer, this, timer->GetId());
Bind(wxEVT_LEFT_DOWN, &GamePanel::OnClick, this);
} }
void GamePanel::Start(const wxString& path, bool solveable) { void GamePanel::Start(const wxString& path, bool solveable,
std::function<void(const wxSize& size)> setMinSize) {
wxLogDebug(_("Started game"));
controller.stopwatch = 0; controller.stopwatch = 0;
controller.loadLayout(path); controller.loadLayout(path);
controller.fill(solveable); controller.fill(solveable);
timer->Start(1000, wxTIMER_CONTINUOUS); setMinSize(drawer.composeMinSize(controller.gridSize));
timer.Start(1000, wxTIMER_CONTINUOUS);
if (sb == nullptr)
sb = ((wxFrame*)this->GetParent())->GetStatusBar();
sb->SetStatusText(LTimeToStr(controller.stopwatch), 0); sb->SetStatusText(LTimeToStr(controller.stopwatch), 0);
sb->SetStatusText(PRemaining(controller.remaining), 1); sb->SetStatusText(PRemaining(controller.remaining), 1);
drawer.initScreen(controller.getTable()); bool redrawn =
drawer.resizeBoard(controller.getTable(), controller.gridSize);
if (!redrawn)
drawer.composeBoard(controller.getTable(), controller.gridSize);
Refresh();
}
void GamePanel::undo() {
controller.undo();
drawer.composeBoard(controller.getTable(), controller.gridSize);
Refresh();
}
void GamePanel::reshuffle(bool solveable) {
controller.free_table();
controller.fill(solveable);
drawer.composeBoard(controller.getTable(), controller.gridSize);
Refresh();
} }
void GamePanel::OnPaint(wxPaintEvent& _) { void GamePanel::OnPaint(wxPaintEvent& _) {
wxAutoBufferedPaintDC dc(this); wxAutoBufferedPaintDC dc(this);
wxLogDebug(_("OnPaint"));
drawer.drawTable(dc); drawer.drawTable(dc);
} }
void GamePanel::OnResize(wxSizeEvent& _) {
const wxSize& resolution = GetClientSize();
wxLogDebug(wxString::Format("OnResize %i %i", resolution.x, resolution.y));
if (isPositive(resolution)) {
drawer.resizeBg(resolution);
if (controller.gameStarted())
drawer.resizeBoard(controller.getTable(), controller.gridSize);
}
Refresh();
}
void GamePanel::OnTimer(wxTimerEvent& _) { void GamePanel::OnTimer(wxTimerEvent& _) {
controller.stopwatch += 1; controller.stopwatch += 1;
sb->SetStatusText(LTimeToStr(controller.stopwatch), 0); sb->SetStatusText(LTimeToStr(controller.stopwatch), 0);
} }
void GamePanel::OnClick(wxMouseEvent& _) { void GamePanel::OnClick(wxMouseEvent& _) {
if (controller.gameStarted()) {
controller.handleClick(ScreenToClient(wxGetMousePosition())); controller.handleClick(ScreenToClient(wxGetMousePosition()));
sb->SetStatusText(PRemaining(controller.remaining), 1); sb->SetStatusText(PRemaining(controller.remaining), 1);
Refresh(); drawer.composeBoard(controller.getTable(), controller.gridSize);
}
void GamePanel::undo() {
controller.undo();
drawer.initScreen(controller.getTable());
Refresh(); Refresh();
} }
void GamePanel::reshuffle(bool solveable) {
controller.free_table();
controller.fill(solveable);
drawer.initScreen(controller.getTable());
Refresh();
} }

View File

@ -5,14 +5,15 @@
#include <wx/stopwatch.h> #include <wx/stopwatch.h>
#include "Drawer.h"
#include "Controller.h" #include "Controller.h"
#include "Drawer.h"
class GamePanel : public wxPanel { class GamePanel : public wxPanel {
public: public:
GamePanel(wxFrame* parent); GamePanel(wxFrame* parent);
void Start(const wxString& path, bool solveable); void Start(const wxString& path, bool solveable,
std::function<void(const wxSize& size)> setMinSize);
void undo(); void undo();
void reshuffle(bool solveable); void reshuffle(bool solveable);
@ -22,11 +23,16 @@ private:
Controller controller; Controller controller;
void OnPaint(wxPaintEvent& _); void OnPaint(wxPaintEvent& _);
void OnResize(wxSizeEvent& _);
void OnTimer(wxTimerEvent& _); void OnTimer(wxTimerEvent& _);
void OnClick(wxMouseEvent& _); void OnClick(wxMouseEvent& _);
wxDECLARE_EVENT_TABLE();
wxStatusBar* sb = nullptr; wxStatusBar* sb = nullptr;
wxTimer* timer = nullptr; wxTimer timer;
}; };
#define TIMER_ID 1
#endif #endif

View File

@ -1,26 +1,32 @@
#include "MainFrame.h" #include "MainFrame.h"
#include "AboutDlg.h"
#include "HelpDlg.h" #include "HelpDlg.h"
#include "RulesDlg.h" #include "RulesDlg.h"
#include "AboutDlg.h"
#include "resources/icon.xpm" #include "resources/icon.xpm"
MainFrame::MainFrame() MainFrame::MainFrame()
: wxFrame(nullptr, wxID_ANY, _("Маджонг (пасьянс)"), wxDefaultPosition, wxSize(800, 600)), : wxFrame(nullptr, wxID_ANY, _("Маджонг (пасьянс)"), wxDefaultPosition,
dataDirPath(wxStandardPaths::Get().GetUserDataDir()) wxSize(800, 600)),
{ dataDirPath(wxStandardPaths::Get().GetUserDataDir()) {
SetIcon(logo_icon); SetIcon(logo_icon);
initMenu(); initMenu();
bindMenu(); bindMenu();
Bind(wxEVT_SHOW, [this](wxShowEvent& _) -> void {
if (openLayout())
panel->Start(layoutPath, solveable,
[this](const wxSize& size) -> void {
this->SetMinClientSize(size);
});
});
CreateStatusBar(2); CreateStatusBar(2);
panel = new GamePanel(this); panel = new GamePanel(this);
panel->SetFocus(); panel->SetFocus();
openLayout();
} }
void MainFrame::initMenu() { void MainFrame::initMenu() {
@ -28,7 +34,8 @@ void MainFrame::initMenu() {
menuGame->Append(IDM_New_Game, _("Начать сначала")); menuGame->Append(IDM_New_Game, _("Начать сначала"));
menuGame->Append(IDM_Open, _("Открыть карту")); menuGame->Append(IDM_Open, _("Открыть карту"));
menuGame->AppendCheckItem(IDM_Solveable, _("Генерировать решаемую карту")); menuGame->AppendCheckItem(IDM_Solveable, _("Генерировать решаемую карту"));
menuGame->Enable(IDM_Solveable, false); // TODO: finish solveable table generation menuGame->Enable(IDM_Solveable,
false); // TODO: finish solveable table generation
menuGame->AppendSeparator(); menuGame->AppendSeparator();
menuGame->Append(IDM_Undo, _("Отменить ход")); menuGame->Append(IDM_Undo, _("Отменить ход"));
menuGame->Append(IDM_Reshuffle, _("Перемешать поле")); menuGame->Append(IDM_Reshuffle, _("Перемешать поле"));
@ -48,55 +55,77 @@ void MainFrame::initMenu() {
} }
void MainFrame::bindMenu() { void MainFrame::bindMenu() {
Bind(wxEVT_MENU, [this](wxCommandEvent& _) -> void { Bind(
Close(); wxEVT_MENU, [this](wxCommandEvent& _) -> void { Close(); }, IDM_Exit);
}, IDM_Exit);
Bind(wxEVT_MENU, [this](wxCommandEvent& _) -> void { Bind(
openLayout(); wxEVT_MENU,
}, IDM_Open); [this](wxCommandEvent& _) -> void {
if (openLayout())
panel->Start(layoutPath, solveable,
[this](const wxSize& size) -> void {
this->SetMinClientSize(size);
});
},
IDM_Open);
Bind(wxEVT_MENU, [this](wxCommandEvent& _) -> void { Bind(
(new HelpDlg(this, -1))->Show(); wxEVT_MENU,
}, IDM_Help); [this](wxCommandEvent& _) -> void { (new HelpDlg(this, -1))->Show(); },
IDM_Help);
Bind(wxEVT_MENU, [this](wxCommandEvent& _) -> void { Bind(
(new AboutDlg(this, -1))->Show(); wxEVT_MENU,
}, IDM_About); [this](wxCommandEvent& _) -> void { (new AboutDlg(this, -1))->Show(); },
IDM_About);
Bind(wxEVT_MENU, [this](wxCommandEvent& _) -> void { Bind(
(new RulesDlg(this, -1))->Show(); wxEVT_MENU,
}, IDM_Rules); [this](wxCommandEvent& _) -> void { (new RulesDlg(this, -1))->Show(); },
IDM_Rules);
Bind(wxEVT_MENU, [this](wxCommandEvent& _) -> void { Bind(
if (layoutPath.IsEmpty()) wxEVT_MENU,
openLayout(); [this](wxCommandEvent& _) -> void {
else if (!layoutPath.IsEmpty() || openLayout()) {
panel->Start(layoutPath, solveable); panel->Start(layoutPath, solveable,
[this](const wxSize& size) -> void {
this->SetMinClientSize(size);
});
}
},
IDM_New_Game);
Refresh(); Bind(
}, IDM_New_Game); wxEVT_MENU,
[this](wxCommandEvent& evt) -> void { solveable = evt.IsChecked(); },
IDM_Solveable);
Bind(wxEVT_MENU, [this](wxCommandEvent& _) -> void { Bind(
solveable = _.IsChecked(); wxEVT_MENU, [this](wxCommandEvent& _) -> void { panel->undo(); },
}, IDM_Solveable); IDM_Undo);
Bind(wxEVT_MENU, [this](wxCommandEvent& _) -> void { Bind(
panel->undo(); wxEVT_MENU,
}, IDM_Undo); [this](wxCommandEvent& _) -> void { panel->reshuffle(solveable); },
IDM_Reshuffle);
Bind(wxEVT_MENU, [this](wxCommandEvent& _) -> void {
panel->reshuffle(solveable);
}, IDM_Reshuffle);
} }
void MainFrame::openLayout() { /**
wxFileDialog openFileDlg(this, "Открыть карту", dataDirPath + wxFileName::GetPathSeparator() + _("layouts"), "Turtle.smlf", "Файлы Mahjong карт (*.smlf)|*.smlf", wxFD_OPEN | wxFD_FILE_MUST_EXIST); * Shows a file opening dialog asking for .smlf file if succed, sets its path to
* layoutPath
* @return true if user have chosen a file, false if cancelled
*/
bool MainFrame::openLayout() {
wxFileDialog openFileDlg(
this, _("Открыть карту"),
dataDirPath + wxFileName::GetPathSeparator() + _("layouts"),
_("Turtle.smlf"), _("Файлы Mahjong карт (*.smlf)|*.smlf"),
wxFD_OPEN | wxFD_FILE_MUST_EXIST);
if (openFileDlg.ShowModal() == wxID_CANCEL) if (openFileDlg.ShowModal() == wxID_CANCEL)
return; return false;
layoutPath = openFileDlg.GetPath(); layoutPath = openFileDlg.GetPath();
return true;
panel->Start(layoutPath, solveable);
} }

View File

@ -18,14 +18,14 @@ private:
void initMenu(); void initMenu();
void bindMenu(); void bindMenu();
void openLayout();
GamePanel *panel; GamePanel *panel;
bool openLayout();
const wxString dataDirPath; const wxString dataDirPath;
wxString layoutPath; wxString layoutPath;
bool solveable = false; bool solveable = false; // determites wether to generate solveable or completely random map
}; };
enum enum

View File

@ -1,7 +1,8 @@
#include "utils.h" #include "utils.h"
wxString LTimeToStr(int time) { wxString LTimeToStr(int time) {
return wxString::Format(_("%d:%02d:%02d"), time / 3600, (time / 60) % 60, time % 60); return wxString::Format(_("%d:%02d:%02d"), time / 3600, (time / 60) % 60,
time % 60);
} }
int upDiv(int a, int b) { int upDiv(int a, int b) {
@ -15,3 +16,7 @@ wxString itowxS(int a) {
wxString PRemaining(uint8_t remaining) { wxString PRemaining(uint8_t remaining) {
return wxString::Format("%i%%", remaining * 100 / 144); return wxString::Format("%i%%", remaining * 100 / 144);
} }
bool isPositive(const wxSize& size) {
return size.x > 0 && size.y > 0;
}

View File

@ -41,10 +41,8 @@ public:
using TLVec = vector<vector<vector<CardT>>>; using TLVec = vector<vector<vector<CardT>>>;
enum Values { enum Values { MATCHED = -3, EMPTY, FREE };
MATCHED = -3,
EMPTY, bool isPositive(const wxSize& size);
FREE
};
#endif #endif