File indexing completed on 2024-11-24 03:43:18

0001 /*******************************************************************
0002  *
0003  * Copyright 2007  Aron Boström <c02ab@efd.lth.se>
0004  *
0005  * Bovo is free software; you can redistribute it and/or modify
0006  * it under the terms of the GNU General Public License as published by
0007  * the Free Software Foundation; either version 2, or (at your option)
0008  * any later version.
0009  *
0010  * Bovo is distributed in the hope that it will be useful,
0011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0013  * GNU General Public License for more details.
0014  *
0015  * You should have received a copy of the GNU General Public License
0016  * along with Bovo; see the file COPYING.  If not, write to
0017  * the Free Software Foundation, 51 Franklin Street, Fifth Floor,
0018  * Boston, MA 02110-1301, USA.
0019  *
0020  ********************************************************************/
0021 
0022 /** @file game.h declares class Game in namespace bovo */
0023 
0024 #ifndef BOVO_GAME_H
0025 #define BOVO_GAME_H
0026 
0027 #include <KGameDifficulty>
0028 #include <QList>
0029 #include <QObject>
0030 #include <QStringList>
0031 
0032 #include "common.h"
0033 #include "move.h"
0034 
0035 
0036 /** namespace for ai */
0037 namespace ai
0038 {
0039 class Ai;
0040 class AiFactory;
0041 } /* namespace ai */
0042 
0043 using namespace ai;
0044 
0045 /** namespace for game engine */
0046 namespace bovo
0047 {
0048 class Board;
0049 class Dimension;
0050 class Coord;
0051 
0052 /**
0053  * The Game engine
0054  *
0055  * This class is supposed to replace the gui/Game class and the game/board
0056  * class.
0057  *
0058  * It keeps track of the both players (AI, network, gui or whatever).
0059  * It keeps track of the playing board, and its playing history.
0060  * It can walk up or down the playing history (undo).
0061  * It can call an AI player of its own, to give the active player a hint.
0062  * It decides if a game has ended (someone has won or it is a draw).
0063  * It can tell which is the winning line and the winning move.
0064  *
0065  * @code
0066  * Dimension dimension(width, height);
0067  * Game game(dimension, X);
0068  * MoveStatus status = game.move(Coord(x, y));
0069  * if (status.error()) {
0070  *     qDebug() << status.toQString() << endl;
0071  *     // status.turn() == true => not your turn
0072  *     // status.busy() == true => tried to play an already busy coordinate
0073  *     // status.gameOver() == true => game is already over
0074  * }
0075  * @endcode
0076  */
0077 class Game : public QObject
0078 {
0079     Q_OBJECT
0080 public:
0081     /**
0082      * @brief Constructs a Game
0083      * @description Constructs a Game object with a playing board with
0084      * width and height specified by a given Dimension, a starting Player and
0085      * an AI skill level
0086      * @param dimension the Dimension specifying the width and height
0087      * @param startingPlayer the player who starts
0088      * @param skill the skill (difficulty level) of the AI
0089      * @param demoMode whether this game is a demo or not
0090      * @param playTime time in ms for space between turns in demo and replay
0091      * @param aiFactory provider of AI implementations
0092      */
0093     Game(const Dimension &dimension,
0094          Player startingPlayer,
0095          KGameDifficultyLevel::StandardLevel skill,
0096          DemoMode demoMode,
0097          unsigned int playTime,
0098          AiFactory *aiFactory);
0099 
0100     /**
0101      * @brief Re-Constructs a saved Game
0102      * @description Constructs a Game object with a playing board with
0103      * width and height specified by a given Dimension, a game history and
0104      * an AI skill level
0105      * @param dimension the Dimension specifying the width and height
0106      * @param restoreGame the game history to restore
0107      * @param skill the skill (difficulty level) of the AI
0108      * @param playTime time in ms for space between turns in demo and replay
0109      * @param aiFactory provider of AI implementations
0110      */
0111     Game(const Dimension &dimension, const QStringList &restoreGame, KGameDifficultyLevel::StandardLevel skill, unsigned int playTime, AiFactory *aiFactory);
0112 
0113     /**
0114      * @brief destructs this Game
0115      * @description destructs this Game object
0116      */
0117     ~Game() override;
0118 
0119     /**
0120      * @brief is it the computer's turn?
0121      * @description tells whether the computer is the one with the current turn
0122      * @return \c true if computer is at turn, \c false otherwise
0123      */
0124     bool computerTurn() const;
0125 
0126     /**
0127      * @brief is game in demo mode?
0128      * @return \c Demo if game is in demo mode, \c NotDemo otherwise
0129      */
0130     DemoMode demoMode() const;
0131 
0132     /**
0133      * @brief is Game Over?
0134      * @description tells whether game is over (someone has won) or not
0135      * @return \c true if game has ended, \c false if game is still on
0136      */
0137     bool isGameOver() const;
0138 
0139     /**
0140      * @brief the game history
0141      * @description gives the history as a linked list, starting with oldest
0142      * moves first.
0143      * @return the game history
0144      */
0145     QList<Move> history() const;
0146 
0147     /**
0148      * @brief the latest move
0149      * @description returns the latest move that has been performed
0150      * @return the latest move performed
0151      */
0152     Move latestMove() const;
0153 
0154     /**
0155      * @brief is this coordinate on board?
0156      * @description tells whether this coordinate is within the limits of the
0157      * playing board.
0158      * @param coord coordinate to verify
0159      * @return \c true if coordinate is ok, \c false otherwise
0160      */
0161     bool ok(const Coord &coord) const;
0162 
0163     /**
0164      * @brief the player id
0165      * @return the player id
0166      */
0167     Player player() const;
0168 
0169     /**
0170      * @brief sets the AI skill
0171      * @description sets the skill level of the AI
0172      * @param skill new skill (difficulty level) for the AI
0173      */
0174     void setSkill(KGameDifficultyLevel::StandardLevel skill);
0175 
0176     /**
0177      * @brief starts a new turn
0178      * @description starts a new turn
0179      */
0180     void start();
0181 
0182     /**
0183      * @brief gets the player of a coordinate
0184      * @description returns the player id of a coordinate in the playing board
0185      * @param coord coordinate to query
0186      * @return \c X, \c O, or \c No
0187      */
0188     Player player(const Coord &coord) const;
0189 
0190     /**
0191      * @brief save game
0192      * Saves this game to a file
0193      * @param filename savegame file
0194      * @return \c true if game was saved successfully, \c false otherwise
0195      */
0196     bool save(const QString &filename) const;
0197 
0198     /**
0199      * @brief return game history if it is not over yet
0200      * This is used for saving an unfinished game upon quitting bovo,
0201      * so we can continue this game next time.
0202      * @return formatted savefile without line breaks
0203      */
0204     QStringList saveLast() const;
0205 
0206     /**
0207      * @brief start a game that have been restored.
0208      */
0209     void startRestored();
0210 
0211     /**
0212      * @brief in which direction was the winning line?
0213      * @description tells in what direction the gameover was caused, or -1 if
0214      * game is still on.
0215      * @return @c -1 if game isn't over, @c 0 for horizontal,
0216      * @c 1 for vertical, @c 2 for diagonal upperleft downwards right,
0217      * @c 3 for bottomleft upwards right
0218      */
0219     short winDir() const;
0220 
0221     /**
0222      * @brief returns if the board is full
0223      * @description returns true if every field on the table is occupied
0224      */
0225     bool boardFull() const;
0226 
0227     /**
0228      * @brief cancel the AI if it is thinking and wait for actual cancellation
0229      * @description interrupts the thinking of the AI if it is thinking, and
0230      * does not return until the AI thread has really finished
0231      */
0232     void cancelAndWait();
0233 
0234 public Q_SLOTS:
0235     /**
0236      * @brief make a move
0237      * @param move move to make
0238      */
0239     void move(const Move &move);
0240 
0241     /**
0242      * @brief start replaying game
0243      * Starts the replay of this game, emitting the signal \c replayBegin()
0244      */
0245     void replay();
0246 
0247     /**
0248      * @brief undo the latest move in the history
0249      */
0250     void undoLatest();
0251 
0252 Q_SIGNALS:
0253     /**
0254      * @brief emitted at game over
0255      * @param moves Winning moves (winning line)
0256      */
0257     void gameOver(const QList<Move> &moves);
0258 
0259     /**
0260      * @brief emitted when board has changed (needs repainting)
0261      * @param move the Move that has changed the board, player()==No means undo
0262      */
0263     void boardChanged(const Move &move);
0264 
0265     /**
0266      * @brief emitted when it is the player's turn
0267      */
0268     void playerTurn();
0269 
0270     /**
0271      * @brief emitted when it is the player's turn
0272      */
0273     void oposerTurn();
0274 
0275     /**
0276      * @brief emitted at replay, signaling the UI to clear itself
0277      */
0278     void replayBegin();
0279 
0280     /**
0281      * @brief emitted when replay ends
0282      * @param moves winning line
0283      */
0284     void replayEnd(const QList<Move> &moves);
0285 
0286     /**
0287      * @brief emitted once this game is allowed to be undoed
0288      */
0289     void undoAble();
0290 
0291     /**
0292      * @brief emitted once this game no longer is allowed to be undoed
0293      */
0294     void undoNotAble();
0295 
0296 private Q_SLOTS:
0297     void replayNext();
0298 
0299 private:
0300     /**
0301      * @brief make a move
0302      * @description performs the specified move.
0303      * @param move move to make
0304      */
0305     void makeMove(const Move &move);
0306 
0307     /* get a neighbour coord in a given direction */
0308     Coord next(const Coord &coord, usi direction) const;
0309 
0310     /* calculates if a coord is part of a winning line */
0311     short win(const Coord &coord) const;
0312 
0313     /* returns the winning line */
0314     QList<Move> winningMoves() const;
0315 
0316     /* AI */
0317     Ai *m_ai;
0318 
0319     /* AI factory */
0320     AiFactory *m_aiFactory;
0321 
0322     /* playing board */
0323     Board *m_board;
0324 
0325     /* Current player */
0326     Player m_curPlayer;
0327 
0328     /* computer player id */
0329     Player m_computerMark;
0330 
0331     /* Whether this is a demo game or not */
0332     DemoMode m_demoMode;
0333 
0334     /* is game over? */
0335     bool m_gameOver;
0336 
0337     /* game history */
0338     QList<Move> m_history;
0339 
0340     /* if game is in Undo state */
0341     bool m_inUndoState;
0342 
0343     /* user player id */
0344     Player m_playerMark;
0345 
0346     /* time in between two moves in replay and demo mode, in milliseconds */
0347     unsigned int m_playTime;
0348 
0349     /* is game in replay mode? */
0350     bool m_replaying;
0351 
0352     /* replay iterator for history list */
0353     QList<Move>::const_iterator m_replayIterator;
0354 
0355     /* replay iterator for the end of the history */
0356     QList<Move>::const_iterator m_replayIteratorEnd;
0357 
0358     /* winning direction, or -1 if game isn't won */
0359     short m_winDir;
0360 
0361     /* the number of marks on the board */
0362     short m_stepCount;
0363 };
0364 
0365 } /* namespace bovo */
0366 
0367 #endif // BOVO_GAME_H