forked from openkylin/bovo
368 lines
10 KiB
C++
368 lines
10 KiB
C++
/*******************************************************************
|
|
*
|
|
* Copyright 2007 Aron Boström <c02ab@efd.lth.se>
|
|
*
|
|
* Bovo is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2, or (at your option)
|
|
* any later version.
|
|
*
|
|
* Bovo is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with Bovo; see the file COPYING. If not, write to
|
|
* the Free Software Foundation, 51 Franklin Street, Fifth Floor,
|
|
* Boston, MA 02110-1301, USA.
|
|
*
|
|
********************************************************************/
|
|
|
|
/** @file game.h declares class Game in namespace bovo */
|
|
|
|
#ifndef BOVO_GAME_H
|
|
#define BOVO_GAME_H
|
|
|
|
#include <KgDifficulty>
|
|
#include <QList>
|
|
#include <QObject>
|
|
#include <QStringList>
|
|
|
|
#include "common.h"
|
|
#include "move.h"
|
|
|
|
|
|
/** namespace for ai */
|
|
namespace ai
|
|
{
|
|
class Ai;
|
|
class AiFactory;
|
|
} /* namespace ai */
|
|
|
|
using namespace ai;
|
|
|
|
/** namespace for game engine */
|
|
namespace bovo
|
|
{
|
|
class Board;
|
|
class Dimension;
|
|
class Coord;
|
|
|
|
/**
|
|
* The Game engine
|
|
*
|
|
* This class is supposed to replace the gui/Game class and the game/board
|
|
* class.
|
|
*
|
|
* It keeps track of the both players (AI, network, gui or whatever).
|
|
* It keeps track of the playing board, and its playing history.
|
|
* It can walk up or down the playing history (undo).
|
|
* It can call an AI player of its own, to give the active player a hint.
|
|
* It decides if a game has ended (someone has won or it is a draw).
|
|
* It can tell which is the winning line and the winning move.
|
|
*
|
|
* @code
|
|
* Dimension dimension(width, height);
|
|
* Game game(dimension, X);
|
|
* MoveStatus status = game.move(Coord(x, y));
|
|
* if (status.error()) {
|
|
* qDebug() << status.toQString() << endl;
|
|
* // status.turn() == true => not your turn
|
|
* // status.busy() == true => tried to play an already busy coordinate
|
|
* // status.gameOver() == true => game is already over
|
|
* }
|
|
* @endcode
|
|
*/
|
|
class Game : public QObject
|
|
{
|
|
Q_OBJECT
|
|
public:
|
|
/**
|
|
* @brief Constructs a Game
|
|
* @description Constructs a Game object with a playing board with
|
|
* width and height specified by a given Dimension, a starting Player and
|
|
* an AI skill level
|
|
* @param dimension the Dimension specifying the width and height
|
|
* @param startingPlayer the player who starts
|
|
* @param skill the skill (difficulty level) of the AI
|
|
* @param demoMode whether this game is a demo or not
|
|
* @param playTime time in ms for space between turns in demo and replay
|
|
* @param aiFactory provider of AI implementations
|
|
*/
|
|
Game(const Dimension &dimension,
|
|
Player startingPlayer,
|
|
KgDifficultyLevel::StandardLevel skill,
|
|
DemoMode demoMode,
|
|
unsigned int playTime,
|
|
AiFactory *aiFactory);
|
|
|
|
/**
|
|
* @brief Re-Constructs a saved Game
|
|
* @description Constructs a Game object with a playing board with
|
|
* width and height specified by a given Dimension, a game history and
|
|
* an AI skill level
|
|
* @param dimension the Dimension specifying the width and height
|
|
* @param restoreGame the game history to restore
|
|
* @param skill the skill (difficulty level) of the AI
|
|
* @param playTime time in ms for space between turns in demo and replay
|
|
* @param aiFactory provider of AI implementations
|
|
*/
|
|
Game(const Dimension &dimension, const QStringList &restoreGame, KgDifficultyLevel::StandardLevel skill, unsigned int playTime, AiFactory *aiFactory);
|
|
|
|
/**
|
|
* @brief destructs this Game
|
|
* @description destructs this Game object
|
|
*/
|
|
~Game() override;
|
|
|
|
/**
|
|
* @brief is it the computer's turn?
|
|
* @description tells whether the computer is the one with the current turn
|
|
* @return \c true if computer is at turn, \c false otherwise
|
|
*/
|
|
bool computerTurn() const;
|
|
|
|
/**
|
|
* @brief is game in demo mode?
|
|
* @return \c Demo if game is in demo mode, \c NotDemo otherwise
|
|
*/
|
|
DemoMode demoMode() const;
|
|
|
|
/**
|
|
* @brief is Game Over?
|
|
* @description tells whether game is over (someone has won) or not
|
|
* @return \c true if game has ended, \c false if game is still on
|
|
*/
|
|
bool isGameOver() const;
|
|
|
|
/**
|
|
* @brief the game history
|
|
* @description gives the history as a linked list, starting with oldest
|
|
* moves first.
|
|
* @return the game history
|
|
*/
|
|
QList<Move> history() const;
|
|
|
|
/**
|
|
* @brief the latest move
|
|
* @description returns the latest move that has been performed
|
|
* @return the latest move performed
|
|
*/
|
|
Move latestMove() const;
|
|
|
|
/**
|
|
* @brief is this coordinate on board?
|
|
* @description tells whether this coordinate is within the limits of the
|
|
* playing board.
|
|
* @param coord coordinate to verify
|
|
* @return \c true if coordinate is ok, \c false otherwise
|
|
*/
|
|
bool ok(const Coord &coord) const;
|
|
|
|
/**
|
|
* @brief the player id
|
|
* @return the player id
|
|
*/
|
|
Player player() const;
|
|
|
|
/**
|
|
* @brief sets the AI skill
|
|
* @description sets the skill level of the AI
|
|
* @param skill new skill (difficulty level) for the AI
|
|
*/
|
|
void setSkill(KgDifficultyLevel::StandardLevel skill);
|
|
|
|
/**
|
|
* @brief starts a new turn
|
|
* @description starts a new turn
|
|
*/
|
|
void start();
|
|
|
|
/**
|
|
* @brief gets the player of a coordinate
|
|
* @description returns the player id of a coordinate in the playing board
|
|
* @param coord coordinate to query
|
|
* @return \c X, \c O, or \c No
|
|
*/
|
|
Player player(const Coord &coord) const;
|
|
|
|
/**
|
|
* @brief save game
|
|
* Saves this game to a file
|
|
* @param filename savegame file
|
|
* @return \c true if game was saved successfully, \c false otherwise
|
|
*/
|
|
bool save(const QString &filename) const;
|
|
|
|
/**
|
|
* @brief return game history if it is not over yet
|
|
* This is used for saving an unfinished game upon quitting bovo,
|
|
* so we can continue this game next time.
|
|
* @return formatted savefile without line breaks
|
|
*/
|
|
QStringList saveLast() const;
|
|
|
|
/**
|
|
* @brief start a game that have been restored.
|
|
*/
|
|
void startRestored();
|
|
|
|
/**
|
|
* @brief in which direction was the winning line?
|
|
* @description tells in what direction the gameover was caused, or -1 if
|
|
* game is still on.
|
|
* @return @c -1 if game isn't over, @c 0 for horizontal,
|
|
* @c 1 for vertical, @c 2 for diagonal upperleft downwards right,
|
|
* @c 3 for bottomleft upwards right
|
|
*/
|
|
short winDir() const;
|
|
|
|
/**
|
|
* @brief returns if the board is full
|
|
* @description returns true if every field on the table is occupied
|
|
*/
|
|
bool boardFull() const;
|
|
|
|
/**
|
|
* @brief cancel the AI if it is thinking and wait for actual cancellation
|
|
* @description interrupts the thinking of the AI if it is thinking, and
|
|
* does not return until the AI thread has really finished
|
|
*/
|
|
void cancelAndWait();
|
|
|
|
public Q_SLOTS:
|
|
/**
|
|
* @brief make a move
|
|
* @param move move to make
|
|
*/
|
|
void move(const Move &move);
|
|
|
|
/**
|
|
* @brief start replaying game
|
|
* Starts the replay of this game, emitting the signal \c replayBegin()
|
|
*/
|
|
void replay();
|
|
|
|
/**
|
|
* @brief undo the latest move in the history
|
|
*/
|
|
void undoLatest();
|
|
|
|
Q_SIGNALS:
|
|
/**
|
|
* @brief emitted at game over
|
|
* @param moves Winning moves (winning line)
|
|
*/
|
|
void gameOver(const QList<Move> &moves);
|
|
|
|
/**
|
|
* @brief emitted when board has changed (needs repainting)
|
|
* @param move the Move that has changed the board, player()==No means undo
|
|
*/
|
|
void boardChanged(const Move &move);
|
|
|
|
/**
|
|
* @brief emitted when it is the player's turn
|
|
*/
|
|
void playerTurn();
|
|
|
|
/**
|
|
* @brief emitted when it is the player's turn
|
|
*/
|
|
void oposerTurn();
|
|
|
|
/**
|
|
* @brief emitted at replay, signaling the UI to clear itself
|
|
*/
|
|
void replayBegin();
|
|
|
|
/**
|
|
* @brief emitted when replay ends
|
|
* @param moves winning line
|
|
*/
|
|
void replayEnd(const QList<Move> &moves);
|
|
|
|
/**
|
|
* @brief emitted once this game is allowed to be undoed
|
|
*/
|
|
void undoAble();
|
|
|
|
/**
|
|
* @brief emitted once this game no longer is allowed to be undoed
|
|
*/
|
|
void undoNotAble();
|
|
|
|
private Q_SLOTS:
|
|
void replayNext();
|
|
|
|
private:
|
|
/**
|
|
* @brief make a move
|
|
* @description performs the specified move.
|
|
* @param move move to make
|
|
*/
|
|
void makeMove(const Move &move);
|
|
|
|
/* get a neighbour coord in a given direction */
|
|
Coord next(const Coord &coord, usi direction) const;
|
|
|
|
/* calculates if a coord is part of a winning line */
|
|
short win(const Coord &coord) const;
|
|
|
|
/* returns the winning line */
|
|
QList<Move> winningMoves() const;
|
|
|
|
/* AI */
|
|
Ai *m_ai;
|
|
|
|
/* AI factory */
|
|
AiFactory *m_aiFactory;
|
|
|
|
/* playing board */
|
|
Board *m_board;
|
|
|
|
/* Current player */
|
|
Player m_curPlayer;
|
|
|
|
/* computer player id */
|
|
Player m_computerMark;
|
|
|
|
/* Whether this is a demo game or not */
|
|
DemoMode m_demoMode;
|
|
|
|
/* is game over? */
|
|
bool m_gameOver;
|
|
|
|
/* game history */
|
|
QList<Move> m_history;
|
|
|
|
/* if game is in Undo state */
|
|
bool m_inUndoState;
|
|
|
|
/* user player id */
|
|
Player m_playerMark;
|
|
|
|
/* time in between two moves in replay and demo mode, in milliseconds */
|
|
unsigned int m_playTime;
|
|
|
|
/* is game in replay mode? */
|
|
bool m_replaying;
|
|
|
|
/* replay iterator for history list */
|
|
QList<Move>::const_iterator m_replayIterator;
|
|
|
|
/* replay iterator for the end of the history */
|
|
QList<Move>::const_iterator m_replayIteratorEnd;
|
|
|
|
/* winning direction, or -1 if game isn't won */
|
|
short m_winDir;
|
|
|
|
/* the number of marks on the board */
|
|
short m_stepCount;
|
|
};
|
|
|
|
} /* namespace bovo */
|
|
|
|
#endif // BOVO_GAME_H
|