File indexing completed on 2024-05-19 04:04:47

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 &currentPlayer() { return *m_currentPlayer; }
0145     const Player &currentPlayer() 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