Dependency fix
[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 #include "introitem.h"
23
24 #include <QGraphicsScene>
25 #include <QDateTime>
26 #include <QTimer>
27 #include <QPropertyAnimation>
28 #include <QParallelAnimationGroup>
29 #include <QFont>
30 #include <QMessageBox>
31
32 #include <QDebug>
33
34 GameView *GameView::instance_ = 0;
35
36 GameView::GameView(QWidget *parent) :
37         QGraphicsView(parent)
38 {
39     scene_ = new QGraphicsScene;
40     hiddenIndex_ = -1;
41     setScene(scene_);
42
43     introItem_ = new IntroItem;
44     introItem_->setText("Select new game from menu to play");
45     scene_->addItem(introItem_);
46
47     verticalStep_ = 0;
48     horizontalStep_ = 0;
49
50     qsrand(QDateTime::currentDateTime().toTime_t());
51 }
52
53 GameView *GameView::instance()
54 {
55     if(!instance_) {
56         instance_ = new GameView;
57     }
58
59     return instance_;
60 }
61
62 QList<PuzzleItem *> GameView::pieces() const
63 {
64     return pieces_;
65 }
66
67 void GameView::setPieces(const QList<PuzzleItem *> pieces)
68 {
69     if(pieces.isEmpty()) {
70         qDebug() << "Empty list @ GameView::setPieces";
71         return;
72     }
73
74     QList<QGraphicsItem *> previousItems = scene_->items();
75     if(!previousItems.isEmpty()) {
76         foreach(QGraphicsItem *item, previousItems) {
77             scene_->removeItem(item);
78         }
79     }
80
81     pieces_ = pieces;
82
83     int horizontalCount = 0;
84
85     // Find out board size
86     if(pieces_.count() == 12) {
87         horizontalCount = 4;
88     }
89     else if(pieces_.count() == 20) {
90         horizontalCount = 5;
91     }
92     else {
93         qDebug() << "Invalid piece count @ GameView::setPieces";
94         qDebug() << QString("Count was %1").arg(pieces_.count());
95         return;
96     }
97
98     int verticalCount = pieces_.count() / horizontalCount;
99     horizontalStep_ = IMAGE_WIDTH / horizontalCount + 5;
100     verticalStep_ = IMAGE_HEIGHT / verticalCount + 5;
101
102     int pieceNumber = 0;
103
104     // Set pieces to their correct positions
105     for(int i = 0; i < verticalCount; ++i) {
106         for(int j = 0; j < horizontalCount; ++j) {
107             scene_->addItem(pieces_.at(pieceNumber));
108             QPointF point(j * horizontalStep_, i * verticalStep_);
109             pieces_.at(pieceNumber)->setPos(point);
110             pieces_.at(pieceNumber)->setCorrectPlace(point);
111             pieces_.at(pieceNumber)->setCurrentPlace(point);
112             pieceNumber++;
113         }
114     }
115
116     // Wait a second
117     QTimer::singleShot(750, this, SLOT(shufflePieces()));
118 }
119
120 void GameView::shufflePieces()
121 {
122     if(pieces_.isEmpty()) {
123         qDebug() << "Empty list @ GameView::shufflePieces";
124         return;
125     }
126
127     // Give pieces ramdom locations
128     int rounds = 5; //TODO
129     for(int j = 0; j < rounds; ++j) {
130         for(int i = 0; i < pieces_.count(); ++i) {
131             QPointF tmp;
132             int changeIndex = 0;
133             while(changeIndex == i) {
134                 changeIndex = qrand() % pieces_.count();
135             }
136             tmp = pieces_.at(changeIndex)->currentPlace();
137             pieces_.at(changeIndex)->setCurrentPlace(pieces_.at(i)->currentPlace());
138             pieces_.at(i)->setCurrentPlace(tmp);
139         }
140     }
141
142     // TODO Animate transitions to new locations
143     QParallelAnimationGroup *animationGroup = new QParallelAnimationGroup(this);
144     for(int i = 0; i < pieces_.count(); ++i) {
145         QPropertyAnimation *animation = new QPropertyAnimation(pieces_.at(i), "pos");
146         animation->setStartValue(pieces_.at(i)->correctPlace());
147         animation->setEndValue(pieces_.at(i)->currentPlace());
148         animation->setDuration(750);
149         animation->setEasingCurve(QEasingCurve::InOutCirc);
150         animationGroup->addAnimation(animation);
151     }
152     animationGroup->start();
153
154     // Hide random piece
155     int hiddenPiece = qrand() % pieces_.count();
156     emptyPlace_ = pieces_.at(hiddenPiece)->currentPlace();
157     pieces_.at(hiddenPiece)->hide();
158     hiddenIndex_ = hiddenPiece;
159 }
160
161 QPointF GameView::emptyPlace()
162 {
163     return emptyPlace_;
164 }
165
166 void GameView::setEmptyPlace(const QPointF &place)
167 {
168     emptyPlace_ = place;
169 }
170
171 bool GameView::areAllPiecesOk() const
172 {
173     for(int i = 0; i < pieces_.count(); ++i) {
174         // Skip hidden piece
175         if(i == hiddenIndex_) {
176             continue;
177         }
178         // Id piece is not in it's place
179         else if(pieces_.at(i)->correctPlace() != pieces_.at(i)->currentPlace()) {
180             return false;
181         }
182     }
183     // Show hidden piece and move it to it's place
184     pieces_.at(hiddenIndex_)->show();
185     pieces_.at(hiddenIndex_)->moveMeTo(emptyPlace_);
186
187     // Set all pieces not movable
188     for(int i = 0; i < pieces_.count(); ++i) {
189         pieces_.at(i)->setMovable(false);
190     }
191
192     // Show dialog with move count
193     QMessageBox::about(const_cast<GameView *>(this), tr("You won"), QString("Puzzle completed with %1 moves").arg(PuzzleItem::moveCount()));
194
195     return true;
196 }
197
198 void GameView::setMovingPieces()
199 {
200     if(pieces_.isEmpty()) {
201         qDebug() << "Empty list @ GameView::setMovingPieces";
202         return;
203     }
204
205     QPointF point = QPointF();
206     for(int i = 0; i < pieces_.count(); ++i) {
207         point = pieces_.at(i)->currentPlace();
208
209         // Is piece on the left side of the empty space
210         if(emptyPlace_.y() == point.y() && point.x() + horizontalStep_ == emptyPlace_.x()) {
211             pieces_.at(i)->setMovable(true);
212         }
213
214         // Is piece on the right side of the empty space
215         else if(emptyPlace_.y() == point.y() && point.x() - horizontalStep_ == emptyPlace_.x()) {
216             pieces_.at(i)->setMovable(true);
217         }
218
219         // Is piece below the empty space
220         else if(emptyPlace_.x() == point.x() && point.y() - verticalStep_ == emptyPlace_.y()) {
221             pieces_.at(i)->setMovable(true);
222         }
223
224         // Is piece on top of the empty space
225         else if(emptyPlace_.x() == point.x() && point.y() + verticalStep_ == emptyPlace_.y()) {
226             pieces_.at(i)->setMovable(true);
227         }
228
229         // The piece is somewhere else
230         else {
231             pieces_.at(i)->setMovable(false);
232         }
233     }
234 }