File indexing completed on 2024-04-21 04:04:02
0001 /* 0002 KShisen - A japanese game similar to Mahjongg 0003 SPDX-FileCopyrightText: 1997 Mario Weilguni <mweilguni@sime.com> 0004 SPDX-FileCopyrightText: 2002-2004 Dave Corrie <kde@davecorrie.com> 0005 SPDX-FileCopyrightText: 2007 Mauricio Piacentini <mauricio@tabuleiro.com> 0006 SPDX-FileCopyrightText: 2009-2016 Frederik Schwarzer <schwarzer@kde.org> 0007 0008 SPDX-License-Identifier: GPL-2.0-or-later 0009 */ 0010 0011 // KMahjonggLib integration and SVG support for KDE 4: Mauricio Piacentini <mauricio@tabuleiro.com> 0012 0013 #ifndef KSHISEN_BOARD_H 0014 #define KSHISEN_BOARD_H 0015 0016 // STL 0017 #include <memory> 0018 #include <vector> 0019 0020 // Qt 0021 #include <QList> 0022 #include <QSize> 0023 #include <QWidget> 0024 #include <QRandomGenerator> 0025 0026 // KDEGames 0027 #include <KGameClock> 0028 #include <KGameSound> 0029 0030 // LibKMahjongg 0031 #include <KMahjonggBackground> 0032 #include <KMahjonggTileset> 0033 0034 // KShisen 0035 #include "debug.h" 0036 #include "move.h" 0037 #include "possiblemove.h" 0038 0039 namespace KShisen 0040 { 0041 /** 0042 * A list of possible moves the player has to choose between 0043 */ 0044 using PossibleMoves = QList<PossibleMove>; 0045 0046 /** 0047 * @brief Class holding the game board and its functions. 0048 */ 0049 class Board : public QWidget 0050 { 0051 Q_OBJECT 0052 0053 public: 0054 explicit Board(QWidget * parent = nullptr); 0055 0056 /// Number of different kinds of tiles in the game. 0057 static int constexpr nTiles = 42; 0058 0059 void paintEvent(QPaintEvent * e) override; 0060 void mousePressEvent(QMouseEvent * e) override; 0061 void resizeEvent(QResizeEvent * e) override; 0062 0063 void setDelay(int); 0064 int delay() const; 0065 0066 /// Returns if undo step is available 0067 bool canUndo() const; 0068 /// Returns if redo step is available 0069 bool canRedo() const; 0070 /// Undoes one step 0071 void undo(); 0072 /// Redoes one step 0073 void redo(); 0074 0075 void setSize(int x, int y); 0076 void resizeBoard(); 0077 0078 void showHint(); 0079 bool pathFoundBetweenMatchingTiles(PossibleMoves & possibleMoves) const; 0080 0081 #ifdef DEBUGGING 0082 void makeHintMove(); 0083 void finish(); 0084 void dumpBoard() const; 0085 void dumpBoard(const std::vector<int> & field) const; 0086 #endif 0087 0088 /// Returns the number of tiles left on the board 0089 int tilesLeft() const; 0090 /// Returns the current game time in seconds 0091 int currentTime() const; 0092 0093 /// Returns whether the current game is solvable 0094 bool isSolvable(bool restore); // const? 0095 0096 bool solvableFlag() const; 0097 void setSolvableFlag(bool enabled); 0098 bool showUnsolvableMessageFlag() const; 0099 void setShowUnsolvableMessageFlag(bool enabled); 0100 bool gravityFlag() const; 0101 void setGravityFlag(bool enabled); 0102 void setChineseStyleFlag(bool enabled); 0103 void setTilesCanSlideFlag(bool enabled); 0104 0105 /// Returns possible number of tiles in X direction 0106 int xTiles() const; 0107 /// Returns possible number of tiles in Y direction 0108 int yTiles() const; 0109 /// Returns overall possible number of tiles in current game board size 0110 int tiles() const; 0111 0112 /// Resets the game timer 0113 void resetTimer(); 0114 /// Resets the undo history 0115 void resetUndo(); 0116 /// Resets the redo history 0117 void resetRedo(); 0118 /// Sets whether there are no matching tiles left 0119 void setGameStuckEnabled(bool enabled); 0120 /// Sets whether the game is over 0121 void setGameOverEnabled(bool enabled); 0122 /// Sets whether the game is in cheat mode 0123 void setCheatModeEnabled(bool enabled); 0124 0125 /** Returns whether the game is over. 0126 * @return True if game is over, False if game is not over 0127 */ 0128 bool isOver() const; 0129 0130 /** Returns whether the game is in pause mode. 0131 * @return True if game is paused, False if game is not paused 0132 */ 0133 bool isPaused() const; 0134 0135 /** Returns whether there are still matching tiles left. 0136 * @return True if there are no matching tiles left, False if there are matching tiles left 0137 */ 0138 bool isStuck() const; 0139 0140 /** Returns whether player is in cheat mode. 0141 * @return True if the player is in cheat mode, False if not 0142 */ 0143 bool hasCheated() const; 0144 0145 Q_SIGNALS: 0146 void markMatched(); // unused? 0147 void newGameStarted(); 0148 void changed(); 0149 void tileCountChanged(); 0150 void endOfGame(); 0151 void resized(); 0152 void invalidMove(); 0153 void tilesDoNotMatch(); 0154 void selectATile(); 0155 void selectAMove(); 0156 void selectAMatchingTile(); 0157 void cheatStatusChanged(); 0158 0159 public Q_SLOTS: 0160 /** Does most of the newGame work. 0161 * This slot is called from the KShisen::invokeNewGame() signal from KShisen and 0162 * should call KShisen::newGame again to do the work that cannot be done 0163 * from Board. 0164 */ 0165 void newGame(); 0166 0167 /// Controls the pause mode 0168 void setPauseEnabled(bool enabled); 0169 0170 /** Enables / disables sounds. 0171 * @param enabled Whether sound shall be enabled 0172 */ 0173 void setSoundsEnabled(bool enabled); 0174 /// Loads the game settings 0175 void loadSettings(); 0176 /// Loads the given tileset 0177 bool loadTileset(QString const & pathToTileset); 0178 /// Loads the given background 0179 bool loadBackground(QString const & pathToBackground); 0180 0181 private Q_SLOTS: 0182 void undrawConnection(); 0183 0184 protected: 0185 QSize sizeHint() const override; 0186 0187 private: // functions 0188 /** Calculates the board's offset. 0189 * The board is centred inside the main playing area. xOffset()/yOffset() 0190 * provide the coordinates of the top-left corner of the board. 0191 */ 0192 int xOffset() const; 0193 int yOffset() const; 0194 0195 /** Returns the line width to use. 0196 * The line width should be relative to the tile size, however, if the tile size is too small, keep a minimum line width. 0197 */ 0198 int lineWidth() const; 0199 0200 /** Puts a tile of type @p value to the given position @p tilePos. 0201 * @param tilePos Position to be modified. 0202 * @param value Type of the tile to place. 0203 */ 0204 void setField(TilePos tilePos, int value); 0205 /** Returns the kind of tile residing at the given position @p tilePos 0206 * @param TilePos Position to look at. 0207 * @return Type of the tile. 0208 */ 0209 int field(TilePos tilePos) const; 0210 /** Repaints the area of the given @p TilePos. 0211 * @param TilePos Position of the tile to repaint. 0212 */ 0213 void repaintTile(TilePos tilePos); 0214 void showInfoRect(QPainter &, const QString & message); 0215 void drawTiles(QPainter &, QPaintEvent *); 0216 void clearHighlight(); 0217 0218 /** Checks if two tiles can match. 0219 * This is used for connecting them and for highlighting tiles of the same group. 0220 * @param tile1 type of the first tile 0221 * @param tile2 type of the second tile 0222 */ 0223 bool tilesMatch(int tile1, int tile2) const; 0224 0225 /** Checks if a path between two tiles can be made with a single line. 0226 * @param tilePos1 coordinates of the first tile 0227 * @param tilePos2 coordinates of the second tile 0228 */ 0229 bool canMakePath(TilePos tilePos1, TilePos tilePos2) const; 0230 0231 /** Checks if the tile at \p tilePos1 can be slid to \p tilePos2. 0232 * @param tilePos1 coordinates of the slide's initial position 0233 * @param tilePos2 coordinates of the slide's final position 0234 * @param slide The movement of the last tile slid will be stored in @p slide 0235 */ 0236 bool canSlideTiles(TilePos tilePos1, TilePos tilePos2, Slide & slide) const; 0237 0238 /** Checks if a path between two tiles can be made with 2 or 3 lines. 0239 * @param tilePos1 coordinates of the first tile 0240 * @param tilePos2 coordinates of the second tile 0241 * @param possibleMoves All the possible moves are stored here 0242 * @return The number of paths found 0243 */ 0244 int findPath(TilePos tilePos1, TilePos tilePos2, PossibleMoves & possibleMoves) const; 0245 0246 /** Find a path of 1 or 2 segments between tiles. 0247 * @param tilePos1 coordinates of the first tile 0248 * @param tilePos2 coordinates of the second tile 0249 * @param possibleMoves all the possible moves are stored here 0250 * @return The number of paths found 0251 */ 0252 int findSimplePath(TilePos tilePos1, TilePos tilePos2, PossibleMoves & possibleMoves) const; 0253 void performMove(PossibleMove & possibleMoves); 0254 void performSlide(TilePos tilePos, Slide const & slide); 0255 void reverseSlide(TilePos tilePos, Slide const & slide); 0256 bool isTileHighlighted(TilePos tilePos) const; 0257 void drawConnection(); 0258 void drawPossibleMoves(bool b); 0259 /** Calculated the middle coordinates of the given tile position. 0260 * @param tilePos tile position 0261 * @return The middle coordinates of the tile at \p tilePos 0262 */ 0263 QPoint midCoord(TilePos tilePos) const; 0264 void unmarkTile(); 0265 void marked(TilePos tilePos); 0266 void madeMove(TilePos tilePos1, TilePos tilePos2, Slide slide = Slide()); 0267 0268 /// Applies gravity to all columns. 0269 void applyGravity(); 0270 0271 /** Returns True if @p tilePos is a valid position on Board. 0272 * @return Whether @p tiePos is valid. 0273 */ 0274 bool isValidPos(TilePos tilePos) const; 0275 0276 /** Returns True if @p tilePos is a valid position on Board including outline. 0277 * @return Whether @p tiePos is valid. 0278 */ 0279 bool isValidPosWithOutline(TilePos tilePos) const; 0280 0281 /** Returns True if @p tile is of kind FLOWERS. 0282 * @return Whether @p tile is within the range of the Flower tiles. 0283 */ 0284 bool isTileFlower(int tile) const; 0285 /** Returns True if @p tile is of kind SEASONS. 0286 * @return Whether @p tile is within the range of the Seasons tiles. 0287 */ 0288 bool isTileSeason(int tile) const; 0289 0290 private: 0291 KGameClock m_gameClock{}; 0292 0293 KMahjonggTileset m_tiles{}; 0294 KMahjonggBackground m_background{}; 0295 0296 QRandomGenerator m_random{}; 0297 0298 std::list<std::unique_ptr<Move>> m_undo{}; ///< Undo history 0299 std::list<std::unique_ptr<Move>> m_redo{}; ///< Redo history 0300 0301 int m_markX{0}; 0302 int m_markY{0}; 0303 Path m_connection{}; 0304 PossibleMoves m_possibleMoves{}; 0305 std::vector<int> m_field{}; ///< Matrix holding the game board grid 0306 int m_xTiles{}; 0307 int m_yTiles{}; 0308 int m_delay{}; 0309 int m_level{}; 0310 int m_shuffle{}; 0311 0312 // The game can be in one of the following states. 0313 enum class GameState { Normal, 0314 Paused, 0315 Stuck, 0316 Over }; 0317 GameState m_gameState{GameState::Normal}; 0318 bool m_cheat{}; ///< Whether the cheat mode is set 0319 0320 bool m_gravityFlag{true}; ///< Whether game is played with gravity 0321 bool m_solvableFlag{}; ///< Whether game is solvable 0322 bool m_showUnsolvableMessageFlag{}; ///< Whether "game unsolvable" message is shown 0323 bool m_chineseStyleFlag{}; ///< Whether game follows Chinese rules 0324 bool m_tilesCanSlideFlag{}; ///< Whether tiles can slide when connecting 0325 0326 int m_highlightedTile{-1}; 0327 0328 bool m_paintConnection{}; 0329 bool m_paintPossibleMoves{}; 0330 bool m_paintInProgress{}; 0331 TilePos m_tileRemove1{}; 0332 TilePos m_tileRemove2{}; 0333 KGameSound m_soundPick; ///< Sound object to play when tile is selected 0334 KGameSound m_soundFall; ///< Sound object to play when tiles fall down in gravity mode 0335 }; 0336 } // namespace KShisen 0337 0338 #endif // KSHISEN_BOARD_H 0339 0340 // vim: expandtab:tabstop=4:shiftwidth=4 0341 // kate: space-indent on; indent-width 4