|
|
|
// Author: Denis Kozadaev - (c) 2017-2020
|
|
|
|
|
|
|
|
|
|
|
|
#include <cstdlib>
|
|
|
|
|
|
|
|
#include <tdeapplication.h>
|
|
|
|
#include <tqpainter.h>
|
|
|
|
#include <tqcursor.h>
|
|
|
|
#include <tqmessagebox.h>
|
|
|
|
#include <tqfiledialog.h>
|
|
|
|
#include <tqdatetime.h>
|
|
|
|
#include <tqwmatrix.h>
|
|
|
|
|
|
|
|
#include "gameboard.h"
|
|
|
|
|
|
|
|
#define DELAY 10
|
|
|
|
#define STEP 5
|
|
|
|
|
|
|
|
BoardItem::BoardItem(int n, TQWidget *parent, const char *name)
|
|
|
|
:TQLabel(parent, name)
|
|
|
|
{
|
|
|
|
num = n;
|
|
|
|
}
|
|
|
|
|
|
|
|
BoardItem::~BoardItem()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
BoardItem::paintEvent(TQPaintEvent *e)
|
|
|
|
{
|
|
|
|
TQPainter *p;
|
|
|
|
int w = width() - 1,
|
|
|
|
h = height() - 1;
|
|
|
|
|
|
|
|
TQLabel::paintEvent(e);
|
|
|
|
p = new TQPainter(this);
|
|
|
|
|
|
|
|
p->setPen(TQt::black);
|
|
|
|
p->drawRect(0, 0, w, h);
|
|
|
|
p->setPen(TQt::magenta);
|
|
|
|
p->drawText(0, 0, w, h, TQt::AlignCenter,
|
|
|
|
TQString::number(item() + 1));
|
|
|
|
|
|
|
|
delete p;
|
|
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
GameBoard::GameBoard(TQWidget *parent, const char *name)
|
|
|
|
:TQWidget(parent, name)
|
|
|
|
{
|
|
|
|
#include "cat.xpm"
|
|
|
|
TQPixmap xpm(cat_xpm);
|
|
|
|
|
|
|
|
memset(map, 0, sizeof(map));
|
|
|
|
nt = n = xt = yt = -1;
|
|
|
|
dx = dy = 0;
|
|
|
|
|
|
|
|
tmr = new TQTimer(this);
|
|
|
|
TQObject::connect(tmr, SIGNAL(timeout()), this, SLOT(moveItem()));
|
|
|
|
setEnabled(TRUE);
|
|
|
|
origin = xpm;
|
|
|
|
}
|
|
|
|
|
|
|
|
GameBoard::~GameBoard()
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < 16; ++i)
|
|
|
|
if (map[i] != NULL)
|
|
|
|
delete map[i];
|
|
|
|
|
|
|
|
delete tmr;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
GameBoard::resizeEvent(TQResizeEvent *e)
|
|
|
|
{
|
|
|
|
TQWidget::resizeEvent(e);
|
|
|
|
initMap();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
GameBoard::initMap()
|
|
|
|
{
|
|
|
|
const int num = 15;
|
|
|
|
int i, x, y,
|
|
|
|
w = width() / 4,
|
|
|
|
h = height() / 4;
|
|
|
|
TQFont fnt("Antiqua", 18);
|
|
|
|
TQPixmap xpm;
|
|
|
|
|
|
|
|
if (!origin.isNull()) {
|
|
|
|
TQWMatrix mtx;
|
|
|
|
mtx.scale((float)width() / (float)origin.width(),
|
|
|
|
(float)height() / (float)origin.height());
|
|
|
|
xpm = origin.xForm(mtx);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < num; ++i) {
|
|
|
|
if (map[i] != NULL)
|
|
|
|
delete map[i];
|
|
|
|
map[i] = new BoardItem(i, this);
|
|
|
|
map[i]->setFont(fnt);
|
|
|
|
map[i]->resize(w, h);
|
|
|
|
map[i]->setAlignment(TQt::AlignCenter);
|
|
|
|
if (!xpm.isNull()) {
|
|
|
|
y = (i >> 2);
|
|
|
|
x = i - (y << 2);
|
|
|
|
map[i]->move(x * w, y * h);
|
|
|
|
TQPixmap xpm1(map[i]->size());
|
|
|
|
copyBlt(&xpm1, 0, 0, &xpm,
|
|
|
|
map[i]->x(), map[i]->y(), w, h);
|
|
|
|
map[i]->setPixmap(xpm1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (map[num] != NULL)
|
|
|
|
delete map[num];
|
|
|
|
map[num] = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
GameBoard::mousePressEvent(TQMouseEvent *e)
|
|
|
|
{
|
|
|
|
int x = e->x(),
|
|
|
|
y = e->y(),
|
|
|
|
i, it;
|
|
|
|
|
|
|
|
i = index(x, y);
|
|
|
|
if (mayMove(i) && (n == -1)) {
|
|
|
|
for (it = 0; (it < 16) && (map[it] != NULL); ++it);
|
|
|
|
startMoving(i, it);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
GameBoard::mayMove(int n)
|
|
|
|
{
|
|
|
|
int res = 0;
|
|
|
|
|
|
|
|
if ((n >= 0) && (n < 16)) {
|
|
|
|
switch (n) {
|
|
|
|
case 0:
|
|
|
|
res = (map[n + 1] == NULL) ||
|
|
|
|
(map[n + 4] == NULL);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 1:
|
|
|
|
case 2:
|
|
|
|
res = (map[n - 1] == NULL) ||
|
|
|
|
(map[n + 1] == NULL) ||
|
|
|
|
(map[n + 4] == NULL);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 3:
|
|
|
|
res = (map[n - 1] == NULL) ||
|
|
|
|
(map[n + 4] == NULL);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 4:
|
|
|
|
case 8:
|
|
|
|
res = (map[n + 1] == NULL) ||
|
|
|
|
(map[n - 4] == NULL) ||
|
|
|
|
(map[n + 4] == NULL);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 5:
|
|
|
|
case 6:
|
|
|
|
case 9:
|
|
|
|
case 10:
|
|
|
|
res = (map[n - 1] == NULL) ||
|
|
|
|
(map[n + 1] == NULL) ||
|
|
|
|
(map[n - 4] == NULL) ||
|
|
|
|
(map[n + 4] == NULL);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 7:
|
|
|
|
case 11:
|
|
|
|
res = (map[n - 1] == NULL) ||
|
|
|
|
(map[n - 4] == NULL) ||
|
|
|
|
(map[n + 4] == NULL);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 12:
|
|
|
|
res = (map[n + 1] == NULL) ||
|
|
|
|
(map[n - 4] == NULL);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 13:
|
|
|
|
case 14:
|
|
|
|
res = (map[n - 1] == NULL) ||
|
|
|
|
(map[n + 1] == NULL) ||
|
|
|
|
(map[n - 4] == NULL);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 15:
|
|
|
|
res = (map[n - 1] == NULL) ||
|
|
|
|
(map[n - 4] == NULL);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return (res);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
GameBoard::index(int x, int y)
|
|
|
|
{
|
|
|
|
int ndx = -1,
|
|
|
|
i, x1, y1;
|
|
|
|
|
|
|
|
if ((map[0] != NULL) || (map[1] != NULL)) {
|
|
|
|
for (i = 0; i < 16; ++i) {
|
|
|
|
if (map[i] != NULL) {
|
|
|
|
x1 = map[i]->x();
|
|
|
|
y1 = map[i]->y();
|
|
|
|
if ((x >= x1) && (y >= y1) &&
|
|
|
|
(x < (x1 + map[i]->width())) &&
|
|
|
|
(y < (y1 + map[i]->height()))) {
|
|
|
|
ndx = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return (ndx);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
GameBoard::startMoving(int i, int t)
|
|
|
|
{
|
|
|
|
n = i; nt = t;
|
|
|
|
xt = (t - (t & ~3)) * map[n]->width();
|
|
|
|
yt = (t >> 2) * map[n]->height();
|
|
|
|
dx = step(xt, map[n]->x());
|
|
|
|
dy = step(yt, map[n]->y());
|
|
|
|
tmr->start(DELAY);
|
|
|
|
TDEApplication::setOverrideCursor(TQCursor(TQt::WaitCursor));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
GameBoard::step(int t, int f)
|
|
|
|
{
|
|
|
|
int res;
|
|
|
|
|
|
|
|
if (t > f)
|
|
|
|
res = STEP;
|
|
|
|
else if (t < f)
|
|
|
|
res = -STEP;
|
|
|
|
else
|
|
|
|
res = 0;
|
|
|
|
|
|
|
|
return (res);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
GameBoard::moveItem()
|
|
|
|
{
|
|
|
|
int x, y, stp, a;
|
|
|
|
|
|
|
|
if ((n != -1) && (nt != -1) && (map[n] != NULL)) {
|
|
|
|
x = map[n]->x();
|
|
|
|
y = map[n]->y();
|
|
|
|
stp = 0;
|
|
|
|
if (dx != 0) {
|
|
|
|
stp = (x == xt);
|
|
|
|
if (!stp) {
|
|
|
|
a = abs(x - xt);
|
|
|
|
if (a < abs(dx))
|
|
|
|
dx = sign(dx) * a;
|
|
|
|
x += dx;
|
|
|
|
}
|
|
|
|
} else if (dy != 0) {
|
|
|
|
stp = (y == yt);
|
|
|
|
if (!stp) {
|
|
|
|
a = abs(y - yt);
|
|
|
|
if (a < abs(dy))
|
|
|
|
dy = sign(dy) * a;
|
|
|
|
y += dy;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
map[n]->move(x, y);
|
|
|
|
if (stp) {
|
|
|
|
map[nt] = map[n];
|
|
|
|
map[n] = NULL;
|
|
|
|
nt = n = -1;
|
|
|
|
xt = yt = -1;
|
|
|
|
dx = dy = 0;
|
|
|
|
tmr->stop();
|
|
|
|
TDEApplication::restoreOverrideCursor();
|
|
|
|
checkEndGame();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
GameBoard::sign(int x)
|
|
|
|
{
|
|
|
|
int res;
|
|
|
|
|
|
|
|
if (x > 0)
|
|
|
|
res = 1;
|
|
|
|
else if (x < 0)
|
|
|
|
res = -1;
|
|
|
|
else
|
|
|
|
res = 0;
|
|
|
|
|
|
|
|
return (res);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
GameBoard::checkEndGame()
|
|
|
|
{
|
|
|
|
int i, n;
|
|
|
|
TQString txt;
|
|
|
|
|
|
|
|
for (n = i = 0; i < 15; ++i)
|
|
|
|
if ((map[i] != NULL) && (map[i]->item() == i))
|
|
|
|
n++;
|
|
|
|
if (n == 15) {
|
|
|
|
txt = tr("Game Over");
|
|
|
|
TQMessageBox::information(this, txt, txt);
|
|
|
|
setEnabled(FALSE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
GameBoard::newGame()
|
|
|
|
{
|
|
|
|
setEnabled(TRUE);
|
|
|
|
initMap();
|
|
|
|
newTask();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
GameBoard::newTask()
|
|
|
|
{
|
|
|
|
int i, n, stp, x, y;
|
|
|
|
BoardItem *tmp;
|
|
|
|
|
|
|
|
srandom(TQDateTime::currentDateTime().toTime_t());
|
|
|
|
do {
|
|
|
|
stp = (random() % 13) & 0xF;
|
|
|
|
if ((stp & 1) == 0)
|
|
|
|
stp++;
|
|
|
|
} while (stp % 5 == 0);
|
|
|
|
|
|
|
|
n = random() & 0xF;
|
|
|
|
|
|
|
|
for (i = 0; i < 16; ++i) {
|
|
|
|
n += stp;
|
|
|
|
if (n > 15)
|
|
|
|
n -= 16;
|
|
|
|
tmp = map[i];
|
|
|
|
map[i] = map[n];
|
|
|
|
map[n] = tmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < 16; ++i)
|
|
|
|
if (map[i] != NULL) {
|
|
|
|
y = (i >> 2);
|
|
|
|
x = i - (y << 2);
|
|
|
|
map[i]->move(x * map[i]->width(), y * map[i]->height());
|
|
|
|
map[i]->show();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
GameBoard::loadImage()
|
|
|
|
{
|
|
|
|
TQString str;
|
|
|
|
TQPixmap img;
|
|
|
|
|
|
|
|
str = TQFileDialog::getOpenFileName(TQString::null, "*", this, NULL,
|
|
|
|
tr("Open an image..."));
|
|
|
|
|
|
|
|
if (!str.isEmpty()) {
|
|
|
|
if (img.load(str)) {
|
|
|
|
origin = img;
|
|
|
|
initMap();
|
|
|
|
} else
|
|
|
|
TQMessageBox::critical(this, tr("Error loading..."),
|
|
|
|
tr("Cannot load the image ") + str);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#include "gameboard.moc"
|