diff --git a/Tetris_task.pro b/Tetris_task.pro
new file mode 100644
index 0000000..ade1f6b
--- /dev/null
+++ b/Tetris_task.pro
@@ -0,0 +1,30 @@
+QT += core gui
+QT += multimedia
+greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
+
+CONFIG += c++11
+
+# You can make your code fail to compile if it uses deprecated APIs.
+# In order to do so, uncomment the following line.
+#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
+
+SOURCES += \
+ main.cpp \
+ tetrixboard.cpp \
+ tetrixpiece.cpp \
+ tetrixwindow.cpp
+
+HEADERS += \
+ tetrixboard.h \
+ tetrixpiece.h \
+ tetrixwindow.h
+
+FORMS +=
+
+# Default rules for deployment.
+qnx: target.path = /tmp/$${TARGET}/bin
+else: unix:!android: target.path = /opt/$${TARGET}/bin
+!isEmpty(target.path): INSTALLS += target
+
+DISTFILES += \
+ Video_Game_Players_-_Tetris_Theme_48152782.mp3
diff --git a/Tetris_task.pro.user b/Tetris_task.pro.user
new file mode 100644
index 0000000..6356787
--- /dev/null
+++ b/Tetris_task.pro.user
@@ -0,0 +1,425 @@
+
+
+
+
+
+ EnvironmentId
+ {4f500388-fdcc-4898-ad1a-0bc7990e4420}
+
+
+ ProjectExplorer.Project.ActiveTarget
+ 0
+
+
+ ProjectExplorer.Project.EditorSettings
+
+ true
+ false
+ true
+
+ Cpp
+
+ CppGlobal
+
+
+
+ QmlJS
+
+ QmlJSGlobal
+
+
+ 2
+ UTF-8
+ false
+ 4
+ false
+ 80
+ true
+ true
+ 1
+ false
+ true
+ false
+ 0
+ true
+ true
+ 0
+ 8
+ true
+ false
+ 1
+ true
+ true
+ true
+ *.md, *.MD, Makefile
+ false
+ true
+
+
+
+ ProjectExplorer.Project.PluginSettings
+
+
+ true
+ false
+ true
+ true
+ true
+ true
+
+
+ 0
+ true
+
+ -fno-delayed-template-parsing
+
+ true
+ Builtin.BuildSystem
+
+ true
+ true
+ Builtin.DefaultTidyAndClazy
+ 6
+
+
+
+ true
+
+
+
+
+ ProjectExplorer.Project.Target.0
+
+ Desktop
+ Desktop Qt 5.12.12 MinGW 64-bit
+ Desktop Qt 5.12.12 MinGW 64-bit
+ qt.qt5.51212.win64_mingw73_kit
+ 0
+ 0
+ 0
+
+ 0
+ C:\Users\mefby\OneDrive\Документы\7_семестр\Плюсы и QT\build-Tetris_task-Desktop_Qt_5_12_12_MinGW_64_bit-Debug
+ C:/Users/mefby/OneDrive/Документы/7_семестр/Плюсы и QT/build-Tetris_task-Desktop_Qt_5_12_12_MinGW_64_bit-Debug
+
+
+ true
+ QtProjectManager.QMakeBuildStep
+ false
+
+
+
+ true
+ Qt4ProjectManager.MakeStep
+
+ 2
+ Сборка
+ Сборка
+ ProjectExplorer.BuildSteps.Build
+
+
+
+ true
+ Qt4ProjectManager.MakeStep
+ clean
+
+ 1
+ Очистка
+ Очистка
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+
+ Отладка
+ Qt4ProjectManager.Qt4BuildConfiguration
+ 2
+
+
+ C:\Users\mefby\OneDrive\Документы\7_семестр\Плюсы и QT\build-Tetris_task-Desktop_Qt_5_12_12_MinGW_64_bit-Release
+ C:/Users/mefby/OneDrive/Документы/7_семестр/Плюсы и QT/build-Tetris_task-Desktop_Qt_5_12_12_MinGW_64_bit-Release
+
+
+ true
+ QtProjectManager.QMakeBuildStep
+ false
+
+
+
+ true
+ Qt4ProjectManager.MakeStep
+
+ 2
+ Сборка
+ Сборка
+ ProjectExplorer.BuildSteps.Build
+
+
+
+ true
+ Qt4ProjectManager.MakeStep
+ clean
+
+ 1
+ Очистка
+ Очистка
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+
+ Выпуск
+ Qt4ProjectManager.Qt4BuildConfiguration
+ 0
+ 0
+
+
+ 0
+ C:\Users\mefby\OneDrive\Документы\7_семестр\Плюсы и QT\build-Tetris_task-Desktop_Qt_5_12_12_MinGW_64_bit-Profile
+ C:/Users/mefby/OneDrive/Документы/7_семестр/Плюсы и QT/build-Tetris_task-Desktop_Qt_5_12_12_MinGW_64_bit-Profile
+
+
+ true
+ QtProjectManager.QMakeBuildStep
+ false
+
+
+
+ true
+ Qt4ProjectManager.MakeStep
+
+ 2
+ Сборка
+ Сборка
+ ProjectExplorer.BuildSteps.Build
+
+
+
+ true
+ Qt4ProjectManager.MakeStep
+ clean
+
+ 1
+ Очистка
+ Очистка
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+
+ Профилирование
+ Qt4ProjectManager.Qt4BuildConfiguration
+ 0
+ 0
+ 0
+
+ 3
+
+
+ 0
+ Развёртывание
+ Развёртывание
+ ProjectExplorer.BuildSteps.Deploy
+
+ 1
+
+ false
+ ProjectExplorer.DefaultDeployConfiguration
+
+ 1
+
+ true
+ true
+ true
+
+ 2
+
+ Qt4ProjectManager.Qt4RunConfiguration:C:/qt_projects/Tetris_task/Tetris_task.pro
+ C:/qt_projects/Tetris_task/Tetris_task.pro
+ false
+ true
+ true
+ false
+ true
+ C:/Users/mefby/OneDrive/Документы/7_семестр/Плюсы и QT/build-Tetris_task-Desktop_Qt_5_12_12_MinGW_64_bit-Debug
+
+ 1
+
+
+
+ ProjectExplorer.Project.Target.1
+
+ Desktop
+ Desktop Qt 5.12.12 MinGW 32-bit
+ Desktop Qt 5.12.12 MinGW 32-bit
+ qt.qt5.51212.win32_mingw73_kit
+ 0
+ 0
+ 0
+
+ 0
+ C:\Users\mefby\OneDrive\Документы\7_семестр\Плюсы и QT\build-Tetris_task-Desktop_Qt_5_12_12_MinGW_32_bit-Debug
+ C:/Users/mefby/OneDrive/Документы/7_семестр/Плюсы и QT/build-Tetris_task-Desktop_Qt_5_12_12_MinGW_32_bit-Debug
+
+
+ true
+ QtProjectManager.QMakeBuildStep
+ false
+
+
+
+ true
+ Qt4ProjectManager.MakeStep
+
+ 2
+ Сборка
+ Сборка
+ ProjectExplorer.BuildSteps.Build
+
+
+
+ true
+ Qt4ProjectManager.MakeStep
+ clean
+
+ 1
+ Очистка
+ Очистка
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+
+ Отладка
+ Qt4ProjectManager.Qt4BuildConfiguration
+ 2
+
+
+ C:\Users\mefby\OneDrive\Документы\7_семестр\Плюсы и QT\build-Tetris_task-Desktop_Qt_5_12_12_MinGW_32_bit-Release
+ C:/Users/mefby/OneDrive/Документы/7_семестр/Плюсы и QT/build-Tetris_task-Desktop_Qt_5_12_12_MinGW_32_bit-Release
+
+
+ true
+ QtProjectManager.QMakeBuildStep
+ false
+
+
+
+ true
+ Qt4ProjectManager.MakeStep
+
+ 2
+ Сборка
+ Сборка
+ ProjectExplorer.BuildSteps.Build
+
+
+
+ true
+ Qt4ProjectManager.MakeStep
+ clean
+
+ 1
+ Очистка
+ Очистка
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+
+ Выпуск
+ Qt4ProjectManager.Qt4BuildConfiguration
+ 0
+ 0
+
+
+ 0
+ C:\Users\mefby\OneDrive\Документы\7_семестр\Плюсы и QT\build-Tetris_task-Desktop_Qt_5_12_12_MinGW_32_bit-Profile
+ C:/Users/mefby/OneDrive/Документы/7_семестр/Плюсы и QT/build-Tetris_task-Desktop_Qt_5_12_12_MinGW_32_bit-Profile
+
+
+ true
+ QtProjectManager.QMakeBuildStep
+ false
+
+
+
+ true
+ Qt4ProjectManager.MakeStep
+
+ 2
+ Сборка
+ Сборка
+ ProjectExplorer.BuildSteps.Build
+
+
+
+ true
+ Qt4ProjectManager.MakeStep
+ clean
+
+ 1
+ Очистка
+ Очистка
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+
+ Профилирование
+ Qt4ProjectManager.Qt4BuildConfiguration
+ 0
+ 0
+ 0
+
+ 3
+
+
+ 0
+ Развёртывание
+ Развёртывание
+ ProjectExplorer.BuildSteps.Deploy
+
+ 1
+
+ false
+ ProjectExplorer.DefaultDeployConfiguration
+
+ 1
+
+ true
+ true
+ true
+
+ 2
+
+ Qt4ProjectManager.Qt4RunConfiguration:C:/qt_projects/Tetris_task/Tetris_task.pro
+ C:/qt_projects/Tetris_task/Tetris_task.pro
+ false
+ true
+ true
+ false
+ true
+
+ 1
+
+
+
+ ProjectExplorer.Project.TargetCount
+ 2
+
+
+ ProjectExplorer.Project.Updater.FileVersion
+ 22
+
+
+ Version
+ 22
+
+
diff --git a/Video_Game_Players_-_Tetris_Theme_48152782.mp3 b/Video_Game_Players_-_Tetris_Theme_48152782.mp3
new file mode 100644
index 0000000..225519d
Binary files /dev/null and b/Video_Game_Players_-_Tetris_Theme_48152782.mp3 differ
diff --git a/main.cpp b/main.cpp
index f1c8bd9..838d55b 100644
--- a/main.cpp
+++ b/main.cpp
@@ -1,10 +1,22 @@
-#include
-
-#include "tetris.h"
-
-int main(int argc, char *argv[]) {
- QApplication a(argc, argv);
- Tetris w;
- w.show();
- return a.exec();
-}
+#include "tetrixwindow.h"
+
+#include
+#include
+#include
+#include
+#include
+
+int main(int argc, char *argv[])
+{
+ QApplication app(argc, argv);
+ TetrixWindow window;
+ window.show();
+ QMediaPlaylist *playlist = new QMediaPlaylist();
+ playlist->addMedia(QUrl("qrc:/tetris_music/background.wav"));
+ playlist->setPlaybackMode(QMediaPlaylist::Loop);
+ QMediaPlayer *player = new QMediaPlayer;
+ player->setMedia(playlist);
+ player->setVolume(10);
+ player->play();
+ return app.exec();
+}
diff --git a/tetrisform.cpp b/tetrisform.cpp
new file mode 100644
index 0000000..9156998
--- /dev/null
+++ b/tetrisform.cpp
@@ -0,0 +1,14 @@
+#include "tetrisform.h"
+#include "ui_tetrisform.h"
+
+tetrisForm::tetrisForm(QWidget *parent) :
+ QWidget(parent),
+ ui(new Ui::tetrisForm)
+{
+ ui->setupUi(this);
+}
+
+tetrisForm::~tetrisForm()
+{
+ delete ui;
+}
diff --git a/tetrismainwindow.cpp b/tetrismainwindow.cpp
new file mode 100644
index 0000000..9e4f7d9
--- /dev/null
+++ b/tetrismainwindow.cpp
@@ -0,0 +1,15 @@
+#include "tetrismainwindow.h"
+#include "ui_tetrismainwindow.h"
+
+TetrisMainWindow::TetrisMainWindow(QWidget *parent)
+ : QWidget(parent)
+ , ui(new Ui::TetrisMainWindow)
+{
+ ui->setupUi(this);
+}
+
+TetrisMainWindow::~TetrisMainWindow()
+{
+ delete ui;
+}
+
diff --git a/tetrismainwindow.h b/tetrismainwindow.h
new file mode 100644
index 0000000..84c4696
--- /dev/null
+++ b/tetrismainwindow.h
@@ -0,0 +1,31 @@
+#ifndef TETRISMAINWINDOW_H
+#define TETRISMAINWINDOW_H
+
+#include
+
+QT_BEGIN_NAMESPACE
+namespace Ui { class TetrisMainWindow; }
+QT_END_NAMESPACE
+
+class TetrisMainWindow : public QWidget
+{
+ Q_OBJECT
+
+public:
+ TetrisMainWindow(QWidget *parent = nullptr);
+ ~TetrisMainWindow();
+
+private:
+ Ui::TetrisMainWindow *ui;
+ QLabel *createLabel(const QString &text);
+
+ TetrisBoard *board;
+ QLabel *nextPieceLabel;
+ QLCDNumber *scoreLcd;
+ QLCDNumber *levelLcd;
+ QLCDNumber *linesLcd;
+ QPushButton *startButton;
+ QPushButton *quitButton;
+ QPushButton *pauseButton;
+};
+#endif // TETRISMAINWINDOW_H
diff --git a/tetrismainwindow.ui b/tetrismainwindow.ui
new file mode 100644
index 0000000..8127c88
--- /dev/null
+++ b/tetrismainwindow.ui
@@ -0,0 +1,19 @@
+
+
+ TetrisMainWindow
+
+
+
+ 0
+ 0
+ 800
+ 600
+
+
+
+ TetrisMainWindow
+
+
+
+
+
diff --git a/tetrixboard.cpp b/tetrixboard.cpp
new file mode 100644
index 0000000..1ef4abf
--- /dev/null
+++ b/tetrixboard.cpp
@@ -0,0 +1,283 @@
+#include "tetrixboard.h"
+
+#include
+#include
+#include
+#include
+
+TetrixBoard::TetrixBoard(QWidget *parent)
+ : QFrame(parent), isStarted(false)
+{
+ setFrameStyle(QFrame::Panel | QFrame::Sunken);
+ setFocusPolicy(Qt::StrongFocus);
+ 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()
+{
+
+ isStarted = true;
+ isWaitingAfterLine = false;
+ numLinesRemoved = 0;
+ numPiecesDropped = 0;
+ score = 0;
+ clearBoard();
+
+ emit linesRemovedChanged(numLinesRemoved);
+ emit scoreChanged(score);
+
+ newPiece();
+ timer.start(timeoutTime(), this);
+}
+
+void TetrixBoard::paintEvent(QPaintEvent *event)
+{
+ QFrame::paintEvent(event);
+
+ QPainter painter(this);
+ QRect rect = contentsRect();
+
+ 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 || 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_Up:
+ tryMove(curPiece.rotatedLeft(), curX, curY);
+ break;
+ case Qt::Key_Space:
+ dropDown();
+ break;
+ case Qt::Key_Down:
+ 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;
+
+ 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().window());
+
+ 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 constexpr QRgb colorTable[8] = {
+ 0xFF3300, 0xCC6666, 0x66CC66, 0x6666CC,
+ 0xCCCC66, 0x33FFFF, 0x66CCCC, 0xFF9900
+ };
+
+ QColor color = colorTable[int(shape)];
+ painter.fillRect(x + 1, y + 1, squareWidth() - 2, squareHeight() - 2,
+ color);
+
+ painter.setPen(color.lighter());
+ painter.drawLine(x, y + squareHeight() - 1, x, y);
+ painter.drawLine(x, y, x + squareWidth() - 1, y);
+
+ painter.setPen(color.darker());
+ 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);
+}
diff --git a/tetrixboard.h b/tetrixboard.h
new file mode 100644
index 0000000..b237c91
--- /dev/null
+++ b/tetrixboard.h
@@ -0,0 +1,69 @@
+#ifndef TETRIXBOARD_H
+#define TETRIXBOARD_H
+
+#include
+#include
+#include
+
+#include "tetrixpiece.h"
+
+QT_BEGIN_NAMESPACE
+class QLabel;
+QT_END_NAMESPACE
+
+class TetrixBoard : public QFrame
+{
+ Q_OBJECT
+
+public:
+ TetrixBoard(QWidget *parent = nullptr);
+
+ void setNextPieceLabel(QLabel *label);
+ QSize sizeHint() const override;
+ QSize minimumSizeHint() const override;
+
+public slots:
+ void start();
+ void pause();
+
+signals:
+ void scoreChanged(int score);
+ void linesRemovedChanged(int numLines);
+
+protected:
+ void paintEvent(QPaintEvent *event) override;
+ void keyPressEvent(QKeyEvent *event) override;
+ void timerEvent(QTimerEvent *event) override;
+
+private:
+ enum { BoardWidth = 12, BoardHeight = 24 };
+
+ TetrixShape &shapeAt(int x, int y) { return board[(y * BoardWidth) + x]; }
+ int timeoutTime() { return 1000; }
+ 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 nextPieceLabel;
+ bool isStarted;
+ bool isWaitingAfterLine;
+ TetrixPiece curPiece;
+ TetrixPiece nextPiece;
+ int curX;
+ int curY;
+ int numLinesRemoved;
+ int numPiecesDropped;
+ int score;
+ TetrixShape board[BoardWidth * BoardHeight];
+};
+
+#endif
diff --git a/tetrixpiece.cpp b/tetrixpiece.cpp
new file mode 100644
index 0000000..eab5cf7
--- /dev/null
+++ b/tetrixpiece.cpp
@@ -0,0 +1,77 @@
+#include "tetrixpiece.h"
+
+#include
+
+void TetrixPiece::setRandomShape()
+{
+ setShape(TetrixShape(QRandomGenerator::global()->bounded(7) + 1));
+}
+
+void TetrixPiece::setShape(TetrixShape shape)
+{
+ static constexpr 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;
+}
+
diff --git a/tetrixpiece.h b/tetrixpiece.h
new file mode 100644
index 0000000..89fe166
--- /dev/null
+++ b/tetrixpiece.h
@@ -0,0 +1,33 @@
+#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
diff --git a/tetrixwindow.cpp b/tetrixwindow.cpp
new file mode 100644
index 0000000..721970e
--- /dev/null
+++ b/tetrixwindow.cpp
@@ -0,0 +1,61 @@
+#include "tetrixboard.h"
+#include "tetrixwindow.h"
+
+#include
+#include
+#include
+#include
+#include
+
+
+TetrixWindow::TetrixWindow(QWidget *parent)
+ : QWidget(parent), 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);
+
+ linesLcd = new QLCDNumber(5);
+ linesLcd->setSegmentStyle(QLCDNumber::Filled);
+
+ startButton = new QPushButton(tr("&Новая игра"));
+ startButton->setFocusPolicy(Qt::NoFocus);
+ quitButton = new QPushButton(tr("&Выход"));
+ quitButton->setFocusPolicy(Qt::NoFocus);
+
+ connect(startButton, &QPushButton::clicked, board, &TetrixBoard::start);
+ connect(quitButton , &QPushButton::clicked, qApp, &QCoreApplication::quit);
+ connect(board, &TetrixBoard::scoreChanged,
+ scoreLcd, QOverload::of(&QLCDNumber::display));
+ connect(board, &TetrixBoard::linesRemovedChanged,
+ linesLcd, QOverload::of(&QLCDNumber::display));
+
+ QGridLayout *layout = new QGridLayout;
+ layout->addWidget(createLabel(tr("Следующая фигура")), 0, 0);
+ layout->addWidget(nextPieceLabel, 1, 0);
+ layout->addWidget(startButton, 4, 0);
+ layout->addWidget(board, 0, 1, 6, 1);
+ layout->addWidget(createLabel(tr("Счёт")), 0, 2);
+ layout->addWidget(scoreLcd, 1, 2);
+ layout->addWidget(createLabel(tr("Линий собрано")), 2, 2);
+ layout->addWidget(linesLcd, 3, 2);
+ layout->addWidget(quitButton, 4, 2);
+ setLayout(layout);
+
+ setWindowTitle(tr("Тетрис"));
+ resize(550, 370);
+}
+
+QLabel *TetrixWindow::createLabel(const QString &text)
+{
+ QLabel *label = new QLabel(text);
+ label->setAlignment(Qt::AlignHCenter | Qt::AlignBottom);
+ return label;
+}
+
+
diff --git a/tetrixwindow.h b/tetrixwindow.h
new file mode 100644
index 0000000..53f367d
--- /dev/null
+++ b/tetrixwindow.h
@@ -0,0 +1,31 @@
+#ifndef TETRIXWINDOW_H
+#define TETRIXWINDOW_H
+
+#include
+
+QT_BEGIN_NAMESPACE
+class QLCDNumber;
+class QLabel;
+class QPushButton;
+QT_END_NAMESPACE
+class TetrixBoard;
+
+class TetrixWindow : public QWidget
+{
+ Q_OBJECT
+
+public:
+ TetrixWindow(QWidget *parent = nullptr);
+
+private:
+ QLabel *createLabel(const QString &text);
+
+ TetrixBoard *board;
+ QLabel *nextPieceLabel;
+ QLCDNumber *scoreLcd;
+ QLCDNumber *linesLcd;
+ QPushButton *startButton;
+ QPushButton *quitButton;
+};
+
+#endif