File indexing completed on 2024-04-28 04:02:29
0001 /* 0002 SPDX-FileCopyrightText: 2007 Dmitry Suzdalev <dimsuz@gmail.com> 0003 SPDX-FileCopyrightText: 2010 Brian Croom <brian.s.croom@gmail.com> 0004 0005 SPDX-License-Identifier: GPL-2.0-or-later 0006 */ 0007 0008 #ifndef MINEFIELDITEM_H 0009 #define MINEFIELDITEM_H 0010 0011 // Qt 0012 #include <QGraphicsObject> 0013 #include <QList> 0014 #include <QPair> 0015 0016 class KGameRenderer; 0017 class CellItem; 0018 class BorderItem; 0019 0020 using FieldPos = QPair<int, int>; 0021 0022 /** 0023 * Graphics item that represents MineField. 0024 * It is composed of many (or little) of CellItems. 0025 * This class is responsible of generation game field 0026 * with given properties (num rows, num cols, num mines) and 0027 * handling resizes 0028 */ 0029 class MineFieldItem : public QGraphicsObject 0030 { 0031 Q_OBJECT 0032 public: 0033 /** 0034 * Constructor. 0035 */ 0036 explicit MineFieldItem(KGameRenderer* renderer); 0037 /** 0038 * Initializes game field: creates items, places them on positions, 0039 * (re)sets some variables 0040 * 0041 * @param numRows number of rows 0042 * @param numCols number of columns 0043 * @param numMines number of mines 0044 */ 0045 void initField( int numRows, int numCols, int numMines ); 0046 /** 0047 * Resets mines to the initial state. 0048 */ 0049 void resetMines(); 0050 /** 0051 * Resizes this graphics item so it fits in given rect 0052 */ 0053 void resizeToFitInRect(const QRectF& rect); 0054 /** 0055 * Reimplemented from QGraphicsItem 0056 */ 0057 QRectF boundingRect() const override;// reimp 0058 /** 0059 * @return num rows in field 0060 */ 0061 int rowCount() const; 0062 /** 0063 * @return num columns in field 0064 */ 0065 int columnCount() const; 0066 /** 0067 * @return num mines in field 0068 */ 0069 int minesCount() const; 0070 0071 /** 0072 * Minimal number of free positions on a field 0073 */ 0074 static const int MINIMAL_FREE = 10; 0075 0076 Q_SIGNALS: 0077 void flaggedMinesCountChanged(int); 0078 void firstClickDone(); 0079 void gameOver(bool won); 0080 private: 0081 // reimplemented 0082 void mousePressEvent( QGraphicsSceneMouseEvent * ) override; 0083 // reimplemented 0084 void mouseReleaseEvent( QGraphicsSceneMouseEvent * ) override; 0085 // reimplemented 0086 void mouseMoveEvent( QGraphicsSceneMouseEvent * ) override; 0087 0088 /** 0089 * Returns cell item at (row,col). 0090 * Always use this function instead hand-computing index in m_cells 0091 */ 0092 inline CellItem* itemAt(int row, int col) { return m_cells.at( row*m_numCols + col ); } 0093 /** 0094 * Overloaded one, which takes QPair 0095 */ 0096 inline CellItem* itemAt( FieldPos pos ) { return itemAt(pos.first,pos.second); } 0097 /** 0098 * Calculates (row,col) from given index in m_cells and returns them in QPair 0099 */ 0100 inline FieldPos rowColFromIndex(int idx) 0101 { 0102 int row = idx/m_numCols; 0103 return qMakePair(row, idx - row*m_numCols); 0104 } 0105 /** 0106 * Generates game field ensuring that cell at clickedIdx 0107 * will be empty to allow the player quickly jump into the game. 0108 * 0109 * @param clickedIdx specifies index which should NOT have mine and be empty 0110 */ 0111 void generateField(int clickedIdx); 0112 /** 0113 * Returns all adjacent items for item at row, col 0114 */ 0115 QList<CellItem*> adjacentItemsFor(int row, int col); 0116 /** 0117 * Returns all valid adjacent row,col pairs for row, col 0118 */ 0119 QList<FieldPos> adjacentRowColsFor(int row, int col); 0120 /** 0121 * Checks if player lost the game. Return `true` if lost. 0122 * A `true` return value and a `false` `m_gameOver` indicates that the game is restarted. 0123 */ 0124 bool checkLost(); 0125 /** 0126 * Checks if player won the game. Return `true` if won. 0127 */ 0128 bool checkWon(); 0129 /** 0130 * Reveals all unmarked items containing mines 0131 */ 0132 void revealAllMines(); 0133 /** 0134 * Reimplemented from QGraphicsItem 0135 */ 0136 void paint( QPainter * painter, const QStyleOptionGraphicsItem*, QWidget * widget = nullptr ) override; 0137 /** 0138 * Repositions all child cell items upon resizes 0139 */ 0140 void adjustItemPositions(); 0141 /** 0142 * Reveals all empty cells around cell at (row,col), 0143 * until it found cells with digits (which are also revealed) 0144 */ 0145 void revealEmptySpace(int row, int col); 0146 /** 0147 * Sets up border items (positions and properties) 0148 */ 0149 void setupBorderItems(); 0150 /** 0151 * Changes the flag state of a clicked cell and updates mine count 0152 */ 0153 void handleFlag(CellItem* itemUnderMouse); 0154 /** 0155 * Return `true` if the game is finished (and possibly restarted) after the call. 0156 */ 0157 bool onItemRevealed(int row, int col); 0158 // overload 0159 bool onItemRevealed(CellItem* item); 0160 0161 // note: in member functions use itemAt (see above ) 0162 // instead of hand-computing index from row & col! 0163 // => not depend on how m_cells is represented 0164 /** 0165 * Array which holds all child cell items 0166 */ 0167 QList<CellItem*> m_cells; 0168 /** 0169 * Array which holds border items 0170 */ 0171 QList<BorderItem*> m_borders; 0172 /** 0173 * The width and height of minefield cells in scene coordinates 0174 */ 0175 int m_cellSize = 1; // dummy init value for non-large boundingRect, non-null because used for divisions 0176 /** 0177 * Number of field rows 0178 */ 0179 int m_numRows = 1; // dummy init value for non-large boundingRect, non-null because used for divisions 0180 /** 0181 * Number of field columns 0182 */ 0183 int m_numCols = 1; // dummy init value for non-large boundingRect, non-null because used for divisions 0184 /** 0185 * Number of mines in field 0186 */ 0187 int m_minesCount; 0188 /** 0189 * Number of flagged mines 0190 */ 0191 int m_flaggedMinesCount; 0192 /** 0193 * row and column where mouse was pressed. 0194 * (-1,-1) if it is already released 0195 */ 0196 FieldPos m_leftButtonPos; 0197 FieldPos m_midButtonPos; 0198 bool m_firstClick; 0199 bool m_gameOver; 0200 bool m_emulatingMidButton; 0201 int m_numUnrevealed; 0202 0203 KGameRenderer* m_renderer; 0204 }; 0205 0206 #endif