eliot/game/public_game.h
Olivier Teulière 4ffaef3e1d - Throw exceptions in case of problem in Duplicate::setPlayer()
- Clean up of the text interface:
    - removed all uses of wcstok()
    - factorized common code
    - made code a bit more robust
2009-01-24 17:11:07 +00:00

301 lines
8.6 KiB
C++

/*****************************************************************************
* Eliot
* Copyright (C) 1999-2008 Antoine Fraboulet & Olivier Teulière
* Authors: Antoine Fraboulet <antoine.fraboulet @@ free.fr>
* Olivier Teulière <ipkiss @@ gmail.com>
*
* This program 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 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*****************************************************************************/
#ifndef _PUBLIC_GAME_H_
#define _PUBLIC_GAME_H_
#include <string>
class Game;
class Dictionary;
class Bag;
class Board;
class History;
class Player;
class Navigation;
class Results;
using namespace std;
/**
* This class is a wrapper around a Game object (Façade design pattern).
*
* Game objects are not meant for direct use outside of the game library,
* because they expose too many internal members.
* A PublicGame provides a cleaner interface to implement a UI, avoiding
* the need to know too much about the Game internals.
*/
class PublicGame
{
public:
/**
* Build a PublicGame from a Game object
* The PublicGame takes the ownership of the Game object.
*/
// XXX: should be private?
PublicGame(Game &iGame);
~PublicGame();
/***************
* Game type
***************/
// XXX: should not be in Game?
/// Game mode: each one of these modes is implemented in an inherited class
enum GameMode
{
kTRAINING,
kFREEGAME,
kDUPLICATE
};
GameMode getMode() const;
string getModeAsString() const;
/// Game variant: it slightly modifies the rules of the game
enum GameVariant
{
kNONE, // Normal game rules
kJOKER, // Joker game
kEXPLOSIVE // "Explosive" game
};
/**
* Accessors for the variant of the game.
* The variant can be changed during a game without any problem
* (though it seems rather useless...)
*/
void setVariant(GameVariant iVariant);
GameVariant getVariant() const;
/***************
* Various getters
***************/
/**
* Get the dictionary associated with the game.
* You should never create a new dictionary object while a Game
* object still exists
*/
const Dictionary & getDic() const;
/// Get the board
const Board& getBoard() const;
/// Get the bag
const Bag& getBag() const;
/// Get the history of the game */
const History& getHistory() const;
/***************
* Methods to access players.
***************/
/**
* Add a player to the game.
* The Game object takes ownership of the given player
*/
void addPlayer(Player *iPlayer);
const Player& getPlayer(unsigned int iNum) const;
const Player& getCurrentPlayer() const;
unsigned int getNbPlayers() const;
unsigned int getNbHumanPlayers() const;
/// Return true if the player has played for the current turn
// XXX: not very nice API, should be a player property...
bool hasPlayed(unsigned int player) const;
/***************
* Game handling
***************/
/**
* Start the game.
* AI players are handled automatically, so if the game only has AI
* players, it will play until the end.
*/
void start();
/**
* Method used by human players to play the word iWord at coordinates
* iCoord, and end the turn (if possible)
* Possible return values:
* 0: correct word, the Round can be used by the caller
* 1: one letter of the word is invalid in the current dictionary
* 2: invalid coordinates (unreadable or out of the board)
* 3: word not present in the dictionary
* 4: not enough letters in the rack to play the word
* 5: word is part of a longer one
* 6: word overwriting an existing letter
* 7: invalid crosscheck
* 8: word already present on the board (no new letter from the rack)
* 9: isolated word (not connected to the rest)
* 10: first word not horizontal
* 11: first word not covering the H8 square
* 12: word going out of the board
*/
int play(const wstring &iWord, const wstring &iCoord);
/**
* Go back to turn iTurn.
* We must have: iTurn < getHistory().getSize()
* Possible return values:
* 0: everything went fine
* 1: iTurn is invalid
*/
//int back(unsigned int iTurn);
/// Shuffle the rack of the current player
void shuffleRack();
/***************
* Training games
* These methods throw an exception if the current game is not in
* the Training mode.
***************/
void trainingSearch();
const Results& trainingGetResults() const;
int trainingPlayResult(unsigned int iResultIndex);
enum RackMode
{
kRACK_NEW, // Only new tiles
kRACK_ALL // All tiles
};
/**
* Complete (or reset) the rack randomly.
* @exception EndGameException if it is impossible to complete the rack
* for some reason...
*/
void trainingSetRackRandom(bool iCheck, RackMode iRackMode);
void trainingSetRackManual(bool iCheck, const wstring &iLetters);
/// Place a temporary word on the board for preview purposes
void trainingTestPlay(unsigned int iResultIndex);
/// Remove the temporary word
void trainingRemoveTestPlay();
/// Get the temporary word
wstring trainingGetTestPlayWord() const;
/***************
* Duplicate games
* These methods throw an exception if the current game is not in
* the Duplicate mode.
***************/
/**
* Set the current player, given its ID.
* The given player ID must correspond to a human player, who did not
* play yet for this turn.
* @param p: ID of the player
* @exception GameException: Thrown if the player is not human or if
* he has already played
*/
void duplicateSetPlayer(unsigned int p);
/***************
* FreeGame games
* These methods throw an exception if the current game is not in
* the FreeGame mode.
***************/
/**
* Pass the turn, changing the letters listed in iToChange.
* If you simply want to pass the turn without changing any letter,
* provide an empty string.
*
* Possible return values:
* 0: everything went fine
* 1: changing letters is not allowed if there are less than 7 tiles
* left in the bag
* 2: the rack of the current player does not contain all the
* listed letters
* 3: the game is already finished
* 4: some letters are invalid for the current dictionary
*/
int freeGamePass(const wstring &iToChange);
/***************
* Saved games handling
***************/
/**
* Possible formats for the saved games
*/
enum GameFileFormat
{
kFILE_FORMAT_STANDARD,
kFILE_FORMAT_ADVANCED
};
/**
* load() returns the loaded game, or NULL if there was a problem
* load() does need some more work to be robust enough to
* handle "hand written" files
*/
static PublicGame * load(FILE *fin, const Dictionary &iDic);
/**
* Save a game to a file
* Standard format is used for training games so that it is compatible
* with previous versions of Eliot.
*
* Saving can be forced to advanced format for training games by
* setting the last parameter to kFILE_FORMAT_ADVANCED
*/
void save(ostream &out, GameFileFormat format = kFILE_FORMAT_STANDARD) const;
/***************
* Navigation in the game history
***************/
unsigned int getCurrTurn() const;
unsigned int getNbTurns() const;
bool isFirstTurn() const;
bool isLastTurn() const;
void firstTurn();
void prevTurn();
void nextTurn();
void lastTurn();
/**
* Get rid of the future turns of the game, the current turn
* becoming the last one.
*/
void clearFuture();
/**
* Print the contents of the commands history, to ease debugging
*/
void printTurns() const;
private:
/// Wrapped game
Game &m_game;
};
#endif