f660dc157ea740e08b901bb0fae0453d0c2bc68d
[impuzzle] / src / gameview.cpp
1 /*
2   Image Puzzle - A set your pieces straight game
3   Copyright (C) 2009  Timo Härkönen
4
5   This program is free software: you can redistribute it and/or modify
6   it under the terms of the GNU General Public License as published by
7   the Free Software Foundation, either version 3 of the License, or
8   (at your option) any later version.
9
10   This program is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   GNU General Public License for more details.
14
15   You should have received a copy of the GNU General Public License
16   along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18
19 #include "gameview.h"
20 #include "puzzleitem.h"
21 #include "defines.h"
22
23 #include <QGraphicsScene>
24 #include <QDateTime>
25 #include <QTimer>
26 #include <QPropertyAnimation>
27 #include <QParallelAnimationGroup>
28 #include <QFont>
29
30 #include <QDebug>
31
32 GameView *GameView::instance_ = 0;
33
34 GameView::GameView(QWidget *parent) :
35         QGraphicsView(parent)
36 {
37     scene_ = new QGraphicsScene;
38     hiddenIndex_ = -1;
39     setScene(scene_);
40
41     qsrand(QDateTime::currentDateTime().toTime_t());
42 }
43
44 GameView *GameView::instance()
45 {
46     if(!instance_) {
47         instance_ = new GameView;
48     }
49
50     return instance_;
51 }
52
53 QList<PuzzleItem *> GameView::pieces() const
54 {
55     return pieces_;
56 }
57
58 void GameView::setPieces(const QList<PuzzleItem *> pieces)
59 {
60     if(pieces.isEmpty()) {
61         qDebug() << "Empty list @ GameView::setPieces";
62         return;
63     }
64
65     QList<QGraphicsItem *> previousItems = scene_->items();
66     if(!previousItems.isEmpty()) {
67         foreach(QGraphicsItem *item, previousItems) {
68             scene_->removeItem(item);
69         }
70     }
71
72     pieces_ = pieces;
73
74     int horizontalCount = 0;
75
76     // Find out board size
77     if(pieces_.count() == 12) {
78         horizontalCount = 4;
79     }
80     else if(pieces_.count() == 20) {
81         horizontalCount = 5;
82     }
83     else {
84         qDebug() << "Invalid piece count @ GameView::setPieces";
85         qDebug() << QString("Count was %1").arg(pieces_.count());
86         return;
87     }
88
89     int verticalCount = pieces_.count() / horizontalCount;
90     int horizontalStep = IMAGE_WIDTH / horizontalCount + 5;
91     int verticalStep = IMAGE_HEIGHT / verticalCount + 5;
92
93     int pieceNumber = 0;
94
95     // Set pieces to their correct positions
96     for(int i = 0; i < verticalCount; ++i) {
97         for(int j = 0; j < horizontalCount; ++j) {
98             scene_->addItem(pieces_.at(pieceNumber));
99             QPointF point(j * horizontalStep, i * verticalStep);
100             pieces_.at(pieceNumber)->setPos(point);
101             pieces_.at(pieceNumber)->setCorrectPlace(point);
102             pieces_.at(pieceNumber)->setCurrentPlace(point);
103             pieceNumber++;
104         }
105     }
106
107     // Wait a second
108     QTimer::singleShot(1000, this, SLOT(shufflePieces()));
109 }
110
111 void GameView::shufflePieces()
112 {
113     if(pieces_.isEmpty()) {
114         qDebug() << "Empty list @ GameView::shufflePieces";
115         return;
116     }
117
118     // TODO Give pieces ramdom locations
119     int rounds = 5;
120     for(int j = 0; j < rounds; ++j) {
121         for(int i = 0; i < pieces_.count(); ++i) {
122             QPointF tmp;
123             int changeIndex = 0;
124             while(changeIndex == i) {
125                 changeIndex = qrand() % pieces_.count();
126             }
127             tmp = pieces_.at(changeIndex)->currentPlace();
128             pieces_.at(changeIndex)->setCurrentPlace(pieces_.at(i)->currentPlace());
129             pieces_.at(i)->setCurrentPlace(tmp);
130         }
131     }
132
133     // TODO Animate transitions to new locations
134     QParallelAnimationGroup *animationGroup = new QParallelAnimationGroup(this);
135     for(int i = 0; i < pieces_.count(); ++i) {
136         QPropertyAnimation *animation = new QPropertyAnimation(pieces_.at(i), "pos");
137         animation->setStartValue(pieces_.at(i)->correctPlace());
138         animation->setEndValue(pieces_.at(i)->currentPlace());
139         animation->setDuration(750);
140         animation->setEasingCurve(QEasingCurve::InOutCirc);
141         animationGroup->addAnimation(animation);
142     }
143     animationGroup->start();
144
145     // Hide random piece
146     int hiddenPiece = qrand() % pieces_.count();
147     emptyPlace_ = pieces_.at(hiddenPiece)->currentPlace();
148     pieces_.at(hiddenPiece)->hide();
149     hiddenIndex_ = hiddenPiece;
150 }
151
152 QPointF GameView::emptyPlace()
153 {
154     return emptyPlace_;
155 }
156
157 void GameView::setEmptyPlace(const QPointF &place)
158 {
159     emptyPlace_ = place;
160 }
161
162 bool GameView::areAllPiecesOk() const
163 {
164     for(int i = 0; i < pieces_.count(); ++i) {
165         if(i == hiddenIndex_) {
166             continue;
167         }
168         else if(pieces_.at(i)->correctPlace() != pieces_.at(i)->currentPlace()) {
169             return false;
170         }
171     }
172     pieces_.at(hiddenIndex_)->show();
173     pieces_.at(hiddenIndex_)->moveMeTo(emptyPlace_);
174
175     for(int i = 0; i < pieces_.count(); ++i) {
176         pieces_.at(i)->setMovable(false);
177     }
178
179     return true;
180 }