Diffstat (limited to 'noncore/games/fifteen/fifteen.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r-- | noncore/games/fifteen/fifteen.cpp | 364 |
1 files changed, 364 insertions, 0 deletions
diff --git a/noncore/games/fifteen/fifteen.cpp b/noncore/games/fifteen/fifteen.cpp new file mode 100644 index 0000000..293cd65 --- a/dev/null +++ b/noncore/games/fifteen/fifteen.cpp | |||
@@ -0,0 +1,364 @@ | |||
1 | /********************************************************************** | ||
2 | ** Copyright (C) 2000 Trolltech AS. All rights reserved. | ||
3 | ** | ||
4 | ** This file is part of Qtopia Environment. | ||
5 | ** | ||
6 | ** This file may be distributed and/or modified under the terms of the | ||
7 | ** GNU General Public License version 2 as published by the Free Software | ||
8 | ** Foundation and appearing in the file LICENSE.GPL included in the | ||
9 | ** packaging of this file. | ||
10 | ** | ||
11 | ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE | ||
12 | ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. | ||
13 | ** | ||
14 | ** See http://www.trolltech.com/gpl/ for GPL licensing information. | ||
15 | ** | ||
16 | ** Contact info@trolltech.com if any conditions of this licensing are | ||
17 | ** not clear to you. | ||
18 | ** | ||
19 | **********************************************************************/ | ||
20 | |||
21 | #include "fifteen.h" | ||
22 | |||
23 | #include <qpe/resource.h> | ||
24 | #include <qpe/config.h> | ||
25 | |||
26 | #include <qvbox.h> | ||
27 | #include <qaction.h> | ||
28 | #include <qlayout.h> | ||
29 | #include <qpainter.h> | ||
30 | #include <qpopupmenu.h> | ||
31 | #include <qmessagebox.h> | ||
32 | #include <qpe/qpetoolbar.h> | ||
33 | #include <qpe/qpemenubar.h> | ||
34 | #include <qstringlist.h> | ||
35 | #include <qapplication.h> | ||
36 | |||
37 | #include <stdlib.h> | ||
38 | #include <time.h> | ||
39 | |||
40 | FifteenMainWindow::FifteenMainWindow(QWidget *parent, const char* name) | ||
41 | : QMainWindow( parent, name ) | ||
42 | { | ||
43 | // random seed | ||
44 | srand(time(0)); | ||
45 | |||
46 | setToolBarsMovable( FALSE ); | ||
47 | QVBox *vbox = new QVBox( this ); | ||
48 | PiecesTable *table = new PiecesTable( vbox ); | ||
49 | setCentralWidget(vbox); | ||
50 | |||
51 | QPEToolBar *toolbar = new QPEToolBar(this); | ||
52 | toolbar->setHorizontalStretchable( TRUE ); | ||
53 | addToolBar(toolbar); | ||
54 | |||
55 | QPEMenuBar *menubar = new QPEMenuBar( toolbar ); | ||
56 | menubar->setMargin(0); | ||
57 | |||
58 | QPopupMenu *game = new QPopupMenu( this ); | ||
59 | |||
60 | QWidget *spacer = new QWidget( toolbar ); | ||
61 | spacer->setBackgroundMode( PaletteButton ); | ||
62 | toolbar->setStretchableWidget( spacer ); | ||
63 | |||
64 | QAction *a = new QAction( tr( "Randomize" ), Resource::loadPixmap( "new" ), | ||
65 | QString::null, 0, this, 0 ); | ||
66 | connect( a, SIGNAL( activated() ), table, SLOT( slotRandomize() ) ); | ||
67 | a->addTo( game ); | ||
68 | a->addTo( toolbar ); | ||
69 | |||
70 | a = new QAction( tr( "Solve" ), Resource::loadPixmap( "repeat" ), | ||
71 | QString::null, 0, this, 0 ); | ||
72 | connect( a, SIGNAL( activated() ), table, SLOT( slotReset() ) ); | ||
73 | a->addTo( game ); | ||
74 | a->addTo( toolbar ); | ||
75 | |||
76 | menubar->insertItem( tr( "Game" ), game ); | ||
77 | } | ||
78 | |||
79 | PiecesTable::PiecesTable(QWidget* parent, const char* name ) | ||
80 | : QTableView(parent, name), _menu(0), _randomized(false) | ||
81 | { | ||
82 | // setup table view | ||
83 | setFrameStyle(StyledPanel | Sunken); | ||
84 | setBackgroundMode(NoBackground); | ||
85 | setMouseTracking(true); | ||
86 | |||
87 | setNumRows(4); | ||
88 | setNumCols(4); | ||
89 | |||
90 | // init arrays | ||
91 | initMap(); | ||
92 | readConfig(); | ||
93 | initColors(); | ||
94 | |||
95 | // set font | ||
96 | QFont f = font(); | ||
97 | f.setPixelSize(18); | ||
98 | f.setBold( TRUE ); | ||
99 | setFont(f); | ||
100 | } | ||
101 | |||
102 | PiecesTable::~PiecesTable() | ||
103 | { | ||
104 | writeConfig(); | ||
105 | } | ||
106 | |||
107 | void PiecesTable::writeConfig() | ||
108 | { | ||
109 | Config cfg("Fifteen"); | ||
110 | cfg.setGroup("Game"); | ||
111 | QStringList map; | ||
112 | for (unsigned int i = 0; i < 16; i++) | ||
113 | map.append( QString::number( _map[i] ) ); | ||
114 | cfg.writeEntry("Map", map, '-'); | ||
115 | cfg.writeEntry("Randomized", _randomized ); | ||
116 | } | ||
117 | |||
118 | void PiecesTable::readConfig() | ||
119 | { | ||
120 | Config cfg("Fifteen"); | ||
121 | cfg.setGroup("Game"); | ||
122 | QStringList map = cfg.readListEntry("Map", '-'); | ||
123 | _randomized = cfg.readBoolEntry( "Randomized", FALSE ); | ||
124 | unsigned int i = 0; | ||
125 | for ( QStringList::Iterator it = map.begin(); it != map.end(); ++it ) { | ||
126 | _map[i] = (*it).toInt(); | ||
127 | i++; | ||
128 | if ( i > 15 ) break; | ||
129 | } | ||
130 | } | ||
131 | |||
132 | void PiecesTable::paintCell(QPainter *p, int row, int col) | ||
133 | { | ||
134 | int w = cellWidth(); | ||
135 | int h = cellHeight(); | ||
136 | int x2 = w - 1; | ||
137 | int y2 = h - 1; | ||
138 | |||
139 | int number = _map[col + row * numCols()] + 1; | ||
140 | |||
141 | // draw cell background | ||
142 | if(number == 16) | ||
143 | p->setBrush(colorGroup().background()); | ||
144 | else | ||
145 | p->setBrush(_colors[number-1]); | ||
146 | p->setPen(NoPen); | ||
147 | p->drawRect(0, 0, w, h); | ||
148 | |||
149 | // draw borders | ||
150 | if (height() > 40) { | ||
151 | p->setPen(colorGroup().text()); | ||
152 | if(col < numCols()-1) | ||
153 | p->drawLine(x2, 0, x2, y2); // right border line | ||
154 | |||
155 | if(row < numRows()-1) | ||
156 | p->drawLine(0, y2, x2, y2); // bottom boder line | ||
157 | } | ||
158 | |||
159 | // draw number | ||
160 | if (number == 16) return; | ||
161 | p->setPen(black); | ||
162 | p->drawText(0, 0, x2, y2, AlignHCenter | AlignVCenter, QString::number(number)); | ||
163 | } | ||
164 | |||
165 | void PiecesTable::resizeEvent(QResizeEvent *e) | ||
166 | { | ||
167 | QTableView::resizeEvent(e); | ||
168 | |||
169 | setCellWidth(contentsRect().width()/ numRows()); | ||
170 | setCellHeight(contentsRect().height() / numCols()); | ||
171 | } | ||
172 | |||
173 | void PiecesTable::initColors() | ||
174 | { | ||
175 | _colors.resize(numRows() * numCols()); | ||
176 | for (int r = 0; r < numRows(); r++) | ||
177 | for (int c = 0; c < numCols(); c++) | ||
178 | _colors[c + r *numCols()] = QColor(255 - 70 * c,255 - 70 * r, 150); | ||
179 | } | ||
180 | |||
181 | void PiecesTable::initMap() | ||
182 | { | ||
183 | _map.resize(16); | ||
184 | for (unsigned int i = 0; i < 16; i++) | ||
185 | _map[i] = i; | ||
186 | |||
187 | _randomized = false; | ||
188 | } | ||
189 | |||
190 | void PiecesTable::randomizeMap() | ||
191 | { | ||
192 | initMap(); | ||
193 | _randomized = true; | ||
194 | // find the free position | ||
195 | int pos = _map.find(15); | ||
196 | |||
197 | int move = 0; | ||
198 | while ( move < 333 ) { | ||
199 | |||
200 | int frow = pos / numCols(); | ||
201 | int fcol = pos - frow * numCols(); | ||
202 | |||
203 | // find click position | ||
204 | int row = rand()%4; | ||
205 | int col = rand()%4; | ||
206 | |||
207 | // sanity check | ||
208 | if ( row < 0 || row >= numRows() ) continue; | ||
209 | if ( col < 0 || col >= numCols() ) continue; | ||
210 | if ( row != frow && col != fcol ) continue; | ||
211 | |||
212 | move++; | ||
213 | |||
214 | // rows match -> shift pieces | ||
215 | if(row == frow) { | ||
216 | |||
217 | if (col < fcol) { | ||
218 | for(int c = fcol; c > col; c--) { | ||
219 | _map[c + row * numCols()] = _map[ c-1 + row *numCols()]; | ||
220 | } | ||
221 | } | ||
222 | else if (col > fcol) { | ||
223 | for(int c = fcol; c < col; c++) { | ||
224 | _map[c + row * numCols()] = _map[ c+1 + row *numCols()]; | ||
225 | } | ||
226 | } | ||
227 | } | ||
228 | // cols match -> shift pieces | ||
229 | else if (col == fcol) { | ||
230 | |||
231 | if (row < frow) { | ||
232 | for(int r = frow; r > row; r--) { | ||
233 | _map[col + r * numCols()] = _map[ col + (r-1) *numCols()]; | ||
234 | } | ||
235 | } | ||
236 | else if (row > frow) { | ||
237 | for(int r = frow; r < row; r++) { | ||
238 | _map[col + r * numCols()] = _map[ col + (r+1) *numCols()]; | ||
239 | } | ||
240 | } | ||
241 | } | ||
242 | // move free cell to click position | ||
243 | _map[pos=(col + row * numCols())] = 15; | ||
244 | repaint(); | ||
245 | } | ||
246 | } | ||
247 | |||
248 | void PiecesTable::checkwin() | ||
249 | { | ||
250 | if(!_randomized) return; | ||
251 | |||
252 | int i; | ||
253 | for (i = 0; i < 16; i++) | ||
254 | if(i != _map[i]) | ||
255 | break; | ||
256 | |||
257 | if (i == 16) { | ||
258 | QMessageBox::information(this, tr("Fifteen Pieces"), | ||
259 | tr("Congratulations!\nYou win the game!")); | ||
260 | _randomized = FALSE; | ||
261 | } | ||
262 | |||
263 | } | ||
264 | |||
265 | void PiecesTable::slotRandomize() | ||
266 | { | ||
267 | randomizeMap(); | ||
268 | } | ||
269 | |||
270 | void PiecesTable::slotReset() | ||
271 | { | ||
272 | initMap(); | ||
273 | repaint(); | ||
274 | } | ||
275 | |||
276 | void PiecesTable::mousePressEvent(QMouseEvent* e) | ||
277 | { | ||
278 | QTableView::mousePressEvent(e); | ||
279 | |||
280 | if (e->button() == RightButton) { | ||
281 | |||
282 | // setup RMB pupup menu | ||
283 | if(!_menu) { | ||
284 | _menu = new QPopupMenu(this); | ||
285 | _menu->insertItem(tr("R&andomize Pieces"), mRandomize); | ||
286 | _menu->insertItem(tr("&Reset Pieces"), mReset); | ||
287 | _menu->adjustSize(); | ||
288 | } | ||
289 | |||
290 | // execute RMB popup and check result | ||
291 | switch(_menu->exec(mapToGlobal(e->pos()))) { | ||
292 | case mRandomize: | ||
293 | randomizeMap(); | ||
294 | break; | ||
295 | case mReset: | ||
296 | initMap(); | ||
297 | repaint(); | ||
298 | break; | ||
299 | default: | ||
300 | break; | ||
301 | } | ||
302 | } | ||
303 | else { | ||
304 | // GAME LOGIC | ||
305 | |||
306 | // find the free position | ||
307 | int pos = _map.find(15); | ||
308 | if(pos < 0) return; | ||
309 | |||
310 | int frow = pos / numCols(); | ||
311 | int fcol = pos - frow * numCols(); | ||
312 | |||
313 | // find click position | ||
314 | int row = findRow(e->y()); | ||
315 | int col = findCol(e->x()); | ||
316 | |||
317 | // sanity check | ||
318 | if (row < 0 || row >= numRows()) return; | ||
319 | if (col < 0 || col >= numCols()) return; | ||
320 | if ( row != frow && col != fcol ) return; | ||
321 | |||
322 | // valid move? | ||
323 | if(row != frow && col != fcol) return; | ||
324 | |||
325 | // rows match -> shift pieces | ||
326 | if(row == frow) { | ||
327 | |||
328 | if (col < fcol) { | ||
329 | for(int c = fcol; c > col; c--) { | ||
330 | _map[c + row * numCols()] = _map[ c-1 + row *numCols()]; | ||
331 | updateCell(row, c, false); | ||
332 | } | ||
333 | } | ||
334 | else if (col > fcol) { | ||
335 | for(int c = fcol; c < col; c++) { | ||
336 | _map[c + row * numCols()] = _map[ c+1 + row *numCols()]; | ||
337 | updateCell(row, c, false); | ||
338 | } | ||
339 | } | ||
340 | } | ||
341 | // cols match -> shift pieces | ||
342 | else if (col == fcol) { | ||
343 | |||
344 | if (row < frow) { | ||
345 | for(int r = frow; r > row; r--) { | ||
346 | _map[col + r * numCols()] = _map[ col + (r-1) *numCols()]; | ||
347 | updateCell(r, col, false); | ||
348 | } | ||
349 | } | ||
350 | else if (row > frow) { | ||
351 | for(int r = frow; r < row; r++) { | ||
352 | _map[col + r * numCols()] = _map[ col + (r+1) *numCols()]; | ||
353 | updateCell(r, col, false); | ||
354 | } | ||
355 | } | ||
356 | } | ||
357 | // move free cell to click position | ||
358 | _map[col + row * numCols()] = 15; | ||
359 | updateCell(row, col, false); | ||
360 | |||
361 | // check if the player wins with this move | ||
362 | checkwin(); | ||
363 | } | ||
364 | } | ||