Mega Code Archive

 
Categories / C++ / Qt
 

Tetrix game

/**************************************************************************** ** ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of the examples of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial Usage ** Licensees holding valid Qt Commercial licenses may use this file in ** accordance with the Qt Commercial License Agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and Nokia. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file.  Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Nokia gives you certain additional ** rights.  These rights are described in the Nokia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3.0 as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL included in the ** packaging of this file.  Please review the following information to ** ensure the GNU General Public License version 3.0 requirements will be ** met: http://www.gnu.org/copyleft/gpl.html. ** ** If you have questions regarding the use of this file, please contact ** Nokia at qt-info@nokia.com. ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef TETRIXPIECE_H #define TETRIXPIECE_H enum TetrixShape { NoShape, ZShape, SShape, LineShape, TShape, SquareShape,                    LShape, MirroredLShape }; class TetrixPiece { public:     TetrixPiece() { setShape(NoShape); }     void setRandomShape();     void setShape(TetrixShape shape);     TetrixShape shape() const { return pieceShape; }     int x(int index) const { return coords[index][0]; }     int y(int index) const { return coords[index][1]; }     int minX() const;     int maxX() const;     int minY() const;     int maxY() const;     TetrixPiece rotatedLeft() const;     TetrixPiece rotatedRight() const; private:     void setX(int index, int x) { coords[index][0] = x; }     void setY(int index, int y) { coords[index][1] = y; }     TetrixShape pieceShape;     int coords[4][2]; }; #endif #include <QtCore> #include <stdlib.h> #include "tetrixpiece.h" void TetrixPiece::setRandomShape() {     setShape(TetrixShape(qrand() % 7 + 1)); } void TetrixPiece::setShape(TetrixShape shape) {     static const int coordsTable[8][4][2] = {         { { 0, 0 },   { 0, 0 },   { 0, 0 },   { 0, 0 } },         { { 0, -1 },  { 0, 0 },   { -1, 0 },  { -1, 1 } },         { { 0, -1 },  { 0, 0 },   { 1, 0 },   { 1, 1 } },         { { 0, -1 },  { 0, 0 },   { 0, 1 },   { 0, 2 } },         { { -1, 0 },  { 0, 0 },   { 1, 0 },   { 0, 1 } },         { { 0, 0 },   { 1, 0 },   { 0, 1 },   { 1, 1 } },         { { -1, -1 }, { 0, -1 },  { 0, 0 },   { 0, 1 } },         { { 1, -1 },  { 0, -1 },  { 0, 0 },   { 0, 1 } }     };     for (int i = 0; i < 4 ; i++) {         for (int j = 0; j < 2; ++j)             coords[i][j] = coordsTable[shape][i][j];     }     pieceShape = shape;   } int TetrixPiece::minX() const {     int min = coords[0][0];     for (int i = 1; i < 4; ++i)         min = qMin(min, coords[i][0]);     return min; } int TetrixPiece::maxX() const   {     int max = coords[0][0];     for (int i = 1; i < 4; ++i)         max = qMax(max, coords[i][0]);     return max; } int TetrixPiece::minY() const {     int min = coords[0][1];     for (int i = 1; i < 4; ++i)         min = qMin(min, coords[i][1]);     return min; } int TetrixPiece::maxY() const   {     int max = coords[0][1];     for (int i = 1; i < 4; ++i)         max = qMax(max, coords[i][1]);     return max; } TetrixPiece TetrixPiece::rotatedLeft() const {     if (pieceShape == SquareShape)         return *this;     TetrixPiece result;     result.pieceShape = pieceShape;     for (int i = 0; i < 4; ++i) {         result.setX(i, y(i));         result.setY(i, -x(i));     }     return result; } TetrixPiece TetrixPiece::rotatedRight() const {     if (pieceShape == SquareShape)         return *this;     TetrixPiece result;     result.pieceShape = pieceShape;     for (int i = 0; i < 4; ++i) {         result.setX(i, -y(i));         result.setY(i, x(i));     }     return result; } #ifndef TETRIXBOARD_H #define TETRIXBOARD_H #include <QBasicTimer> #include <QFrame> #include <QPointer> #include "tetrixpiece.h" QT_BEGIN_NAMESPACE class QLabel; QT_END_NAMESPACE class TetrixBoard : public QFrame {     Q_OBJECT public:     TetrixBoard(QWidget *parent = 0);     void setNextPieceLabel(QLabel *label);     QSize sizeHint() const;     QSize minimumSizeHint() const; public slots:     void start();     void pause(); signals:     void scoreChanged(int score);     void levelChanged(int level);     void linesRemovedChanged(int numLines); protected:     void paintEvent(QPaintEvent *event);     void keyPressEvent(QKeyEvent *event);     void timerEvent(QTimerEvent *event); private:     enum { BoardWidth = 10, BoardHeight = 22 };     TetrixShape &shapeAt(int x, int y) { return board[(y * BoardWidth) + x]; }     int timeoutTime() { return 1000 / (1 + level); }     int squareWidth() { return contentsRect().width() / BoardWidth; }     int squareHeight() { return contentsRect().height() / BoardHeight; }     void clearBoard();     void dropDown();     void oneLineDown();     void pieceDropped(int dropHeight);     void removeFullLines();     void newPiece();     void showNextPiece();     bool tryMove(const TetrixPiece &newPiece, int newX, int newY);     void drawSquare(QPainter &painter, int x, int y, TetrixShape shape);     QBasicTimer timer;     QPointer<QLabel> nextPieceLabel;     bool isStarted;     bool isPaused;     bool isWaitingAfterLine;     TetrixPiece curPiece;     TetrixPiece nextPiece;     int curX;     int curY;     int numLinesRemoved;     int numPiecesDropped;     int score;     int level;     TetrixShape board[BoardWidth * BoardHeight]; }; #endif #include <QtGui> #include "tetrixboard.h" TetrixBoard::TetrixBoard(QWidget *parent)     : QFrame(parent) {     setFrameStyle(QFrame::Panel | QFrame::Sunken);     setFocusPolicy(Qt::StrongFocus);     isStarted = false;     isPaused = false;     clearBoard();     nextPiece.setRandomShape(); } void TetrixBoard::setNextPieceLabel(QLabel *label) {     nextPieceLabel = label; } QSize TetrixBoard::sizeHint() const {     return QSize(BoardWidth * 15 + frameWidth() * 2,                  BoardHeight * 15 + frameWidth() * 2); } QSize TetrixBoard::minimumSizeHint() const   {     return QSize(BoardWidth * 5 + frameWidth() * 2,                  BoardHeight * 5 + frameWidth() * 2); } void TetrixBoard::start() {     if (isPaused)         return;     isStarted = true;     isWaitingAfterLine = false;     numLinesRemoved = 0;     numPiecesDropped = 0;     score = 0;     level = 1;     clearBoard();     emit linesRemovedChanged(numLinesRemoved);     emit scoreChanged(score);     emit levelChanged(level);     newPiece();     timer.start(timeoutTime(), this); } void TetrixBoard::pause() {     if (!isStarted)         return;     isPaused = !isPaused;     if (isPaused) {   timer.stop();     } else {   timer.start(timeoutTime(), this);     }     update();   } void TetrixBoard::paintEvent(QPaintEvent *event) {     QFrame::paintEvent(event);     QPainter painter(this);     QRect rect = contentsRect();     if (isPaused) {   painter.drawText(rect, Qt::AlignCenter, tr("Pause"));         return;     }     int boardTop = rect.bottom() - BoardHeight*squareHeight();     for (int i = 0; i < BoardHeight; ++i) {         for (int j = 0; j < BoardWidth; ++j) {             TetrixShape shape = shapeAt(j, BoardHeight - i - 1);       if (shape != NoShape)                 drawSquare(painter, rect.left() + j * squareWidth(),                            boardTop + i * squareHeight(), shape);         }       }     if (curPiece.shape() != NoShape) {         for (int i = 0; i < 4; ++i) {             int x = curX + curPiece.x(i);             int y = curY - curPiece.y(i);             drawSquare(painter, rect.left() + x * squareWidth(),                        boardTop + (BoardHeight - y - 1) * squareHeight(),                        curPiece.shape());         }       }   } void TetrixBoard::keyPressEvent(QKeyEvent *event) {     if (!isStarted || isPaused || curPiece.shape() == NoShape) {   QFrame::keyPressEvent(event);         return;     }     switch (event->key()) {     case Qt::Key_Left:         tryMove(curPiece, curX - 1, curY);   break;     case Qt::Key_Right:         tryMove(curPiece, curX + 1, curY);   break;     case Qt::Key_Down:         tryMove(curPiece.rotatedRight(), curX, curY);   break;     case Qt::Key_Up:         tryMove(curPiece.rotatedLeft(), curX, curY);   break;     case Qt::Key_Space:   dropDown();   break;     case Qt::Key_D:   oneLineDown();   break;     default:   QFrame::keyPressEvent(event);     } } void TetrixBoard::timerEvent(QTimerEvent *event) {     if (event->timerId() == timer.timerId()) {         if (isWaitingAfterLine) {       isWaitingAfterLine = false;       newPiece();       timer.start(timeoutTime(), this);         } else {             oneLineDown();         }     } else {         QFrame::timerEvent(event);       }   } void TetrixBoard::clearBoard() {     for (int i = 0; i < BoardHeight * BoardWidth; ++i)         board[i] = NoShape; } void TetrixBoard::dropDown() {     int dropHeight = 0;     int newY = curY;     while (newY > 0) {         if (!tryMove(curPiece, curX, newY - 1))             break;         --newY;         ++dropHeight;     }     pieceDropped(dropHeight);   } void TetrixBoard::oneLineDown() {     if (!tryMove(curPiece, curX, curY - 1))   pieceDropped(0); } void TetrixBoard::pieceDropped(int dropHeight) {     for (int i = 0; i < 4; ++i) {         int x = curX + curPiece.x(i);         int y = curY - curPiece.y(i);         shapeAt(x, y) = curPiece.shape();     }     ++numPiecesDropped;     if (numPiecesDropped % 25 == 0) {         ++level;         timer.start(timeoutTime(), this);         emit levelChanged(level);     }     score += dropHeight + 7;     emit scoreChanged(score);     removeFullLines();     if (!isWaitingAfterLine)         newPiece();   } void TetrixBoard::removeFullLines() {     int numFullLines = 0;     for (int i = BoardHeight - 1; i >= 0; --i) {         bool lineIsFull = true;         for (int j = 0; j < BoardWidth; ++j) {             if (shapeAt(j, i) == NoShape) {                 lineIsFull = false;                 break;             }         }         if (lineIsFull) {         ++numFullLines;       for (int k = i; k < BoardHeight - 1; ++k) {                 for (int j = 0; j < BoardWidth; ++j)                     shapeAt(j, k) = shapeAt(j, k + 1);       }         for (int j = 0; j < BoardWidth; ++j)                 shapeAt(j, BoardHeight - 1) = NoShape;   }       }     if (numFullLines > 0) {   numLinesRemoved += numFullLines;   score += 10 * numFullLines;   emit linesRemovedChanged(numLinesRemoved);         emit scoreChanged(score);         timer.start(500, this);         isWaitingAfterLine = true;         curPiece.setShape(NoShape);         update();     }   } void TetrixBoard::newPiece() {     curPiece = nextPiece;     nextPiece.setRandomShape();     showNextPiece();     curX = BoardWidth / 2 + 1;     curY = BoardHeight - 1 + curPiece.minY();     if (!tryMove(curPiece, curX, curY)) {   curPiece.setShape(NoShape);         timer.stop();         isStarted = false;     }   } void TetrixBoard::showNextPiece() {     if (!nextPieceLabel)         return;     int dx = nextPiece.maxX() - nextPiece.minX() + 1;     int dy = nextPiece.maxY() - nextPiece.minY() + 1;     QPixmap pixmap(dx * squareWidth(), dy * squareHeight());     QPainter painter(&pixmap);     painter.fillRect(pixmap.rect(), nextPieceLabel->palette().background());     for (int i = 0; i < 4; ++i) {         int x = nextPiece.x(i) - nextPiece.minX();         int y = nextPiece.y(i) - nextPiece.minY();         drawSquare(painter, x * squareWidth(), y * squareHeight(),                    nextPiece.shape());     }     nextPieceLabel->setPixmap(pixmap);   } bool TetrixBoard::tryMove(const TetrixPiece &newPiece, int newX, int newY) {     for (int i = 0; i < 4; ++i) {         int x = newX + newPiece.x(i);         int y = newY - newPiece.y(i);         if (x < 0 || x >= BoardWidth || y < 0 || y >= BoardHeight)             return false;         if (shapeAt(x, y) != NoShape)             return false;     }     curPiece = newPiece;     curX = newX;     curY = newY;     update();     return true; } void TetrixBoard::drawSquare(QPainter &painter, int x, int y, TetrixShape shape) {     static const QRgb colorTable[8] = {         0x000000, 0xCC6666, 0x66CC66, 0x6666CC,         0xCCCC66, 0xCC66CC, 0x66CCCC, 0xDAAA00     };     QColor color = colorTable[int(shape)];     painter.fillRect(x + 1, y + 1, squareWidth() - 2, squareHeight() - 2,                      color);     painter.setPen(color.light());     painter.drawLine(x, y + squareHeight() - 1, x, y);     painter.drawLine(x, y, x + squareWidth() - 1, y);     painter.setPen(color.dark());     painter.drawLine(x + 1, y + squareHeight() - 1,                      x + squareWidth() - 1, y + squareHeight() - 1);     painter.drawLine(x + squareWidth() - 1, y + squareHeight() - 1,                      x + squareWidth() - 1, y + 1); } #ifndef TETRIXWINDOW_H #define TETRIXWINDOW_H #include <QFrame> #include <QWidget> QT_BEGIN_NAMESPACE class QLCDNumber; class QLabel; class QPushButton; QT_END_NAMESPACE class TetrixBoard; class TetrixWindow : public QWidget {     Q_OBJECT public:     TetrixWindow(); private:     QLabel *createLabel(const QString &text);     TetrixBoard *board;     QLabel *nextPieceLabel;     QLCDNumber *scoreLcd;     QLCDNumber *levelLcd;     QLCDNumber *linesLcd;     QPushButton *startButton;     QPushButton *quitButton;     QPushButton *pauseButton; }; #endif #include <QtGui> #include "tetrixboard.h" #include "tetrixwindow.h" TetrixWindow::TetrixWindow() {     board = new TetrixBoard;     nextPieceLabel = new QLabel;     nextPieceLabel->setFrameStyle(QFrame::Box | QFrame::Raised);     nextPieceLabel->setAlignment(Qt::AlignCenter);     board->setNextPieceLabel(nextPieceLabel);     scoreLcd = new QLCDNumber(5);     scoreLcd->setSegmentStyle(QLCDNumber::Filled);     levelLcd = new QLCDNumber(2);     levelLcd->setSegmentStyle(QLCDNumber::Filled);     linesLcd = new QLCDNumber(5);     linesLcd->setSegmentStyle(QLCDNumber::Filled);     startButton = new QPushButton(tr("&Start"));     startButton->setFocusPolicy(Qt::NoFocus);     quitButton = new QPushButton(tr("&Quit"));     quitButton->setFocusPolicy(Qt::NoFocus);     pauseButton = new QPushButton(tr("&Pause"));       pauseButton->setFocusPolicy(Qt::NoFocus);       connect(startButton, SIGNAL(clicked()), board, SLOT(start()));       connect(quitButton , SIGNAL(clicked()), qApp, SLOT(quit()));     connect(pauseButton, SIGNAL(clicked()), board, SLOT(pause()));     connect(board, SIGNAL(scoreChanged(int)), scoreLcd, SLOT(display(int)));     connect(board, SIGNAL(levelChanged(int)), levelLcd, SLOT(display(int)));     connect(board, SIGNAL(linesRemovedChanged(int)),             linesLcd, SLOT(display(int)));     QGridLayout *layout = new QGridLayout;     layout->addWidget(createLabel(tr("NEXT")), 0, 0);     layout->addWidget(nextPieceLabel, 1, 0);     layout->addWidget(createLabel(tr("LEVEL")), 2, 0);     layout->addWidget(levelLcd, 3, 0);     layout->addWidget(startButton, 4, 0);     layout->addWidget(board, 0, 1, 6, 1);     layout->addWidget(createLabel(tr("SCORE")), 0, 2);     layout->addWidget(scoreLcd, 1, 2);     layout->addWidget(createLabel(tr("LINES REMOVED")), 2, 2);     layout->addWidget(linesLcd, 3, 2);     layout->addWidget(quitButton, 4, 2);     layout->addWidget(pauseButton, 5, 2);     setLayout(layout);     setWindowTitle(tr("Tetrix"));     resize(550, 370); } QLabel *TetrixWindow::createLabel(const QString &text) {     QLabel *lbl = new QLabel(text);     lbl->setAlignment(Qt::AlignHCenter | Qt::AlignBottom);     return lbl; } #include <QtGui> #include <stdlib.h> #include "tetrixwindow.h" int main(int argc, char *argv[]) {     QApplication app(argc, argv);     TetrixWindow window;     window.show();     qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));     return app.exec(); }