From bd53759d021da31acec7f6080450085c1fae98f4 Mon Sep 17 00:00:00 2001 From: kyak Date: Fri, 14 Jan 2011 16:30:00 +0300 Subject: [PATCH] Tile: the 15 Puzzle game written in Qt4 This was my first real try for Qt (and C++, too). Don't beat me hard :) --- Tile/Makefile | 43 +++ Tile/src/Tile.pro | 9 + Tile/src/main.cpp | 18 ++ Tile/src/tile.cpp | 354 +++++++++++++++++++++ Tile/src/tile.h | 43 +++ Tile/src/tile.ui | 765 ++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 1232 insertions(+) create mode 100644 Tile/Makefile create mode 100644 Tile/src/Tile.pro create mode 100644 Tile/src/main.cpp create mode 100644 Tile/src/tile.cpp create mode 100644 Tile/src/tile.h create mode 100644 Tile/src/tile.ui diff --git a/Tile/Makefile b/Tile/Makefile new file mode 100644 index 0000000..e4240c0 --- /dev/null +++ b/Tile/Makefile @@ -0,0 +1,43 @@ +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# + +include $(TOPDIR)/rules.mk + +PKG_NAME:=Tile +PKG_VERSION:=20110114 +PKG_RELEASE:=1 + +include $(INCLUDE_DIR)/package.mk +PKG_UNPACK:=$(CP) ./src/{tile.*,main.cpp,Tile.pro} $(PKG_BUILD_DIR) + +$(call include_mk,qmake.mk) + +define Package/Tile + SECTION:=games + CATEGORY:=Games + TITLE:=15 Puzzle game, written in Qt + DEPENDS:=+qt4 +qt4-gui +dejavu-fonts-ttf +endef + +define Build/Prepare + $(call Build/Prepare/Default) + (\ +cd $(PKG_BUILD_DIR); \ +echo "QMAKE_LIBS+=-Wl,-rpath-link=$(STAGING_DIR)/usr/lib" >> Tile.pro; \ +echo "INCLUDEPATH += $(STAGING_DIR)/usr/include/QtGui" >> Tile.pro; \ +echo "INCLUDEPATH += $(STAGING_DIR)/usr/include/QtCore" >> Tile.pro; \ +) +endef + +define Build/Configure + $(call Build/Configure/Qmake,Tile) +endef + +define Package/Tile/install + $(INSTALL_DIR) $(1)/usr/bin + $(INSTALL_BIN) $(PKG_BUILD_DIR)/Tile $(1)/usr/bin/ +endef + +$(eval $(call BuildPackage,Tile)) diff --git a/Tile/src/Tile.pro b/Tile/src/Tile.pro new file mode 100644 index 0000000..2879a23 --- /dev/null +++ b/Tile/src/Tile.pro @@ -0,0 +1,9 @@ +# ------------------------------------------------- +# Project created by QtCreator 2011-01-13T20:55:49 +# ------------------------------------------------- +TARGET = Tile +TEMPLATE = app +SOURCES += main.cpp \ + tile.cpp +HEADERS += tile.h +FORMS += tile.ui diff --git a/Tile/src/main.cpp b/Tile/src/main.cpp new file mode 100644 index 0000000..d930939 --- /dev/null +++ b/Tile/src/main.cpp @@ -0,0 +1,18 @@ +#include +#include "tile.h" + + +#if defined(Q_WS_QWS) +#include +#endif + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + Tile w; + #if defined(Q_WS_QWS) + QWSServer::setCursorVisible(false); + #endif + w.show(); + return a.exec(); +} diff --git a/Tile/src/tile.cpp b/Tile/src/tile.cpp new file mode 100644 index 0000000..a6e4b1b --- /dev/null +++ b/Tile/src/tile.cpp @@ -0,0 +1,354 @@ +#include "tile.h" +#include "ui_tile.h" + +Tile::Tile(QWidget *parent) : + QMainWindow(parent), + ui(new Ui::Tile) +{ + ui->setupUi(this); + ui->pushButton_16->hide(); + ui->pushButton->setProperty("id","1"); + ui->pushButton_2->setProperty("id","2"); + ui->pushButton_3->setProperty("id","3"); + ui->pushButton_4->setProperty("id","4"); + ui->pushButton_5->setProperty("id","5"); + ui->pushButton_6->setProperty("id","6"); + ui->pushButton_7->setProperty("id","7"); + ui->pushButton_8->setProperty("id","8"); + ui->pushButton_9->setProperty("id","9"); + ui->pushButton_10->setProperty("id","10"); + ui->pushButton_11->setProperty("id","11"); + ui->pushButton_12->setProperty("id","12"); + ui->pushButton_13->setProperty("id","13"); + ui->pushButton_14->setProperty("id","14"); + ui->pushButton_15->setProperty("id","15"); + ui->pushButton_16->setProperty("id","16"); + /*ui->pushButton_Reset->setProperty("id","Reset"); + ui->pushButton_Shuffle->setProperty("id","Shuffle"); + ui->pushButton_Help->setProperty("id","Help"); + ui->pushButton_Quit->setProperty("id","Quit");*/ + /* + ui->pushButton->setAccessibleDescription("1"); + ui->pushButton_2->setAccessibleDescription("2"); + ui->pushButton_3->setAccessibleDescription("3"); + ui->pushButton_4->setAccessibleDescription("4"); + ui->pushButton_5->setAccessibleDescription("5"); + ui->pushButton_6->setAccessibleDescription("6"); + ui->pushButton_7->setAccessibleDescription("7"); + ui->pushButton_8->setAccessibleDescription("8"); + ui->pushButton_9->setAccessibleDescription("9"); + ui->pushButton_10->setAccessibleDescription("10"); + ui->pushButton_11->setAccessibleDescription("11"); + ui->pushButton_12->setAccessibleDescription("12"); + ui->pushButton_13->setAccessibleDescription("13"); + ui->pushButton_14->setAccessibleDescription("14"); + ui->pushButton_15->setAccessibleDescription("15"); + ui->pushButton_16->setAccessibleDescription("16"); + */ + // Create seed for the random + // That is needed only once on application startup + QTime time = QTime::currentTime(); + qsrand((uint)time.msec()); + + qApp->installEventFilter(this); + //ui->pushButton->installEventFilter(this); +} + +Tile::~Tile() +{ + delete ui; +} + +void Tile::changeEvent(QEvent *e) +{ + QMainWindow::changeEvent(e); + switch (e->type()) { + case QEvent::LanguageChange: + ui->retranslateUi(this); + break; + default: + break; + } +} + +void Tile::checkNeighbours() +{ + QPushButton *button = qobject_cast< QPushButton* >(QObject::sender()); + //int id = button->accessibleDescription().toInt(); + int id = button->property("id").toInt(); + //check button to the right + if (id != 16 && id != 12 && id != 8 && id != 4) { + QPushButton *button_neighbour = idtoButton(id+1); + if (button_neighbour->text() == "16" && button_neighbour->isHidden()) { + swapButtons(button, button_neighbour); + return; + } + } + //check button to the left + if (id != 13 && id != 9 && id != 5 && id != 1) { + QPushButton *button_neighbour = idtoButton(id-1); + if (button_neighbour->text() == "16" && button_neighbour->isHidden()) { + swapButtons(button, button_neighbour); + return; + } + } + //check button to the bottom + if (id != 16 && id != 15 && id != 14 && id != 13) { + QPushButton *button_neighbour = idtoButton(id+4); + if (button_neighbour->text() == "16" && button_neighbour->isHidden()) { + swapButtons(button, button_neighbour); + return; + } + } + //check button to the up + if (id != 4 && id != 3 && id != 2 && id != 1) { + QPushButton *button_neighbour = idtoButton(id-4); + if (button_neighbour->text() == "16" && button_neighbour->isHidden()) { + swapButtons(button, button_neighbour); + return; + } + } + //qDebug() << "No swap candidates..."; + return; +} + +QPushButton* Tile::idtoButton(int id) +{ + switch (id) { + case 1: + return ui->pushButton; + case 2: + return ui->pushButton_2; + case 3: + return ui->pushButton_3; + case 4: + return ui->pushButton_4; + case 5: + return ui->pushButton_5; + case 6: + return ui->pushButton_6; + case 7: + return ui->pushButton_7; + case 8: + return ui->pushButton_8; + case 9: + return ui->pushButton_9; + case 10: + return ui->pushButton_10; + case 11: + return ui->pushButton_11; + case 12: + return ui->pushButton_12; + case 13: + return ui->pushButton_13; + case 14: + return ui->pushButton_14; + case 15: + return ui->pushButton_15; + case 16: + return ui->pushButton_16; + default: + break; + } + return NULL; +} + +void Tile::swapButtons(QPushButton *button, QPushButton *button_neighbour) { + button->hide(); + button_neighbour->setText(button->text()); + button->setText("16"); + button_neighbour->show(); + button_neighbour->setFocus(); +} + +void Tile::Reset() +{ + for (int i = 1; i < 16; i++) { + QPushButton *button = idtoButton(i); + QString str; + button->show(); + button->setText(str.setNum(i)); + } + QPushButton *button = idtoButton(16); + button->hide(); + button->setText("16"); +} + +void Tile::Quit() +{ + switch (QMessageBox::information(this, + "Confirm Quit", + "Are you sure to quit?", + "&Quit","&Cancel")) + { + case 0: + qApp->quit(); + default: + break; + } +} + +void Tile::Shuffle() +{ + Reset(); + for (int i = 1; i < 16; i++) { + //get random number 1..15 + int id = randInt(1,15); + //swap it + QPushButton *button_1 = idtoButton(i); + QPushButton *button_2 = idtoButton(id); + QString str = button_1->text(); + button_1->setText(button_2->text()); + button_2->setText(str); + } + if (!isSolvable()) { + Shuffle(); + } +} + +int Tile::randInt(int low, int high) +{ + // Random number between low and high + return qrand() % ((high + 1) - low) + low; +} + +bool Tile::isSolvable() +{ + //http://mathworld.wolfram.com/15Puzzle.html + //accumulator + int acc = 0; + //iterate through all tiles + for (int i = 1; i < 17; i++) { + //get button from id + QPushButton *button = idtoButton(i); + //get the number on tile + int num = button->text().toInt(); + if (num == 16) { + //get row of empty tile + if (i < 5) { + acc = acc + 1; + } else if (i < 9) { + acc = acc + 2; + } else if (i < 13) { + acc = acc + 3; + } else { + acc = acc + 4; + } + continue; + } + //iterate though the rest of tiles + for (int j = i+1; j < 17; j++) { + //get next button + QPushButton *button_next = idtoButton(j); + //get the number of next tile + int num_next = button_next->text().toInt(); + //compare and increment accumulator + if (num_next < num) { + acc++; + } + } + } + //qDebug() << acc; + if (acc%2 == 0) { + return 1; + } else { + return 0; + } +} + +void Tile::Help() +{ + QMessageBox::about(this, + "15 Puzzle", + "\ +This is the famous 15 Puzzle game.\n\ +The object of the puzzle is to place the\n\ +tiles in order by making sliding moves\n\ +that use the empty space.\n\ +\n\ +\"Reset\" (Alt+R): reset the puzzle to solved position\n\ +\"Shuffle\" (Alt+S): shuffle the puzzle. Note that this\n\ +always produces solvable positions, don\'t give up\n\ +\"Help\" (Alt+H): show this help\n\ +\"Quit\" (Alt+Q): quit the app"); +} + +void Tile::keyPressEvent(QKeyEvent *event) +{ + if (event->key() == Qt::Key_Escape || event->key() == Qt::Key_Q) { + Quit(); + } else if (event->key() == Qt::Key_Up) { + //focusNextChild(); + //qDebug() << qApp->focusWidget(); + QPushButton *button = qobject_cast< QPushButton* >(qApp->focusWidget()); + keyUp(button); + } else if (event->key() == Qt::Key_Down) { + //focusPreviousChild(); + //qDebug() << qApp->focusWidget(); + QPushButton *button = qobject_cast< QPushButton* >(qApp->focusWidget()); + keyDown(button); + } else { + return; + } +} + +bool Tile::eventFilter(QObject *obj, QEvent *event) +{ + QKeyEvent *keyEvent = NULL;//event data, if this is a keystroke event + bool result = false;//return true to consume the keystroke + + if (event->type() == QEvent::KeyPress) + { + keyEvent = dynamic_cast(event); + //override Key Up and Key Down only + if (keyEvent->key() == Qt::Key_Up || keyEvent->key() == Qt::Key_Down) { + this->keyPressEvent(keyEvent); + result = true; + } else { + result = QObject::eventFilter(obj, event); + } + }//if type() + + /*else if (event->type() == QEvent::KeyRelease) + { + keyEvent = dynamic_cast(event); + this->keyReleaseEvent(keyEvent); + result = true; + }*///else if type() + + //### Standard event processing ### + else + result = QObject::eventFilter(obj, event); + + return result; +}//eventFilter + +void Tile::keyUp(QPushButton *button) { + int id = button->property("id").toInt(); + QPushButton *button_up; + if (id < 5) { + button_up = idtoButton(id+12); + } else { + button_up = idtoButton(id-4); + } + if (button_up->isHidden()) { + keyUp(button_up); + } else { + button_up->setFocus(); + } +} + +void Tile::keyDown(QPushButton *button) { + int id = button->property("id").toInt(); + QPushButton *button_down; + if (id > 12) { + button_down = idtoButton(id-12); + } else { + button_down = idtoButton(id+4); + } + if (button_down->isHidden()) { + keyDown(button_down); + } else { + button_down->setFocus(); + } +} diff --git a/Tile/src/tile.h b/Tile/src/tile.h new file mode 100644 index 0000000..f1d891e --- /dev/null +++ b/Tile/src/tile.h @@ -0,0 +1,43 @@ +#ifndef TILE_H +#define TILE_H + +#include +#include +#include +#include +#include +#include + +namespace Ui { + class Tile; +} + +class Tile : public QMainWindow { + Q_OBJECT +public: + Tile(QWidget *parent = 0); + ~Tile(); + +public slots: + void checkNeighbours(); + QPushButton* idtoButton(int id); + void swapButtons(QPushButton *button, QPushButton *button_neighbour); + void Reset(); + void Quit(); + void Shuffle(); + int randInt(int low, int high); + bool isSolvable(); + void Help(); + void keyPressEvent(QKeyEvent *event); + bool eventFilter(QObject *obj, QEvent *event); + void keyUp(QPushButton *button); + void keyDown(QPushButton *button); + +protected: + void changeEvent(QEvent *e); + +private: + Ui::Tile *ui; +}; + +#endif // TILE_H diff --git a/Tile/src/tile.ui b/Tile/src/tile.ui new file mode 100644 index 0000000..27cc915 --- /dev/null +++ b/Tile/src/tile.ui @@ -0,0 +1,765 @@ + + + Tile + + + + 0 + 0 + 320 + 240 + + + + Tile + + + + + + + + + 0 + 0 + 60 + 60 + + + + + 16777215 + 16777213 + + + + + DejaVu Sans + 28 + + + + 1 + + + false + + + + + + 60 + 0 + 60 + 60 + + + + + DejaVu Sans + 28 + + + + 2 + + + + + + 120 + 0 + 60 + 60 + + + + + DejaVu Sans + 28 + + + + 3 + + + + + + 180 + 0 + 60 + 60 + + + + + DejaVu Sans + 28 + + + + 4 + + + + + + 0 + 60 + 60 + 60 + + + + + DejaVu Sans + 28 + + + + 5 + + + + + + 60 + 60 + 60 + 60 + + + + + DejaVu Sans + 28 + + + + 6 + + + + + + 120 + 60 + 60 + 60 + + + + + DejaVu Sans + 28 + + + + 7 + + + + + + 180 + 60 + 60 + 60 + + + + + DejaVu Sans + 28 + + + + 8 + + + + + + 0 + 120 + 60 + 60 + + + + + DejaVu Sans + 28 + + + + 9 + + + + + + 60 + 120 + 60 + 60 + + + + + DejaVu Sans + 28 + + + + 10 + + + + + + 120 + 120 + 60 + 60 + + + + + DejaVu Sans + 28 + + + + 11 + + + + + + 180 + 120 + 60 + 60 + + + + + DejaVu Sans + 28 + + + + 12 + + + + + + 0 + 180 + 60 + 60 + + + + + DejaVu Sans + 28 + + + + 13 + + + + + + 60 + 180 + 60 + 60 + + + + + DejaVu Sans + 28 + + + + 14 + + + + + + 120 + 180 + 60 + 60 + + + + + DejaVu Sans + 28 + + + + 15 + + + + + + 180 + 180 + 60 + 60 + + + + + DejaVu Sans + 28 + + + + 16 + + + + + + 255 + 20 + 60 + 20 + + + + Qt::NoFocus + + + &Reset + + + + + + 255 + 80 + 60 + 20 + + + + Qt::NoFocus + + + &Shuffle + + + + + + 255 + 200 + 60 + 20 + + + + Qt::NoFocus + + + &Quit + + + + + + 255 + 140 + 60 + 20 + + + + Qt::NoFocus + + + &Help + + + + + + 240 + 0 + 20 + 240 + + + + Qt::Vertical + + + + + + + pushButton + pushButton_2 + pushButton_3 + pushButton_4 + pushButton_Reset + pushButton_5 + pushButton_6 + pushButton_7 + pushButton_8 + pushButton_Shuffle + pushButton_9 + pushButton_10 + pushButton_11 + pushButton_12 + pushButton_Help + pushButton_13 + pushButton_14 + pushButton_15 + pushButton_16 + pushButton_Quit + + + + + pushButton + clicked() + Tile + checkNeighbours() + + + 40 + 23 + + + 373 + 34 + + + + + pushButton_2 + clicked() + Tile + checkNeighbours() + + + 109 + 20 + + + 343 + 47 + + + + + pushButton_3 + clicked() + Tile + checkNeighbours() + + + 156 + 15 + + + 371 + 19 + + + + + pushButton_4 + clicked() + Tile + checkNeighbours() + + + 236 + 21 + + + 357 + 29 + + + + + pushButton_5 + clicked() + Tile + checkNeighbours() + + + 46 + 100 + + + 340 + 91 + + + + + pushButton_6 + clicked() + Tile + checkNeighbours() + + + 116 + 75 + + + 369 + 136 + + + + + pushButton_7 + clicked() + Tile + checkNeighbours() + + + 165 + 71 + + + 356 + 81 + + + + + pushButton_8 + clicked() + Tile + checkNeighbours() + + + 239 + 110 + + + 396 + 107 + + + + + pushButton_9 + clicked() + Tile + checkNeighbours() + + + 38 + 158 + + + 355 + 149 + + + + + pushButton_10 + clicked() + Tile + checkNeighbours() + + + 103 + 139 + + + 395 + 160 + + + + + pushButton_11 + clicked() + Tile + checkNeighbours() + + + 179 + 168 + + + 376 + 180 + + + + + pushButton_12 + clicked() + Tile + checkNeighbours() + + + 239 + 174 + + + 414 + 201 + + + + + pushButton_13 + clicked() + Tile + checkNeighbours() + + + 48 + 211 + + + 344 + 218 + + + + + pushButton_14 + clicked() + Tile + checkNeighbours() + + + 102 + 200 + + + 335 + 211 + + + + + pushButton_15 + clicked() + Tile + checkNeighbours() + + + 161 + 194 + + + 360 + 188 + + + + + pushButton_16 + clicked() + Tile + checkNeighbours() + + + 225 + 229 + + + 387 + 234 + + + + + pushButton_Reset + clicked() + Tile + Reset() + + + 284 + 31 + + + 288 + 59 + + + + + pushButton_Quit + clicked() + Tile + Quit() + + + 273 + 211 + + + 287 + 120 + + + + + pushButton_Shuffle + clicked() + Tile + Shuffle() + + + 278 + 90 + + + 267 + 121 + + + + + pushButton_Help + clicked() + Tile + Help() + + + 290 + 148 + + + 292 + 178 + + + + + + checkNeighbours() + Reset() + Quit() + Shuffle() + Help() + +