X-Git-Url: http://git.maemo.org/git/?p=impuzzle;a=blobdiff_plain;f=src%2Fgameview.cpp;h=4164b2474b04ada82eda88f1e5ef97174b545a86;hp=f660dc157ea740e08b901bb0fae0453d0c2bc68d;hb=624b98e3fdcba3cbaa1595166205a2367613c07d;hpb=e90ecb7db7b5d4d22fb08f8053db4423797b5afc diff --git a/src/gameview.cpp b/src/gameview.cpp index f660dc1..4164b24 100644 --- a/src/gameview.cpp +++ b/src/gameview.cpp @@ -19,6 +19,9 @@ #include "gameview.h" #include "puzzleitem.h" #include "defines.h" +#include "introitem.h" +#include "imageimporter.h" +#include "settings.h" #include #include @@ -26,6 +29,19 @@ #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef Q_WS_MAEMO_5 +#include +#endif #include @@ -34,11 +50,33 @@ GameView *GameView::instance_ = 0; GameView::GameView(QWidget *parent) : QGraphicsView(parent) { + setBackgroundBrush(Qt::black); + qsrand(QDateTime::currentDateTime().toTime_t()); scene_ = new QGraphicsScene; hiddenIndex_ = -1; setScene(scene_); + introItem_ = new IntroItem; + introItem_->setText("- ImPuzzle -"); + + verticalStep_ = 0; + horizontalStep_ = 0; + qsrand(QDateTime::currentDateTime().toTime_t()); + + if(QFile::exists(QString("%1/%2/%3") + .arg(QDir::homePath()).arg(HOME_DIRECTORY).arg(RESTORE_FILE))) { + if(!restoreGame()) { + setPieces(ImageImporter::instance()->newPieces(Settings::instance()->image(), Settings::instance()->pieceCount())); + PuzzleItem::setMoveCount(0); + } + else { + QTimer::singleShot(0, this, SIGNAL(gameRestored())); + } + } + else { + scene_->addItem(introItem_); + } } GameView *GameView::instance() @@ -55,8 +93,10 @@ QList GameView::pieces() const return pieces_; } -void GameView::setPieces(const QList pieces) +void GameView::setPieces(const QList pieces, bool shuffle) { + PuzzleItem::setManuallyMovable(false); + if(pieces.isEmpty()) { qDebug() << "Empty list @ GameView::setPieces"; return; @@ -74,11 +114,11 @@ void GameView::setPieces(const QList pieces) int horizontalCount = 0; // Find out board size - if(pieces_.count() == 12) { - horizontalCount = 4; + if(pieces_.count() == EASY_PIECE_COUNT) { + horizontalCount = EASY_HORIZONTAL_COUNT; } - else if(pieces_.count() == 20) { - horizontalCount = 5; + else if(pieces_.count() == HARD_PIECE_COUNT) { + horizontalCount = HARD_HORIZONTAL_COUNT; } else { qDebug() << "Invalid piece count @ GameView::setPieces"; @@ -87,8 +127,8 @@ void GameView::setPieces(const QList pieces) } int verticalCount = pieces_.count() / horizontalCount; - int horizontalStep = IMAGE_WIDTH / horizontalCount + 5; - int verticalStep = IMAGE_HEIGHT / verticalCount + 5; + horizontalStep_ = IMAGE_WIDTH / horizontalCount + 5; + verticalStep_ = IMAGE_HEIGHT / verticalCount + 5; int pieceNumber = 0; @@ -96,18 +136,25 @@ void GameView::setPieces(const QList pieces) for(int i = 0; i < verticalCount; ++i) { for(int j = 0; j < horizontalCount; ++j) { scene_->addItem(pieces_.at(pieceNumber)); - QPointF point(j * horizontalStep, i * verticalStep); + QPointF point(j * horizontalStep_, i * verticalStep_); pieces_.at(pieceNumber)->setPos(point); pieces_.at(pieceNumber)->setCorrectPlace(point); pieces_.at(pieceNumber)->setCurrentPlace(point); + pieces_.at(pieceNumber)->setDrawNumber(true); pieceNumber++; } } - // Wait a second - QTimer::singleShot(1000, this, SLOT(shufflePieces())); + // Wait and shuffle if desired + if(shuffle) { + QTimer::singleShot(750, this, SLOT(shufflePieces())); + } + else { + PuzzleItem::setManuallyMovable(true); + } } +//TODO: fixme! void GameView::shufflePieces() { if(pieces_.isEmpty()) { @@ -115,23 +162,134 @@ void GameView::shufflePieces() return; } - // TODO Give pieces ramdom locations - int rounds = 5; - for(int j = 0; j < rounds; ++j) { - for(int i = 0; i < pieces_.count(); ++i) { - QPointF tmp; - int changeIndex = 0; - while(changeIndex == i) { - changeIndex = qrand() % pieces_.count(); + // Give pieces ramdom locations + hiddenIndex_ = qrand() % pieces_.count(); + emptyPlace_ = pieces_.at(hiddenIndex_)->currentPlace(); + + QPointF topLeft = pieces_.at(0)->correctPlace(); + QPointF bottomRight = pieces_.last()->correctPlace(); + + int moveCount = pieces_.count() * 10; + int movesMade = 0; + + PuzzleItem *item = 0; + + for(int i = 0; i < moveCount; ++i) { + int rand = qrand() % 4; + + switch(rand) { + // up + case 0: + if(pieces_.at(hiddenIndex_)->currentPlace().y() > topLeft.y()) { + QPointF tmp = pieces_.at(hiddenIndex_)->currentPlace(); + QGraphicsItem *graphicsItem = scene()->itemAt(tmp + QPointF(0, -verticalStep_)); + if(graphicsItem) { + item = dynamic_cast(graphicsItem); + if(item->movable()) { + emptyPlace_ = item->currentPlace(); + pieces_.at(hiddenIndex_)->setCurrentPlace(item->currentPlace()); + pieces_.at(hiddenIndex_)->setPos(item->currentPlace()); + item->setCurrentPlace(tmp); + item->setPos(tmp); + invalidateScene(); + scene()->update(); + setMovingPieces(); + movesMade++; + } + else { + qDebug() << "Item right of hidden piece not movable"; + } + } + } + else { + --i; + } + break; + // down + case 1: + if(pieces_.at(hiddenIndex_)->currentPlace().y() < bottomRight.y()) { + QPointF tmp = pieces_.at(hiddenIndex_)->currentPlace(); + QGraphicsItem *graphicsItem = scene()->itemAt(tmp + QPointF(0, verticalStep_)); + if(graphicsItem) { + item = dynamic_cast(graphicsItem); + if(item->movable()) { + emptyPlace_ = item->currentPlace(); + pieces_.at(hiddenIndex_)->setCurrentPlace(item->currentPlace()); + pieces_.at(hiddenIndex_)->setPos(item->currentPlace()); + item->setCurrentPlace(tmp); + item->setPos(tmp); + setMovingPieces(); + movesMade++; + } + else { + qDebug() << "Item down of hidden piece not movable"; + } + } + } + else { + --i; + } + break; + // left + case 2: + if(pieces_.at(hiddenIndex_)->currentPlace().x() > topLeft.x()) { + QPointF tmp = pieces_.at(hiddenIndex_)->currentPlace(); + QGraphicsItem *graphicsItem = scene()->itemAt(tmp + QPointF(-horizontalStep_, 0)); + if(graphicsItem) { + item = dynamic_cast(graphicsItem); + if(item->movable()) { + emptyPlace_ = item->currentPlace(); + pieces_.at(hiddenIndex_)->setCurrentPlace(item->currentPlace()); + pieces_.at(hiddenIndex_)->setPos(item->currentPlace()); + item->setCurrentPlace(tmp); + item->setPos(tmp); + setMovingPieces(); + movesMade++; + } + else { + qDebug() << "Item left of hidden piece not movable"; + } + } + } + else { + --i; } - tmp = pieces_.at(changeIndex)->currentPlace(); - pieces_.at(changeIndex)->setCurrentPlace(pieces_.at(i)->currentPlace()); - pieces_.at(i)->setCurrentPlace(tmp); + break; + // right + case 3: + if(pieces_.at(hiddenIndex_)->currentPlace().x() < bottomRight.x()) { + QPointF tmp = pieces_.at(hiddenIndex_)->currentPlace(); + QGraphicsItem *graphicsItem = scene()->itemAt(tmp + QPointF(horizontalStep_, 0)); + if(graphicsItem) { + item = dynamic_cast(graphicsItem); + if(item->movable()) { + emptyPlace_ = item->currentPlace(); + pieces_.at(hiddenIndex_)->setCurrentPlace(item->currentPlace()); + pieces_.at(hiddenIndex_)->setPos(item->currentPlace()); + item->setCurrentPlace(tmp); + item->setPos(tmp); + setMovingPieces(); + movesMade++; + } + else { + qDebug() << "Item up of hidden piece not movable"; + } + } + } + else { + --i; + } + break; + default: + qDebug() << "WTF?"; + break; } } - // TODO Animate transitions to new locations + qDebug() << QString("Shuffle moves: %1/%2").arg(movesMade).arg(moveCount); + QParallelAnimationGroup *animationGroup = new QParallelAnimationGroup(this); + connect(animationGroup, SIGNAL(finished()), this, SLOT(shuffleAnimationFinished())); for(int i = 0; i < pieces_.count(); ++i) { QPropertyAnimation *animation = new QPropertyAnimation(pieces_.at(i), "pos"); animation->setStartValue(pieces_.at(i)->correctPlace()); @@ -141,12 +299,13 @@ void GameView::shufflePieces() animationGroup->addAnimation(animation); } animationGroup->start(); + pieces_.at(hiddenIndex_)->hide(); +} - // Hide random piece - int hiddenPiece = qrand() % pieces_.count(); - emptyPlace_ = pieces_.at(hiddenPiece)->currentPlace(); - pieces_.at(hiddenPiece)->hide(); - hiddenIndex_ = hiddenPiece; +void GameView::shuffleAnimationFinished() +{ + setMovingPieces(); + PuzzleItem::setManuallyMovable(true); } QPointF GameView::emptyPlace() @@ -159,22 +318,298 @@ void GameView::setEmptyPlace(const QPointF &place) emptyPlace_ = place; } -bool GameView::areAllPiecesOk() const +bool GameView::areAllPiecesOk() { for(int i = 0; i < pieces_.count(); ++i) { + // Skip hidden piece if(i == hiddenIndex_) { continue; } + // Id piece is not in it's place else if(pieces_.at(i)->correctPlace() != pieces_.at(i)->currentPlace()) { return false; } } + // Show hidden piece and move it to it's place pieces_.at(hiddenIndex_)->show(); pieces_.at(hiddenIndex_)->moveMeTo(emptyPlace_); + // Set all pieces not movable and hide numbers for(int i = 0; i < pieces_.count(); ++i) { pieces_.at(i)->setMovable(false); + pieces_.at(i)->setDrawNumber(false); } + // Show dialog with move count + QMessageBox::about(const_cast(this), tr("You won"), QString("Puzzle completed with %1 moves").arg(PuzzleItem::moveCount())); + emit gameWon(); + return true; } + +void GameView::setMovingPieces() +{ + if(pieces_.isEmpty()) { + qDebug() << "Empty list @ GameView::setMovingPieces"; + return; + } + + QPointF point = QPointF(); + for(int i = 0; i < pieces_.count(); ++i) { + point = pieces_.at(i)->currentPlace(); + + // Is piece on the left side of the empty space + if(emptyPlace_.y() == point.y() && point.x() + horizontalStep_ == emptyPlace_.x()) { + pieces_.at(i)->setMovable(true); + } + + // Is piece on the right side of the empty space + else if(emptyPlace_.y() == point.y() && point.x() - horizontalStep_ == emptyPlace_.x()) { + pieces_.at(i)->setMovable(true); + } + + // Is piece below the empty space + else if(emptyPlace_.x() == point.x() && point.y() - verticalStep_ == emptyPlace_.y()) { + pieces_.at(i)->setMovable(true); + } + + // Is piece on top of the empty space + else if(emptyPlace_.x() == point.x() && point.y() + verticalStep_ == emptyPlace_.y()) { + pieces_.at(i)->setMovable(true); + } + + // The piece is somewhere else + else { + pieces_.at(i)->setMovable(false); + } + } +} + +bool GameView::restoreGame() +{ + // Read settings from file + QFile file(QString("%1/%2/%3") + .arg(QDir::homePath()) + .arg(HOME_DIRECTORY) + .arg(RESTORE_FILE)); + + if(!file.open(QIODevice::ReadOnly)) { + qDebug() << "Failed to open restore file for reading"; + return false; + } + + QTextStream in(&file); + + QStringList list; + + list = in.readLine().split(";;"); + + qDebug() << "restore list count: " << list.count(); + + if(!list.isEmpty()) { + bool ok = false; + int pieces = list.at(0).toInt(&ok); + if(!ok) { + return false; + } + + QString im = list.at(1); + if(!QFile::exists(im) && im != "default") { + return false; + } + + int moveCount = list.at(2).toInt(&ok); + if(!ok) { + return false; + } + + Settings::instance()->setPieceCount(pieces); + PuzzleItem::setMoveCount(moveCount); + + if(im == "default" || im.isEmpty()) { + Settings::instance()->setImage(0); + Settings::instance()->setImagePath("default"); + } + else { + Settings::instance()->setImagePath(im); + Settings::instance()->setImage(QPixmap(im)); + } + + setPieces(ImageImporter::instance()->newPieces(Settings::instance()->image(), Settings::instance()->pieceCount()), false); + + qDebug() << "pieces_ count after restoring image: " << pieces_.count(); + + if(list.count() >= pieces_.count() + 3) { + for(int j = 0; j < pieces_.count(); ++j) { + if(!list.at(j + 3).isNull()) { + QStringList points = list.at(j + 3).split("#"); + + int x = points.at(0).toInt(&ok); + if(!ok) { + return false; + } + + int y = points.at(1).toInt(&ok); + if(!ok) { + return false; + } + + QPointF point(x, y); + + //qDebug() << "Setting piece " << pieces_.at(j)->pieceNumber(); + //qDebug() << "x: " << point.x() << " y: " << point.y(); + + pieces_.at(j)->setCurrentPlace(point); + } + else { + return false; + } + } + } + else { + file.close(); + file.remove(); + return false; + } + + QStringList hidden = list.last().split("#"); + + if(hidden.count() == 3) { + for(int m = 0; m < pieces_.count(); ++m) { + pieces_.at(m)->setPos(pieces_.at(m)->currentPlace()); + if(pieces_.at(m)->pieceNumber() == hidden.at(2).toInt()) { + //qDebug() << "Hiding piece number " << hidden; + hiddenIndex_ = m; + } + } + + setEmptyPlace(QPointF(hidden.at(0).toInt(), hidden.at(1).toInt())); + + pieces_.at(hiddenIndex_)->setVisible(false); + + setMovingPieces(); + } + else { + setPieces(ImageImporter::instance()->newPieces(Settings::instance()->image(), Settings::instance()->pieceCount())); + file.close(); + file.remove(); + return false; + } + } + else { + qDebug() << "Invalid restore file"; + file.close(); + file.remove(); + return false; + } + + QFileInfo fileInfo(file); + + QDateTime created = fileInfo.created(); + QString infoTxt = QString("Restored game state from %1") + .arg(created.toString(Qt::TextDate)); + +#ifdef Q_WS_MAEMO_5 + QMaemo5InformationBox::information(this, infoTxt); +#endif + + file.close(); + file.remove(); + + return true; +} + +void GameView::saveGame() +{ + if(pieces_.isEmpty() || pieces_.count() < EASY_PIECE_COUNT) { + return; + } + + QDir dir; + if(!dir.exists(QString("%1/%2") + .arg(QDir::homePath()) + .arg(HOME_DIRECTORY))) { + dir.mkpath(QString("%1/%2") + .arg(QDir::homePath()) + .arg(HOME_DIRECTORY)); + } + + QFile file(QString("%1/%2/%3") + .arg(QDir::homePath()) + .arg(HOME_DIRECTORY) + .arg(RESTORE_FILE)); + + if(!file.open(QIODevice::WriteOnly)) { + qDebug() << "Failed to open restore file for writing"; + return; + } + + QTextStream out(&file); + + out << Settings::instance()->pieceCount(); + out << QString(";;"); + if(Settings::instance()->imagePath().isEmpty()) { + out << QString("default"); + } + else { + out << Settings::instance()->imagePath(); + } + out << QString(";;"); + out << PuzzleItem::moveCount(); + out << QString(";;"); + + // piece positions + int number = 0; + int hiddenNo = 0; + + while(number != pieces_.count()) { + for(int i = 0; i < pieces_.count(); ++i) { + if(pieces_.at(i)->pieceNumber() == number + 1) { + out << pieces_.at(i)->currentPlace().x(); + out << QString("#"); + out << pieces_.at(i)->currentPlace().y(); + out << QString(";;"); + pieces_.at(i)->pieceNumber(); + if(!pieces_.at(i)->isVisible()) { + hiddenNo = number + 1; + } + number++; + break; + } + } + } + + out << QString("%1#%2#%3").arg(emptyPlace().x()).arg(emptyPlace().y()).arg(hiddenNo); + + out << "\n"; + + file.close(); + + qApp->quit(); +} + +int GameView::correctPlaces() const +{ + int c = 0; + + for(int i = 0; i < pieces_.count(); ++i) { + if(pieces_.at(i)->currentPlace() == pieces_.at(i)->correctPlace()) { + c++; + } + } + + return c; +} + +QList GameView::movingPlaces() const +{ + QList m; + + for(int i = 0; i < pieces_.count(); ++i) { + if(pieces_.at(i)->movable()) { + m.append(i); + } + } + + return m; +}