1/*
2 Copyright 2007 Dmitry Suzdalev <dimsuz@gmail.com>
3 Copyright 2010 Brian Croom <brian.s.croom@gmail.com>
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 2 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, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18*/
19#ifndef MINEFIELDITEM_H
20#define MINEFIELDITEM_H
21
22#include <QVector>
23#include <QGraphicsObject>
24#include <QPair>
25#include <KRandomSequence>
26
27class KGameRenderer;
28class CellItem;
29class BorderItem;
30
31typedef QPair<int,int> FieldPos;
32
33/**
34 * Graphics item that represents MineField.
35 * It is composed of many (or little) of CellItems.
36 * This class is responsible of generation game field
37 * with given properties (num rows, num cols, num mines) and
38 * handling resizes
39 */
40class MineFieldItem : public QGraphicsObject
41{
42 Q_OBJECT
43public:
44 /**
45 * Constructor.
46 */
47 explicit MineFieldItem(KGameRenderer* renderer);
48 /**
49 * Initializes game field: creates items, places them on positions,
50 * (re)sets some variables
51 *
52 * @param numRows number of rows
53 * @param numCols number of columns
54 * @param numMines number of mines
55 */
56 void initField( int numRows, int numCols, int numMines );
57 /**
58 * Resizes this graphics item so it fits in given rect
59 */
60 void resizeToFitInRect(const QRectF& rect);
61 /**
62 * Reimplemented from QGraphicsItem
63 */
64 QRectF boundingRect() const;// reimp
65 /**
66 * @return num rows in field
67 */
68 int rowCount() const { return m_numRows; }
69 /**
70 * @return num columns in field
71 */
72 int columnCount() const { return m_numCols; }
73 /**
74 * @return num mines in field
75 */
76 int minesCount() const { return m_minesCount; }
77
78 /**
79 * Minimal number of free positions on a field
80 */
81 static const int MINIMAL_FREE = 10;
82
83signals:
84 void flaggedMinesCountChanged(int);
85 void firstClickDone();
86 void gameOver(bool won);
87private:
88 // reimplemented
89 virtual void mousePressEvent( QGraphicsSceneMouseEvent * );
90 // reimplemented
91 virtual void mouseReleaseEvent( QGraphicsSceneMouseEvent * );
92 // reimplemented
93 virtual void mouseMoveEvent( QGraphicsSceneMouseEvent * );
94
95 /**
96 * Returns cell item at (row,col).
97 * Always use this function instead hand-computing index in m_cells
98 */
99 inline CellItem* itemAt(int row, int col) { return m_cells.at( row*m_numCols + col ); }
100 /**
101 * Overloaded one, which takes QPair
102 */
103 inline CellItem* itemAt( const FieldPos& pos ) { return itemAt(pos.first,pos.second); }
104 /**
105 * Calculates (row,col) from given index in m_cells and returns them in QPair
106 */
107 inline FieldPos rowColFromIndex(int idx)
108 {
109 int row = idx/m_numCols;
110 return qMakePair(row, idx - row*m_numCols);
111 }
112 /**
113 * Generates game field ensuring that cell at clickedIdx
114 * will be empty to allow the player quickly jump into the game.
115 *
116 * @param clickedIdx specifies index which should NOT have mine and be empty
117 */
118 void generateField(int clickedIdx);
119 /**
120 * Returns all adjasent items for item at row, col
121 */
122 QList<CellItem*> adjasentItemsFor(int row, int col);
123 /**
124 * Returns all valid adjasent row,col pairs for row, col
125 */
126 QList<FieldPos> adjasentRowColsFor(int row, int col);
127 /**
128 * Checks if player lost the game
129 */
130 void checkLost();
131 /**
132 * Checks if player won the game
133 */
134 void checkWon();
135 /**
136 * Reveals all unmarked items containing mines
137 */
138 void revealAllMines();
139 /**
140 * Reimplemented from QGraphicsItem
141 */
142 void paint( QPainter * painter, const QStyleOptionGraphicsItem*, QWidget * widget = 0 );
143 /**
144 * Repositions all child cell items upon resizes
145 */
146 void adjustItemPositions();
147 /**
148 * Reveals all empty cells around cell at (row,col),
149 * until it found cells with digits (which are also revealed)
150 */
151 void revealEmptySpace(int row, int col);
152 /**
153 * Sets up border items (positions and properties)
154 */
155 void setupBorderItems();
156
157 void onItemRevealed(int row, int col);
158 // overload
159 void onItemRevealed(CellItem* item);
160
161 // note: in member functions use itemAt (see above )
162 // instead of hand-computing index from row & col!
163 // => not depend on how m_cells is represented
164 /**
165 * Array which holds all child cell items
166 */
167 QVector<CellItem*> m_cells;
168 /**
169 * Array which holds border items
170 */
171 QVector<BorderItem*> m_borders;
172 /**
173 * The width and height of minefield cells in scene coordinates
174 */
175 int m_cellSize;
176 /**
177 * Number of field rows
178 */
179 int m_numRows;
180 /**
181 * Number of field columns
182 */
183 int m_numCols;
184 /**
185 * Number of mines in field
186 */
187 int m_minesCount;
188 /**
189 * Number of flagged mines
190 */
191 int m_flaggedMinesCount;
192 /**
193 * Random sequence used to generate mine positions
194 */
195 KRandomSequence m_randomSeq;
196 /**
197 * row and column where mouse was pressed.
198 * (-1,-1) if it is already released
199 */
200 FieldPos m_leftButtonPos;
201 FieldPos m_midButtonPos;
202 bool m_firstClick;
203 bool m_gameOver;
204 bool m_emulatingMidButton;
205 int m_numUnrevealed;
206
207 KGameRenderer* m_renderer;
208};
209
210#endif
211