File indexing completed on 2025-03-23 06:54:31
0001 /* 0002 SPDX-FileCopyrightText: 2008 Sascha Peilicke <sasch.pe@gmx.de> 0003 0004 SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0005 */ 0006 0007 #ifndef KIGO_GAME_H 0008 #define KIGO_GAME_H 0009 0010 #include "move.h" 0011 #include "player.h" 0012 #include "stone.h" 0013 0014 #include <QList> 0015 #include <QProcess> 0016 #include <QString> 0017 #include <QUndoStack> 0018 0019 namespace Kigo { 0020 0021 class Score; 0022 0023 /** 0024 * The Game class implements the Go game and acts as a wrapper around a 0025 * remote Go Game game implementing the Go Text Protocol (GTP). It uses 0026 * GTP protocol version 2 and interfaces the game executable in an 0027 * synchronous manor. The best supported game should (naturally) 0028 * be GnuGo. 0029 * 0030 * @code 0031 * Game *game = new Game; 0032 * 0033 * // Run a session with a Go game in GTP mode 0034 * game->start("gnugo --mode gtp"); 0035 * 0036 * // Get some information about the Go game 0037 * game->name(); 0038 * game->version(); 0039 * 0040 * game->stop(); 0041 * @endcode 0042 * 0043 * @author Sascha Peilicke <sasch.pe@gmx.de> 0044 * @since 0.1 0045 */ 0046 class Game : public QObject 0047 { 0048 Q_OBJECT 0049 0050 public: 0051 /** 0052 * Enumeration of all possible final states of a field when a game is over 0053 */ 0054 enum class FinalState { 0055 FinalAlive = 1, ///< The stone on the field is alive 0056 FinalDead, ///< The stone on the field is dead 0057 FinalSeki, ///< 0058 FinalWhiteTerritory, ///< The field belongs to the white player 0059 FinalBlackTerritory, ///< The field belongs to the black player 0060 FinalDame, ///< The field belongs to no player 0061 FinalStateInvalid ///< The state is invalid, shows error 0062 }; 0063 0064 explicit Game(QObject *parent = nullptr); 0065 ~Game() override; 0066 0067 /** 0068 * Connect to the given Go game game in GTP mode. The most common 0069 * used case is 'gnugo --mode gtp' but this depends on your platform 0070 * and installed Go game(s). 0071 * 0072 * @param command The executable command to start in GTP mode. 0073 */ 0074 bool start(const QString &command); 0075 0076 /** 0077 * Gracefully stop and exit the Go game game. 0078 */ 0079 void stop(); 0080 0081 /** 0082 * Check whether the Game object is connected to a Go game, running 0083 * and waiting for commands to be fed with. 0084 */ 0085 bool isRunning() const { return m_process.state() == QProcess::Running; } 0086 QString engineName() const { return m_engineName; } 0087 QString engineVersion() const { return m_engineVersion; } 0088 QString engineCommand() const { return m_engineCommand; } 0089 QUndoStack *undoStack() { return &m_undoStack; } 0090 0091 /** 0092 * Initialize a new game. 0093 */ 0094 bool init(); 0095 0096 /** 0097 * Initialize from a SGF file and start from a specific move number 0098 * if desired. 0099 * 0100 * @param fileName The SGF file name 0101 * @param moveNumber The move number 0102 */ 0103 bool init(const QString &fileName, int moveNumber = 0); 0104 0105 /** 0106 * Save the current game as a SGF file. 0107 * 0108 * @param fileName The SGF file name 0109 */ 0110 bool save(const QString &fileName); 0111 0112 /** 0113 * Set the board size to NxN. 0114 * 0115 * @param size The board size (standard are 9x9, 13x13 and 19x19) 0116 */ 0117 bool setBoardSize(int size); 0118 int boardSize() const { return m_boardSize; } 0119 0120 /** 0121 * Set the komi. 0122 * 0123 * @param komi The komi to be set (usually 4.5 or 4.5 on 19x19 boards) 0124 */ 0125 bool setKomi(float komi); 0126 float komi() const { return m_komi; } 0127 0128 /** 0129 * Set up fixed placement handicap stones. 0130 * 0131 * @param handicap The number of handicap stones. 0132 */ 0133 bool setFixedHandicap(int handicap); 0134 int fixedHandicap() const { return m_fixedHandicap; } 0135 0136 /** 0137 * Returns the maximum amount fixed handicap stones placeable at the 0138 * current Go board size. 0139 * 0140 * @return The maximum allowed fixed handicap 0141 */ 0142 int fixedHandicapUpperBound(); 0143 0144 Player ¤tPlayer() { return *m_currentPlayer; } 0145 const Player ¤tPlayer() const { return *m_currentPlayer; } 0146 Player &whitePlayer() { return m_whitePlayer; } 0147 const Player &whitePlayer() const { return m_whitePlayer; } 0148 Player &blackPlayer() { return m_blackPlayer; } 0149 const Player &blackPlayer() const { return m_blackPlayer; } 0150 0151 bool playMove(const Move &move, bool undoable = true); 0152 bool playMove(const Player &player, const Stone &stone = Stone(), bool undoable = true); 0153 bool generateMove(const Player &player, bool undoable = true); 0154 bool undoMove(); 0155 bool redoMove(); 0156 0157 int currentMoveNumber() const { return m_currentMove; } 0158 0159 /** 0160 * Returns the last move made by either player. Don't call this method 0161 * when no moves where made at all! 0162 */ 0163 Move lastMove() const; 0164 0165 /** 0166 * Returns the number of moves in the game so far. 0167 * Especially helpful when loading a game. 0168 */ 0169 int moveCount(); 0170 0171 /** 0172 * Returns a list of all stones of that player on the board. 0173 */ 0174 QList<Stone> stones(const Player &player); 0175 0176 /** 0177 * Returns a list of all moves by that player. 0178 */ 0179 QList<Move> moves(const Player &player); 0180 QList<Move> moves() { return m_movesList; } 0181 0182 /** 0183 * Returns the positions of the liberties for the stone at 'field'. 0184 * 0185 * @param field The field to return liberties for 0186 */ 0187 QList<Stone> liberties(const Stone &field); 0188 0189 /** 0190 * Generate a list of the best moves for a player with weights. 0191 */ 0192 QList<Stone> bestMoves(const Player &player); 0193 0194 /** 0195 * List all legal moves for either player. 0196 */ 0197 QList<Stone> legalMoves(const Player &player); 0198 0199 /** 0200 * List the number of captures taken by either player. 0201 */ 0202 int captures(const Player &player); 0203 0204 /** 0205 * Report the final status of a field in a finished game. 0206 * 0207 * @param field Report status for that feed 0208 * @see FinalState 0209 */ 0210 FinalState finalState(const Stone &field); 0211 0212 /** 0213 * Report fields with a specified final status in a finished game. 0214 * 0215 * @param state Report only fields with that state 0216 * @see FinalState 0217 */ 0218 QList<Stone> finalStates(FinalState state); 0219 0220 /** 0221 * Compute the score of a finished game. This method can take a 0222 * long time to complete. It is thus recommended to use estimatedScore(). 0223 * 0224 * @return Score in SGF format (RE property) 0225 */ 0226 Score finalScore(); 0227 0228 /** 0229 * Returns an estimate of the final score based on the current game 0230 * situation. 0231 */ 0232 Score estimatedScore(); 0233 0234 bool canRedo() const { return m_undoStack.canRedo(); } 0235 bool canUndo() const { return m_undoStack.canUndo(); } 0236 0237 bool isFinished() const { return m_gameFinished; } 0238 0239 Q_SIGNALS: 0240 /** 0241 * This signal is emitted when the board is first started and 0242 * can be used to trigger an update to a visual representation. 0243 */ 0244 void boardInitialized(); 0245 0246 /** 0247 * This signal is emitted when the board situation changed and 0248 * can be used to trigger an update to a visual representation. 0249 */ 0250 void boardChanged(); 0251 0252 /** This signal is emitted when the board size was changed. */ 0253 void boardSizeChanged(int); 0254 0255 /** This signal is emitted when a player resigns. */ 0256 void resigned(const Kigo::Player &); 0257 0258 void passMovePlayed(const Kigo::Player &); 0259 /** 0260 * This signal is emitted when both players played a pass move 0261 * after another. It is also send when pass moves are gone 0262 * (which is indicated by a value of 0).*/ 0263 void consecutivePassMovesPlayed(int); 0264 0265 /** This signal is emitted when the current player changes. */ 0266 void currentPlayerChanged(const Kigo::Player &); 0267 0268 /** 0269 * This signal is emitted when the game starts or ends a 0270 * non-blocking wait. This is useful to reflect the wait state 0271 * in the UI. 0272 */ 0273 void waiting(bool); 0274 0275 /** This signal is emitted when availability of redo moves changes */ 0276 void canRedoChanged(bool); 0277 0278 /** This signal is emitted when availability of undo moves changes */ 0279 void canUndoChanged(bool); 0280 0281 public Q_SLOTS: 0282 void gameSetup(); 0283 0284 private Q_SLOTS: 0285 /** 0286 * Wait gracefully for a response from the Go game. The returned string 0287 * from the Go game is stored in 'm_response'. 0288 * 0289 * @param nonBlocking This should be set for commands that take a long 0290 * time to complete to avoid ugly UI blocking. 0291 */ 0292 bool waitResponse(bool nonBlocking = false); 0293 0294 /** 0295 * Slot to handle QProcess's readyRead signal. 0296 */ 0297 void readyRead(); 0298 0299 void undoIndexChanged(int index); 0300 0301 private: 0302 void setCurrentPlayer(Player &player); 0303 0304 QProcess m_process; 0305 0306 QString m_engineName; 0307 QString m_engineVersion; 0308 QString m_engineCommand; 0309 QString m_response; 0310 0311 QList<Move> m_movesList; 0312 int m_currentMove; 0313 QUndoStack m_undoStack; 0314 int m_lastUndoIndex; 0315 0316 Player *m_currentPlayer; 0317 Player m_blackPlayer; 0318 Player m_whitePlayer; 0319 0320 float m_komi; 0321 int m_boardSize; 0322 int m_fixedHandicap; 0323 int m_consecutivePassMoveNumber; 0324 bool m_waitAndProcessEvents; 0325 bool m_gameFinished; 0326 }; 0327 0328 } // End of namespace Kigo 0329 0330 #endif