Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion GameBoard.qml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ import Game 1.0
GridView {
id: root

move: Transition {
NumberAnimation { properties: "x,y"; duration: 1000 }
Comment thread
smay1613 marked this conversation as resolved.
}

cellHeight: height / 4
cellWidth: width / 4

Expand Down Expand Up @@ -31,11 +35,19 @@ GridView {
}
}

function restartGame() {
_gameController.restartGame()
}

signal tileMoved()
signal solved()
GameController_qml{
Comment thread
smay1613 marked this conversation as resolved.
id: _gameController
onTileMoved: root.tileMoved()
onSolved: root.solved()
}

Component.onCompleted: {
root.model = _gameController.getModel();
root.model = _gameController.getModel();
}
}
25 changes: 25 additions & 0 deletions MoveCounterLabel.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import QtQuick 2.0
import Game 1.0
import QtQuick.Controls 2.5

Label {
property string bestScoreStr: _moveCounter.bestScore === -1 ? "-" : _moveCounter.bestScore;
text: qsTr("Moves: %1 | Best: %2").arg(_moveCounter.currentCount).arg(bestScoreStr)

function increment() {
_moveCounter.increment()
}

function updateBestScore() {
_moveCounter.updateBestScore()
}

function resetCurrentCount() {
_moveCounter.resetCurrentCount()
}

MoveCounter_qml {
id: _moveCounter
}

}
27 changes: 27 additions & 0 deletions TimeLabel.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import QtQuick 2.0
import QtQuick.Controls 2.5

Label {
property int seconds: 0
property double startTime: new Date().getTime()

function stopTimer() {
_timer.stop();
}

function reset() {
seconds = 0;
startTime = new Date().getTime();
_timer.start();
}

text: qsTr("Time: %1").arg(Math.ceil(seconds))

Timer {
id: _timer;
interval: 50; running: true; repeat: true
onTriggered: {
seconds = (new Date().getTime() - startTime) / 1000;
}
}
}
60 changes: 54 additions & 6 deletions gameboard.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <numeric>
#include <algorithm>
#include <random>
#include <QDebug>

GameBoard::GameBoard(QObject *parent, size_t board_dimension):
QAbstractListModel {parent},
Expand All @@ -25,6 +26,7 @@ void GameBoard::shuffle()
std::shuffle(m_raw_board.begin(), m_raw_board.end(), g);
}
while (!isBoardValid());
emit dataChanged(index(0, 0), index(m_boardsize - 1, 0));
}

bool GameBoard::isBoardValid() const
Expand Down Expand Up @@ -54,6 +56,22 @@ bool GameBoard::isPositionValid(const size_t position) const
return position < m_boardsize;
}

bool GameBoard::isSolved() const
{
std::vector<Tile> solved_ethalon(m_boardsize);
std::iota(solved_ethalon.begin(), solved_ethalon.end(), 1);
return solved_ethalon == m_raw_board;
}

int GameBoard::hiddenElementIndex() const
{
const auto hiddenElementIterator =
std::find(m_raw_board.begin(), m_raw_board.end(),
m_hiddenElementValue);

return static_cast<int>(std::distance(m_raw_board.begin(), hiddenElementIterator));
}

int GameBoard::rowCount(const QModelIndex &/*parent*/) const
{
return static_cast<int>(m_boardsize);
Expand Down Expand Up @@ -126,17 +144,47 @@ bool GameBoard::move(int index)
}

Position positionOfIndex {getRowCol(index)};
const int oldHiddenIndex = hiddenElementIndex();
Position hiddenElementPosition {getRowCol(oldHiddenIndex)};

if (!is_adjacent(positionOfIndex, hiddenElementPosition)) {
return false;
}

auto hiddenElementIterator = std::find(m_raw_board.begin(), m_raw_board.end(), m_hiddenElementValue);
moveRow(QModelIndex(), index, QModelIndex(), index > oldHiddenIndex ? oldHiddenIndex : oldHiddenIndex + 1);

Q_ASSERT(hiddenElementIterator != m_raw_board.end());
Position hiddenElementPosition {getRowCol(std::distance(m_raw_board.begin(), hiddenElementIterator))};
const int newHiddenIndex = hiddenElementIndex();
if (newHiddenIndex != index) {
moveRow(QModelIndex(), newHiddenIndex, QModelIndex(), newHiddenIndex > index ? index : index + 1);
}
emit tileMoved();
if (isSolved()) {
emit solved();
}
return true;
}

if (!is_adjacent(positionOfIndex, hiddenElementPosition)) {
bool GameBoard::moveRows(const QModelIndex &sourceParent, int sourceRow, int count, const QModelIndex &destinationParent, int destinationChild)
{
const int sourceEndRow = sourceRow + count;
const bool nice_input = (sourceEndRow > 0) &&
(sourceEndRow <= static_cast<int>(m_boardsize)) &&
!(sourceRow <= destinationChild && destinationChild < sourceEndRow);
if (!nice_input) {
qWarning().nospace()
<< "GameBoard::moveRows. Bad input got: sourceRow = " << sourceRow
<< ", count = " << count << ", destinationChild = " << destinationChild;
return false;
}

std::swap(hiddenElementIterator->value, m_raw_board[index].value);
emit dataChanged(createIndex(0, 0), createIndex(m_boardsize, 0));
beginMoveRows(sourceParent, sourceRow, sourceEndRow - 1, destinationParent, destinationChild);
const std::vector<Tile> movingRowsCopy = {m_raw_board.cbegin() + sourceRow,
m_raw_board.cbegin() + sourceEndRow};
m_raw_board.erase(m_raw_board.cbegin() + sourceRow,
m_raw_board.cbegin() + sourceEndRow);
m_raw_board.insert(m_raw_board.cbegin() + destinationChild - (destinationChild > sourceRow ? count : 0),
movingRowsCopy.begin(), movingRowsCopy.end());

endMoveRows();
return true;
}
16 changes: 14 additions & 2 deletions gameboard.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#pragma once
#pragma once

#include <vector>
#include <QAbstractListModel>
Expand All @@ -18,9 +18,12 @@ class GameBoard : public QAbstractListModel
value = new_value;
return *this;
}
bool operator==(const size_t other) {
bool operator==(size_t other) const {
return other == value;
}
bool operator==(const Tile &other) const {
return other.value == value;
}
};

void shuffle();
Expand All @@ -31,9 +34,15 @@ class GameBoard : public QAbstractListModel
size_t hiddenElementValue() const;

Q_INVOKABLE bool move (int index);
bool moveRows(const QModelIndex &sourceParent, int sourceRow, int count,
const QModelIndex &destinationParent, int destinationChild) override;

using Position = std::pair<size_t, size_t>;

signals:
void tileMoved();
void solved();

private:
std::vector<Tile> m_raw_board;
const size_t m_dimension;
Expand All @@ -43,6 +52,9 @@ class GameBoard : public QAbstractListModel

bool isBoardValid() const;
bool isPositionValid(const size_t position) const;
bool isSolved() const;

int hiddenElementIndex() const;

Position getRowCol(size_t index) const;

Expand Down
7 changes: 7 additions & 0 deletions gamecontroller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,16 @@

GameController::GameController(QObject *parent) : QObject(parent)
{
connect(&gameBoard, &GameBoard::tileMoved, this, &GameController::tileMoved);
connect(&gameBoard, &GameBoard::solved, this, &GameController::solved);
}

GameBoard* GameController::getModel()
{
return &gameBoard;
}

void GameController::restartGame()
{
gameBoard.shuffle();
}
5 changes: 5 additions & 0 deletions gamecontroller.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ class GameController : public QObject
explicit GameController(QObject *parent = nullptr);

Q_INVOKABLE GameBoard* getModel();
Q_INVOKABLE void restartGame();

signals:
void tileMoved();
void solved();

private:
GameBoard gameBoard;
Expand Down
8 changes: 5 additions & 3 deletions lesson4.pro
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
QT += quick
CONFIG += c++11
CONFIG += c++11 sanitizer sanitize_address sanitize_leak sanitize_undefined

# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings
Expand All @@ -15,7 +15,8 @@ DEFINES += QT_DEPRECATED_WARNINGS
SOURCES += \
gameboard.cpp \
gamecontroller.cpp \
main.cpp
main.cpp \
movecounter.cpp

RESOURCES += qml.qrc

Expand All @@ -32,4 +33,5 @@ else: unix:!android: target.path = /opt/$${TARGET}/bin

HEADERS += \
gameboard.h \
gamecontroller.h
gamecontroller.h \
movecounter.h
2 changes: 2 additions & 0 deletions main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include <QQmlApplicationEngine>
#include "gameboard.h"
#include "gamecontroller.h"
#include "movecounter.h"

int main(int argc, char *argv[])
{
Expand All @@ -11,6 +12,7 @@ int main(int argc, char *argv[])

qmlRegisterType<GameBoard> ("Game", 1, 0, "GameBoard_qml" );
qmlRegisterType<GameController>("Game", 1, 0, "GameController_qml");
qmlRegisterType<MoveCounter>("Game", 1, 0, "MoveCounter_qml");

QQmlApplicationEngine engine;
const QUrl url(QStringLiteral("qrc:/main.qml"));
Expand Down
55 changes: 55 additions & 0 deletions main.qml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import QtQuick 2.11
import QtQuick.Window 2.11
import QtQuick.Dialogs 1.2

Window {
id: root
Expand All @@ -12,5 +13,59 @@ Window {
id: _gameBoard
anchors.fill: parent
anchors.margins: 5
anchors.bottomMargin: parent.height - _timeLabel.y
onTileMoved: _moveCounterLabel.increment()
onSolved: {
_moveCounterLabel.updateBestScore();
_timeLabel.stopTimer();
_solvedDialog.open();
}
}

TimeLabel {
id: _timeLabel
anchors {
left: parent.left
bottom: parent.bottom
margins: 5
leftMargin: 10
}
font {
pointSize: parent.height / 4 * 0.15
bold: true
}
}

MoveCounterLabel {
id: _moveCounterLabel
anchors {
right: parent.right
bottom: parent.bottom
margins: 5
rightMargin: 10
}

font {
pointSize: parent.height / 4 * 0.15
bold: true
}
}

function startNewGame() {
_gameBoard.restartGame();
_moveCounterLabel.resetCurrentCount();
_timeLabel.reset();
}

MessageDialog {
id: _solvedDialog
title: qsTr("Solved!")
text: qsTr("Would u like to restart the game?")
standardButtons: StandardButton.Yes | StandardButton.No
icon: StandardIcon.Question
onYes: startNewGame()
onNo: Qt.quit()
// onRejected почему-то не отрабатывает при закрытии диалога
Comment thread
smay1613 marked this conversation as resolved.
}

}
Loading