A lot of clean-up:

- Removed logiv from the History class
 - Used BOOST_FOREACH to simplify loops
 - Remove useless annotations and doxygen blocks
 - Added some constness
 - Marked Training::setRack() as deprecated
 - Improved compilation order in game/
This commit is contained in:
Olivier Teulière 2008-11-22 13:09:28 +00:00
parent 5ea1ec4215
commit 70be50c64e
61 changed files with 491 additions and 763 deletions

View file

@ -19,13 +19,6 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*****************************************************************************/
/**
* \file compdic.c
* \brief Program used to compress a dictionary
* \author Antoine Fraboulet
* \date 1999
*/
#include "config.h"
#include <fstream>

View file

@ -19,13 +19,6 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*****************************************************************************/
/**
* \file dic.c
* \brief Dawg dictionary
* \author Antoine Fraboulet & Olivier Teuliere
* \date 2002
*/
#include "config.h"
#include <fstream>

View file

@ -19,13 +19,6 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*****************************************************************************/
/**
* \file dic.h
* \brief Dawg dictionary
* \author Antoine Fraboulet & Olivier Teuliere
* \date 2002
*/
#ifndef _DIC_H_
#define _DIC_H_
@ -49,7 +42,6 @@ typedef unsigned char dic_code_t;
struct params_cross_t;
struct params_7plus1_t;
struct params_regexp_t;
struct search_RegE_list_t;
class Dictionary
{
@ -234,7 +226,6 @@ public:
unsigned int iMaxLength,
unsigned int iMaxResults = 0) const;
private:
// Prevent from copying the dictionary!
Dictionary &operator=(const Dictionary&);
@ -308,9 +299,3 @@ private:
#endif /* _DIC_H_ */
/// Local Variables:
/// mode: c++
/// mode: hs-minor
/// c-basic-offset: 4
/// indent-tabs-mode: nil
/// End:

View file

@ -18,13 +18,6 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*****************************************************************************/
/**
* \file dic_internals.h
* \brief Internal dictionary structures
* \author Antoine Fraboulet
* \date 2002
*/
#ifndef _DIC_INTERNALS_H_
#define _DIC_INTERNALS_H_
@ -75,6 +68,5 @@ struct __attribute__ ((packed)) DicEdge
}
};
#endif /* _DIC_INTERNALS_H */

View file

@ -18,13 +18,6 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*****************************************************************************/
/**
* \file encoding.cpp
* \brief Utility functions to ease handling of wide-character strings
* \author Olivier Teuliere
* \date 2005
*/
#include "config.h"
#include <iostream>

View file

@ -18,13 +18,6 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*****************************************************************************/
/**
* \file encoding.h
* \brief Utility functions to ease manipulation of wide-character strings
* \author Olivier Teuliere
* \date 2005
*/
#ifndef _ENCODING_H_
#define _ENCODING_H_

View file

@ -19,13 +19,6 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*****************************************************************************/
/**
* \file hashtable.c
* \brief Simple hashtable type
* \author Antoine Fraboulet
* \date 1999
*/
#include "hashtable.h"

View file

@ -19,13 +19,6 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*****************************************************************************/
/**
* \file hashtable.h
* \brief Simple hashtable type
* \author Antoine Fraboulet
* \date 1999
*/
#ifndef _HASHTABLE_H
#define _HASHTABLE_H

View file

@ -181,12 +181,5 @@ private:
void buildMapCodeFromChar();
};
#endif /* _HEADER_H */
/// Local Variables:
/// mode: c++
/// mode: hs-minor
/// c-basic-offset: 4
/// indent-tabs-mode: nil
/// End:

View file

@ -19,13 +19,6 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*****************************************************************************/
/**
* \file listdic.c
* \brief Program used to list a dictionary
* \author Antoine Fraboulet
* \date 1999
*/
#include "config.h"
#include <fstream>
@ -199,3 +192,4 @@ int main(int argc, char *argv[])
return 1;
}
}

View file

@ -18,13 +18,6 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*****************************************************************************/
/**
* \file regexp.c
* \brief Regular Expression functions
* \author Antoine Fraboulet
* \date 2005
*/
#include "config.h"
#include <cstdio>
@ -311,8 +304,3 @@ void Node::printTreeDot(const string &iFileName, int detail) const
}
#endif
/// Local Variables:
/// mode: hs-minor
/// c-basic-offset: 2
/// End:

View file

@ -18,13 +18,6 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*****************************************************************************/
/**
* \file regexp.h
* \brief Regular Expression functions
* \author Antoine Fraboulet
* \date 2005
*/
#ifndef _REGEXP_H_
#define _REGEXP_H_
@ -158,9 +151,3 @@ void regexp_print_ptl(int ptl[]);
#endif /* _REGEXP_H_ */
/// Local Variables:
/// mode: c++
/// mode: hs-minor
/// c-basic-offset: 4
/// indent-tabs-mode: nil
/// End:

View file

@ -19,13 +19,6 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*****************************************************************************/
/**
* \file regexpmain.c
* \brief Program used to test regexp
* \author Antoine Fraboulet
* \date 2005
*/
#include "config.h"
#include <exception>
@ -132,3 +125,4 @@ int main(int argc, char* argv[])
return 1;
}
}

View file

@ -142,9 +142,3 @@ bool Tile::operator!=(const Tile &iOther) const
return !(*this == iOther);
}
/// Local Variables:
/// mode: c++
/// mode: hs-minor
/// c-basic-offset: 4
/// indent-tabs-mode: nil
/// End:

View file

@ -89,9 +89,3 @@ private:
#endif
/// Local Variables:
/// mode: c++
/// mode: hs-minor
/// c-basic-offset: 4
/// indent-tabs-mode: nil
/// End:

View file

@ -22,29 +22,29 @@ noinst_LIBRARIES = libgame.a
AM_CPPFLAGS = -I$(top_srcdir)/dic -I../intl -I$(top_srcdir)/intl @LIBCONFIG_CFLAGS@
libgame_a_SOURCES= \
ai_percent.cpp ai_percent.h \
ai_player.h \
game_exception.cpp game_exception.h \
rack.cpp rack.h \
pldrack.cpp pldrack.h \
round.cpp round.h \
move.cpp move.h \
results.cpp results.h \
bag.cpp bag.h \
player.cpp player.h \
ai_player.h \
ai_percent.cpp ai_percent.h \
coord.cpp coord.h \
cross.cpp cross.h \
board.cpp board.h \
board_cross.cpp \
board_search.cpp \
duplicate.cpp duplicate.h \
freegame.cpp freegame.h \
game.cpp game.h \
game_exception.cpp game_exception.h \
game_factory.cpp game_factory.h \
game_io.cpp \
move.cpp move.h \
player.cpp player.h \
pldrack.cpp pldrack.h \
rack.cpp rack.h \
results.cpp results.h \
round.cpp round.h \
settings.cpp settings.h \
training.cpp training.h \
turn.cpp turn.h \
history.cpp history.h \
game.cpp game.h \
game_io.cpp \
duplicate.cpp duplicate.h \
freegame.cpp freegame.h \
training.cpp training.h \
game_factory.cpp game_factory.h \
debug.h

View file

@ -84,9 +84,3 @@ Move AIPercent::getMove() const
}
}
/// Local Variables:
/// mode: c++
/// mode: hs-minor
/// c-basic-offset: 4
/// indent-tabs-mode: nil
/// End:

View file

@ -61,9 +61,3 @@ private:
#endif
/// Local Variables:
/// mode: c++
/// mode: hs-minor
/// c-basic-offset: 4
/// indent-tabs-mode: nil
/// End:

View file

@ -82,9 +82,3 @@ protected:
#endif
/// Local Variables:
/// mode: c++
/// mode: hs-minor
/// c-basic-offset: 4
/// indent-tabs-mode: nil
/// End:

View file

@ -19,6 +19,8 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*****************************************************************************/
#include <boost/foreach.hpp>
#include <string>
#include <cstdlib> // For rand()
@ -29,15 +31,12 @@
Bag::Bag(const Dictionary &iDic)
: m_dic(iDic)
: m_dic(iDic), m_ntiles(0)
{
m_ntiles = 0;
const vector<Tile>& allTiles = m_dic.getAllTiles();
vector<Tile>::const_iterator it;
for (it = allTiles.begin(); it != allTiles.end(); it++)
BOOST_FOREACH(const Tile &tile, m_dic.getAllTiles())
{
m_tilesMap[*it] = it->maxNumber();
m_ntiles += it->maxNumber();
m_tilesMap[tile] = tile.maxNumber();
m_ntiles += tile.maxNumber();
}
}
@ -53,13 +52,13 @@ unsigned int Bag::in(const Tile &iTile) const
unsigned int Bag::getNbVowels() const
{
map<Tile, int>::const_iterator it;
int v = 0;
for (it = m_tilesMap.begin(); it != m_tilesMap.end(); it++)
std::pair<Tile, int> p;
BOOST_FOREACH(p, m_tilesMap)
{
if (it->first.isVowel())
v += it->second;
if (p.first.isVowel())
v += p.second;
}
return v;
}
@ -67,13 +66,13 @@ unsigned int Bag::getNbVowels() const
unsigned int Bag::getNbConsonants() const
{
map<Tile, int>::const_iterator it;
int c = 0;
for (it = m_tilesMap.begin(); it != m_tilesMap.end(); it++)
std::pair<Tile, int> p;
BOOST_FOREACH(p, m_tilesMap)
{
if (it->first.isConsonant())
c += it->second;
if (p.first.isConsonant())
c += p.second;
}
return c;
}
@ -106,12 +105,12 @@ Tile Bag::selectRandom() const
int n = (int)(max * rand() / (RAND_MAX + 1.0));
map<Tile, int>::const_iterator it;
for (it = m_tilesMap.begin(); it != m_tilesMap.end(); it++)
std::pair<Tile, int> p;
BOOST_FOREACH(p, m_tilesMap)
{
if (n < it->second)
return it->first;
n -= it->second;
if (n < p.second)
return p.first;
n -= p.second;
}
ASSERT(false, "We should not come here");
return Tile();
@ -125,14 +124,14 @@ Tile Bag::selectRandomVowel() const
int n = (int)(max * rand() / (RAND_MAX + 1.0));
map<Tile, int>::const_iterator it;
for (it = m_tilesMap.begin(); it != m_tilesMap.end(); it++)
std::pair<Tile, int> p;
BOOST_FOREACH(p, m_tilesMap)
{
if (!it->first.isVowel())
if (!p.first.isVowel())
continue;
if (n < it->second)
return it->first;
n -= it->second;
if (n < p.second)
return p.first;
n -= p.second;
}
ASSERT(false, "We should not come here");
return Tile();
@ -146,14 +145,14 @@ Tile Bag::selectRandomConsonant() const
int n = (int)(max * rand() / (RAND_MAX + 1.0));
map<Tile, int>::const_iterator it;
for (it = m_tilesMap.begin(); it != m_tilesMap.end(); it++)
std::pair<Tile, int> p;
BOOST_FOREACH(p, m_tilesMap)
{
if (!it->first.isConsonant())
if (!p.first.isConsonant())
continue;
if (n < it->second)
return it->first;
n -= it->second;
if (n < p.second)
return p.first;
n -= p.second;
}
ASSERT(false, "We should not come here");
return Tile();
@ -169,18 +168,12 @@ void Bag::operator=(const Bag &iOther)
void Bag::dumpAll() const
{
map<Tile, int>::const_iterator it;
for (it = m_tilesMap.begin(); it != m_tilesMap.end(); it++)
std::pair<Tile, int> p;
BOOST_FOREACH(p, m_tilesMap)
{
if (it->second)
fprintf(stderr, "%lc[%i] ", it->first.toChar(), it->second);
if (p.second)
fprintf(stderr, "%lc[%i] ", p.first.toChar(), p.second);
}
fprintf(stderr, "\n");
}
/// Local Variables:
/// mode: c++
/// mode: hs-minor
/// c-basic-offset: 4
/// indent-tabs-mode: nil
/// End:

View file

@ -94,9 +94,3 @@ private:
#endif
/// Local Variables:
/// mode: c++
/// mode: hs-minor
/// c-basic-offset: 4
/// indent-tabs-mode: nil
/// End:

View file

@ -23,7 +23,6 @@
#include "dic.h"
#include "tile.h"
#include "round.h"
#include "bag.h"
#include "rack.h"
#include "results.h"
#include "board.h"
@ -254,11 +253,11 @@ void Board::removeRound(const Dictionary &iDic, const Round &iRound)
/* XXX: There is duplicated code with board_search.c.
* We could probably factorize something... */
int Board::checkRoundAux(Matrix<Tile> &iTilesMx,
Matrix<Cross> &iCrossMx,
Matrix<int> &iPointsMx,
Matrix<bool> &iJokerMx,
Round &iRound)
int Board::checkRoundAux(const Matrix<Tile> &iTilesMx,
const Matrix<Cross> &iCrossMx,
const Matrix<int> &iPointsMx,
const Matrix<bool> &iJokerMx,
Round &iRound) const
{
Tile t;
int l, p;
@ -368,7 +367,7 @@ int Board::checkRoundAux(Matrix<Tile> &iTilesMx,
}
int Board::checkRound(Round &iRound)
int Board::checkRound(Round &iRound) const
{
if (iRound.getCoord().getDir() == Coord::HORIZONTAL)
{
@ -530,9 +529,3 @@ void Board::checkDouble()
}
#endif
/// Local Variables:
/// mode: c++
/// mode: hs-minor
/// c-basic-offset: 4
/// indent-tabs-mode: nil
/// End:

View file

@ -89,7 +89,7 @@ public:
void addRound(const Dictionary &iDic, const Round &iRound);
void removeRound(const Dictionary &iDic, const Round &iRound);
int checkRound(Round &iRound);
int checkRound(Round &iRound) const;
/**
*
@ -101,8 +101,8 @@ public:
/**
* board_search.c
*/
void search(const Dictionary &iDic, const Rack &iRack, Results &oResults);
void searchFirst(const Dictionary &iDic, const Rack &iRack, Results &oResults);
void search(const Dictionary &iDic, const Rack &iRack, Results &oResults) const;
void searchFirst(const Dictionary &iDic, const Rack &iRack, Results &oResults) const;
/**
* board_cross.c
@ -143,11 +143,11 @@ private:
static const int m_tileMultipliers[BOARD_REALDIM][BOARD_REALDIM];
static const int m_wordMultipliers[BOARD_REALDIM][BOARD_REALDIM];
int checkRoundAux(Matrix<Tile> &iTilesMx,
Matrix<Cross> &iCrossMx,
Matrix<int> &iPointsMx,
Matrix<bool> &iJokerMx,
Round &iRound);
int checkRoundAux(const Matrix<Tile> &iTilesMx,
const Matrix<Cross> &iCrossMx,
const Matrix<int> &iPointsMx,
const Matrix<bool> &iJokerMx,
Round &iRound) const;
#ifdef DEBUG
void checkDouble();
#endif
@ -156,9 +156,3 @@ private:
#endif
/// Local Variables:
/// mode: c++
/// mode: hs-minor
/// c-basic-offset: 4
/// indent-tabs-mode: nil
/// End:

View file

@ -19,13 +19,6 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*****************************************************************************/
/**
* \file board_cross.cpp
* \brief Build cross information used to speed up search
* \author Antoine Fraboulet & Olivier Teulière
* \date 2005
*/
#include <wctype.h>
#include <dic.h>
@ -135,13 +128,3 @@ void Board::buildCross(const Dictionary &iDic)
Board_check(iDic, m_tilesCol, m_jokerCol, m_crossRow, m_pointRow);
}
/****************************************************************/
/****************************************************************/
/// Local Variables:
/// mode: c++
/// mode: hs-minor
/// c-basic-offset: 4
/// indent-tabs-mode: nil
/// End:

View file

@ -34,9 +34,9 @@
* the real direction of the word
*/
static void BoardSearchEvalMove(const Board &iBoard,
Matrix<Tile> &iTilesMx,
Matrix<int> &iPointsMx,
Matrix<bool> &iJokerMx,
const Matrix<Tile> &iTilesMx,
const Matrix<int> &iPointsMx,
const Matrix<bool> &iJokerMx,
Results &iResults, Round &iWord)
{
unsigned int fromrack = 0;
@ -94,10 +94,10 @@ static void BoardSearchEvalMove(const Board &iBoard,
static void ExtendRight(const Board &iBoard,
const Dictionary &iDic,
Matrix<Tile> &iTilesMx,
Matrix<Cross> &iCrossMx,
Matrix<int> &iPointsMx,
Matrix<bool> &iJokerMx,
const Matrix<Tile> &iTilesMx,
const Matrix<Cross> &iCrossMx,
const Matrix<int> &iPointsMx,
const Matrix<bool> &iJokerMx,
Rack &iRack, Round &ioPartialWord,
Results &iResults, unsigned int iNode,
int iRow, int iCol, int iAnchor)
@ -170,10 +170,10 @@ static void ExtendRight(const Board &iBoard,
static void LeftPart(const Board &iBoard,
const Dictionary &iDic,
Matrix<Tile> &iTilesMx,
Matrix<Cross> &iCrossMx,
Matrix<int> &iPointsMx,
Matrix<bool> &iJokerMx,
const Matrix<Tile> &iTilesMx,
const Matrix<Cross> &iCrossMx,
const Matrix<int> &iPointsMx,
const Matrix<bool> &iJokerMx,
Rack &iRack, Round &ioPartialWord,
Results &iResults, int n, int iRow,
int iAnchor, int iLimit)
@ -221,10 +221,10 @@ static void LeftPart(const Board &iBoard,
static void BoardSearchAux(const Board &iBoard,
const Dictionary &iDic,
Matrix<Tile> &iTilesMx,
Matrix<Cross> &iCrossMx,
Matrix<int> &iPointsMx,
Matrix<bool> &iJokerMx,
const Matrix<Tile> &iTilesMx,
const Matrix<Cross> &iCrossMx,
const Matrix<int> &iPointsMx,
const Matrix<bool> &iJokerMx,
Rack &iRack, Results &iResults,
Coord::Direction iDir)
{
@ -308,7 +308,7 @@ static void BoardSearchAux(const Board &iBoard,
void Board::search(const Dictionary &iDic,
const Rack &iRack,
Results &oResults)
Results &oResults) const
{
// Create a copy of the rack to avoid modifying the given one
Rack copyRack = iRack;
@ -325,7 +325,7 @@ void Board::search(const Dictionary &iDic,
void Board::searchFirst(const Dictionary &iDic,
const Rack &iRack,
Results &oResults)
Results &oResults) const
{
int row = 8, col = 8;
@ -342,9 +342,3 @@ void Board::searchFirst(const Dictionary &iDic,
copyRack.getNbTiles() - 1);
}
/// Local Variables:
/// mode: c++
/// mode: hs-minor
/// c-basic-offset: 4
/// indent-tabs-mode: nil
/// End:

View file

@ -19,13 +19,6 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*****************************************************************************/
/**
* \file coord.cpp
* \brief Board coordinate system
* \author Antoine Fraboulet
* \date 2005
*/
#include <string>
#include <wchar.h>
#include "coord.h"
@ -125,9 +118,3 @@ wstring Coord::toString(coord_mode_t mode) const
return res;
}
/// Local Variables:
/// mode: c++
/// mode: hs-minor
/// c-basic-offset: 4
/// indent-tabs-mode: nil
/// End:

View file

@ -19,13 +19,6 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*****************************************************************************/
/**
* \file coord.h
* \brief Board coordinates system
* \author Antoine Fraboulet
* \date 2005
*/
#ifndef _COORD_H
#define _COORD_H
@ -79,9 +72,3 @@ private:
#endif
/// Local Variables:
/// mode: c++
/// mode: hs-minor
/// c-basic-offset: 4
/// indent-tabs-mode: nil
/// End:

View file

@ -70,9 +70,3 @@ bool Cross::operator==(const Cross &iOther) const
return m_mask == iOther.m_mask;
}
/// Local Variables:
/// mode: c++
/// mode: hs-minor
/// c-basic-offset: 4
/// indent-tabs-mode: nil
/// End:

View file

@ -59,9 +59,3 @@ private:
#endif
/// Local Variables:
/// mode: c++
/// mode: hs-minor
/// c-basic-offset: 4
/// indent-tabs-mode: nil
/// End:

View file

@ -45,9 +45,3 @@
#endif
/// Local Variables:
/// mode: c++
/// mode: hs-minor
/// c-basic-offset: 4
/// indent-tabs-mode: nil
/// End:

View file

@ -19,6 +19,7 @@
*****************************************************************************/
#include "duplicate.h"
#include "game_exception.h"
#include "dic.h"
#include "tile.h"
#include "rack.h"
@ -53,12 +54,12 @@ int Duplicate::play(const wstring &iCoord, const wstring &iWord)
if (res == 0)
{
// Everything is OK, we can play the word
playMove(Move(round), m_currPlayer);
recordPlayerMove(Move(round), m_currPlayer);
}
else
{
// Record the invalid move of the player
playMove(Move(iWord, iCoord), m_currPlayer);
recordPlayerMove(Move(iWord, iCoord), m_currPlayer);
}
// Little hack to handle duplicate games with only AI players.
@ -85,7 +86,7 @@ void Duplicate::playAI(unsigned int p)
ASSERT(false, "AI tried to cheat!");
}
playMove(move, p);
recordPlayerMove(move, p);
}
@ -97,9 +98,13 @@ int Duplicate::start()
m_currPlayer = 0;
// Complete the rack for the player that just played
int res = helperSetRackRandom(m_currPlayer, true, RACK_NEW);
// End of the game?
if (res == 1)
try
{
const PlayedRack &newRack =
helperSetRackRandom(getCurrentPlayer().getCurrentRack(), true, RACK_NEW);
m_players[m_currPlayer]->setCurrentRack(newRack);
}
catch (EndGameException &e)
{
endGame();
return 1;
@ -153,12 +158,18 @@ void Duplicate::tryEndTurn()
}
void Duplicate::playMove(const Move &iMove, unsigned int p)
void Duplicate::recordPlayerMove(const Move &iMove, unsigned int p)
{
ASSERT(p < getNPlayers(), "Wrong player number");
// Get what was the rack for the current turn
Rack oldRack;
m_players[p]->getCurrentRack().getRack(oldRack);
// Compute the new rack
const Rack &newRack = helperComputeRackForMove(oldRack, iMove);
// Update the rack and the score of the playing player
m_players[p]->endTurn(iMove, m_history.getSize());
m_players[p]->endTurn(iMove, m_history.getSize(), newRack);
m_hasPlayed[p] = true;
}
@ -179,14 +190,17 @@ void Duplicate::endTurn()
// TODO: do something if nobody played a valid round!
// Get the best valid move
const Move &bestMove = m_players[imax]->getLastMove();
// Handle solo bonus
// First check whether there are enough players in the game for the
// bonus to apply
int minNbPlayers = Settings::Instance().getInt("duplicate.solo-players");
if (getNPlayers() >= (unsigned int)minNbPlayers &&
m_players[imax]->getLastMove().getType() == Move::VALID_ROUND)
bestMove.getType() == Move::VALID_ROUND)
{
int maxScore = m_players[imax]->getLastMove().getScore();
int maxScore = bestMove.getScore();
// Find whether other players than imax have the same score
bool otherWithSameScore = false;
for (unsigned int i = imax + 1; i < getNPlayers(); i++)
@ -208,7 +222,7 @@ void Duplicate::endTurn()
}
// Play the best word on the board
helperPlayMove(imax, m_players[imax]->getLastMove());
helperPlayMove(imax, bestMove);
// Leave the same reliquate to all players
// This is required by the start() method which will be called to
@ -280,9 +294,3 @@ bool Duplicate::hasPlayed(unsigned int p) const
return it != m_hasPlayed.end() && it->second;
}
/// Local Variables:
/// mode: c++
/// mode: hs-minor
/// c-basic-offset: 4
/// indent-tabs-mode: nil
/// End:

View file

@ -98,7 +98,8 @@ private:
// Private constructor to force using the GameFactory class
Duplicate(const Dictionary &iDic);
void playMove(const Move &iMove, unsigned int p);
/// Record a player move
void recordPlayerMove(const Move &iMove, unsigned int p);
/// Make the AI player whose ID is p play its turn
void playAI(unsigned int p);
@ -136,9 +137,3 @@ private:
#endif /* _DUPLICATE_H_ */
/// Local Variables:
/// mode: c++
/// mode: hs-minor
/// c-basic-offset: 4
/// indent-tabs-mode: nil
/// End:

View file

@ -18,10 +18,13 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*****************************************************************************/
#include <boost/foreach.hpp>
#include <iomanip>
#include <wctype.h>
#include "freegame.h"
#include "game_exception.h"
#include "dic.h"
#include "tile.h"
#include "rack.h"
@ -60,20 +63,14 @@ int FreeGame::play(const wstring &iCoord, const wstring &iWord)
Move move(round);
// Update the rack and the score of the current player
m_players[m_currPlayer]->endTurn(move, m_history.getSize());
// Everything is OK, we can play the word
helperPlayMove(m_currPlayer, move);
recordPlayerMove(move, m_currPlayer);
}
else
{
Move move(iWord, iCoord);
// Record the invalid move of the player
m_players[m_currPlayer]->endTurn(move, m_history.getSize());
// Update the game
helperPlayMove(m_currPlayer, move);
recordPlayerMove(move, m_currPlayer);
}
// Next turn
@ -99,13 +96,27 @@ void FreeGame::playAI(unsigned int p)
}
// Update the rack and the score of the current player
player->endTurn(move, m_history.getSize());
recordPlayerMove(move, p);
helperPlayMove(p, move);
endTurn();
}
void FreeGame::recordPlayerMove(const Move &iMove, unsigned int p)
{
ASSERT(p < getNPlayers(), "Wrong player number");
// Get what was the rack for the current turn
Rack oldRack;
m_players[p]->getCurrentRack().getRack(oldRack);
// Compute the new rack
const Rack &newRack = helperComputeRackForMove(oldRack, iMove);
// Record the invalid move of the player
m_players[p]->endTurn(iMove, m_history.getSize(), newRack);
}
int FreeGame::start()
{
ASSERT(getNPlayers(), "Cannot start a game without any player");
@ -113,7 +124,9 @@ int FreeGame::start()
// Set the initial racks of the players
for (unsigned int i = 0; i < getNPlayers(); i++)
{
helperSetRackRandom(i, false, RACK_NEW);
const PlayedRack &newRack =
helperSetRackRandom(getPlayer(i).getCurrentRack(), false, RACK_NEW);
m_players[i]->setCurrentRack(newRack);
}
m_currPlayer = 0;
@ -130,12 +143,21 @@ int FreeGame::start()
int FreeGame::endTurn()
{
const Move &move = m_players[m_currPlayer]->getLastMove();
// Update the game
helperPlayMove(m_currPlayer, move);
// Complete the rack for the player that just played
const Move &move = m_history.getPreviousTurn().getMove();
if (move.getType() == Move::VALID_ROUND ||
move.getType() == Move::CHANGE_LETTERS)
{
if (helperSetRackRandom(m_currPlayer, false, RACK_NEW) == 1)
try
{
const PlayedRack &newRack =
helperSetRackRandom(getCurrentPlayer().getCurrentRack(), false, RACK_NEW);
m_players[m_currPlayer]->setCurrentRack(newRack);
}
catch (EndGameException &e)
{
// End of the game
endGame();
@ -181,10 +203,10 @@ void FreeGame::endGame()
{
const PlayedRack &pld = m_players[i]->getCurrentRack();
pld.getAllTiles(tiles);
for (unsigned int j = 0; j < tiles.size(); j++)
BOOST_FOREACH(const Tile &tile, tiles)
{
m_players[i]->addPoints(- tiles[j].getPoints());
m_players[m_currPlayer]->addPoints(tiles[j].getPoints());
m_players[i]->addPoints(- tile.getPoints());
m_players[m_currPlayer]->addPoints(tile.getPoints());
}
}
}
@ -209,9 +231,13 @@ int FreeGame::checkPass(const wstring &iToChange, unsigned int p) const
// It is forbidden to change letters when the bag does not contain at
// least 7 letters (this is explicitly stated in the ODS). But it is
// still allowed to pass
#ifdef REAL_BAG_MODE
if (m_bag.getNbTiles() < 7 && !iToChange.empty())
#else
Bag bag(m_dic);
realBag(bag);
if (bag.getNbTiles() < 7 && !iToChange.empty())
#endif
{
return 1;
}
@ -221,14 +247,14 @@ int FreeGame::checkPass(const wstring &iToChange, unsigned int p) const
PlayedRack pld = player->getCurrentRack();
Rack rack;
pld.getRack(rack);
for (unsigned int i = 0; i < iToChange.size(); i++)
BOOST_FOREACH(wchar_t wch, iToChange)
{
// Remove the letter from the rack
if (!rack.in(Tile(iToChange[i])))
if (!rack.in(Tile(wch)))
{
return 2;
}
rack.remove(Tile(iToChange[i]));
rack.remove(Tile(wch));
}
// According to the rules in the ODS, it is allowed to pass its turn (no
@ -250,9 +276,7 @@ int FreeGame::pass(const wstring &iToChange)
Move move(iToChange);
// End the player's turn
m_players[m_currPlayer]->endTurn(move, m_history.getSize());
// Update the game
helperPlayMove(m_currPlayer, move);
recordPlayerMove(move, m_currPlayer);
// Next game turn
endTurn();
@ -260,9 +284,3 @@ int FreeGame::pass(const wstring &iToChange)
return 0;
}
/// Local Variables:
/// mode: c++
/// mode: hs-minor
/// c-basic-offset: 4
/// indent-tabs-mode: nil
/// End:

View file

@ -86,6 +86,9 @@ private:
/// Make the AI player whose ID is p play its turn
void playAI(unsigned int p);
/// Record a player move
void recordPlayerMove(const Move &iMove, unsigned int p);
/// Finish the current turn
int endTurn();
@ -101,9 +104,3 @@ private:
#endif /* _FREEGAME_H_ */
/// Local Variables:
/// mode: c++
/// mode: hs-minor
/// c-basic-offset: 4
/// indent-tabs-mode: nil
/// End:

View file

@ -19,6 +19,16 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*****************************************************************************/
#include <boost/foreach.hpp>
#if ENABLE_NLS
# include <libintl.h>
# define _(String) gettext(String)
#else
# define _(String) String
#endif
#include "dic.h"
#include "tile.h"
#include "rack.h"
@ -34,7 +44,6 @@
#include "debug.h"
const unsigned int Game::RACK_SIZE = 7;
const int Game::BONUS_POINTS = 50;
@ -50,9 +59,9 @@ Game::Game(const Dictionary &iDic):
Game::~Game()
{
for (unsigned int i = 0; i < getNPlayers(); i++)
BOOST_FOREACH(Player *p, m_players)
{
delete m_players[i];
delete p;
}
}
@ -64,11 +73,51 @@ const Player& Game::getPlayer(unsigned int iNum) const
}
Rack Game::helperComputeRackForMove(const Rack &iRack, const Move &iMove)
{
// Start from the given rack
Rack newRack = iRack;
if (iMove.getType() == Move::VALID_ROUND)
{
// Remove the played tiles from the rack
const Round &round = iMove.getRound();
for (unsigned int i = 0; i < round.getWordLen(); i++)
{
if (round.isPlayedFromRack(i))
{
if (round.isJoker(i))
newRack.remove(Tile::Joker());
else
newRack.remove(round.getTile(i));
}
}
}
else if (iMove.getType() == Move::CHANGE_LETTERS)
{
// Remove the changed tiles from the rack
const wstring & changed = iMove.getChangedLetters();
BOOST_FOREACH(wchar_t ch, changed)
{
newRack.remove(Tile(ch));
}
}
return newRack;
}
void Game::helperPlayMove(unsigned int iPlayerId, const Move &iMove)
{
// Get the original rack from the player history
const PlayedRack &oldPldRack = getPlayer(iPlayerId).getLastRack();
Rack oldRack;
oldPldRack.getRack(oldRack);
const Rack &newRack = helperComputeRackForMove(oldRack, iMove);
// History of the game
m_history.setCurrentRack(getPlayer(iPlayerId).getLastRack());
m_history.playMove(iPlayerId, m_history.getSize(), iMove);
m_history.setCurrentRack(oldPldRack);
m_history.playMove(iPlayerId, m_history.getSize(), iMove, newRack);
// Points
m_points += iMove.getScore();
@ -79,6 +128,16 @@ void Game::helperPlayMove(unsigned int iPlayerId, const Move &iMove)
{
helperPlayRound(iPlayerId, iMove.getRound());
}
#ifdef REAL_BAG_MODE
else if (iMove.getType() == Move::CHANGE_LETTERS)
{
// Put the changed letters back into the bag
BOOST_FOREACH(wchar_t ch, iMove.getChangedLetters())
{
m_bag.replaceTile(Tile(ch));
}
}
#endif
}
@ -101,6 +160,9 @@ void Game::helperPlayRound(unsigned int iPlayerId, const Round &iRound)
// Is the represented letter still available in the bag?
// XXX: this way to get the represented letter sucks...
Tile t(towupper(round.getTile(i).toChar()));
#ifdef REAL_BAG_MODE
Bag &bag = m_bag;
#else
Bag bag(m_dic);
realBag(bag);
// FIXME: realBag() does not give us a real bag in this
@ -117,15 +179,16 @@ void Game::helperPlayRound(unsigned int iPlayerId, const Round &iRound)
// the best way to fix it.
vector<Tile> tiles;
getPlayer(iPlayerId).getCurrentRack().getAllTiles(tiles);
for (unsigned int j = 0; j < tiles.size(); j++)
BOOST_FOREACH(const Tile &tile, tiles)
{
bag.replaceTile(tiles[j]);
bag.replaceTile(tile);
}
getPlayer(iPlayerId).getLastRack().getAllTiles(tiles);
for (unsigned int j = 0; j < tiles.size(); j++)
BOOST_FOREACH(const Tile &tile, tiles)
{
bag.takeTile(tiles[j]);
bag.takeTile(tile);
}
#endif
if (bag.in(t))
{
@ -142,6 +205,8 @@ void Game::helperPlayRound(unsigned int iPlayerId, const Round &iRound)
}
}
#ifdef REAL_BAG_MODE
#else
// Update the bag
// We remove tiles from the bag only when they are played
// on the board. When going back in the game, we must only
@ -161,6 +226,7 @@ void Game::helperPlayRound(unsigned int iPlayerId, const Round &iRound)
}
}
}
#endif
// Update the board
m_board.addRound(m_dic, round);
@ -211,41 +277,79 @@ void Game::shuffleRack()
m_players[currPlayer()]->setCurrentRack(pld);
}
#ifdef REAL_BAG_MODE
void Game::realBag(Bag &ioBag) const
Bag Game::getBag() const
{
vector<Tile> tiles;
Bag bag = m_bag;
// Copy the bag
ioBag = m_bag;
vector<Tile> tiles;
// The real content of the bag depends on the game mode
if (getMode() == kFREEGAME)
{
// In freegame mode, take the letters from all the racks
for (unsigned int i = 0; i < getNPlayers(); i++)
// In freegame mode, replace the letters from all the racks
BOOST_FOREACH(const Player *player, m_players)
{
getPlayer(i).getCurrentRack().getAllTiles(tiles);
for (unsigned int j = 0; j < tiles.size(); j++)
player->getCurrentRack().getAllTiles(tiles);
BOOST_FOREACH(const Tile &tile, tiles)
{
ioBag.takeTile(tiles[j]);
bag.replaceTile(tile);
}
}
}
else
{
/* In training or duplicate mode, take the rack of the current
* player only */
// In training or duplicate mode, replace the rack of the current
// player only
getPlayer(m_currPlayer).getCurrentRack().getAllTiles(tiles);
for (unsigned int j = 0; j < tiles.size(); j++)
BOOST_FOREACH(const Tile &tile, tiles)
{
ioBag.takeTile(tiles[j]);
bag.replaceTile(tile);
}
}
return bag;
}
#else
void Game::realBag(Bag &ioBag) const
{
// Copy the bag
ioBag = m_bag;
vector<Tile> tiles;
// The real content of the bag depends on the game mode
if (getMode() == kFREEGAME)
{
// In freegame mode, take the letters from all the racks
BOOST_FOREACH(const Player *player, m_players)
{
player->getCurrentRack().getAllTiles(tiles);
BOOST_FOREACH(const Tile &tile, tiles)
{
ioBag.takeTile(tile);
}
}
}
else
{
// In training or duplicate mode, take the rack of the current
// player only
getPlayer(m_currPlayer).getCurrentRack().getAllTiles(tiles);
BOOST_FOREACH(const Tile &tile, tiles)
{
ioBag.takeTile(tile);
}
}
}
#endif
int Game::helperSetRackRandom(unsigned int p, bool iCheck, set_rack_mode mode)
PlayedRack Game::helperSetRackRandom(const PlayedRack &iPld,
bool iCheck, set_rack_mode mode) const
{
ASSERT(p < getNPlayers(), "Wrong player number");
// FIXME: RACK_MANUAL shouldn't be in the enum
@ -266,24 +370,28 @@ int Game::helperSetRackRandom(unsigned int p, bool iCheck, set_rack_mode mode)
min = 1;
}
// Make a copy of the current player's rack
PlayedRack pld = getPlayer(p).getCurrentRack();
// Make a copy of the given rack
PlayedRack pld = iPld;
int nold = pld.getNbOld();
// Create a copy of the bag in which we can do everything we want,
// and take from it the tiles of the players rack so that "bag"
// contains the right number of tiles.
#ifdef REAL_BAG_MODE
Bag &bag = m_bag;
#else
Bag bag(m_dic);
realBag(bag);
#endif
if (mode == RACK_NEW && nold != 0)
{
// We may have removed too many letters from the bag (i.e. the 'new'
// letters of the player)
vector<Tile> tiles;
pld.getNewTiles(tiles);
for (unsigned int i = 0; i < tiles.size(); i++)
BOOST_FOREACH(const Tile &tile, tiles)
{
bag.replaceTile(tiles[i]);
bag.replaceTile(tile);
}
pld.resetNew();
}
@ -292,9 +400,9 @@ int Game::helperSetRackRandom(unsigned int p, bool iCheck, set_rack_mode mode)
// Replace all the tiles in the bag before choosing random ones
vector<Tile> tiles;
pld.getAllTiles(tiles);
for (unsigned int i = 0; i < tiles.size(); i++)
BOOST_FOREACH(const Tile &tile, tiles)
{
bag.replaceTile(tiles[i]);
bag.replaceTile(tile);
}
// RACK_NEW with an empty rack is equivalent to RACK_ALL
pld.reset();
@ -318,9 +426,9 @@ int Game::helperSetRackRandom(unsigned int p, bool iCheck, set_rack_mode mode)
{
// 1) Is there already a joker in the remaining letters of the rack?
bool jokerFound = false;
for (unsigned int i = 0; i < tiles.size(); i++)
BOOST_FOREACH(const Tile &tile, tiles)
{
if (tiles[i].isJoker())
if (tile.isJoker())
{
jokerFound = true;
break;
@ -346,34 +454,35 @@ int Game::helperSetRackRandom(unsigned int p, bool iCheck, set_rack_mode mode)
// (i.e. minimum required, minus what we already have in the rack)
unsigned int neededVowels = min;
unsigned int neededConsonants = min;
for (unsigned int i = 0; i < tiles.size(); ++i)
BOOST_FOREACH(const Tile &tile, tiles)
{
if (neededVowels > 0 && tiles[i].isVowel())
if (neededVowels > 0 && tile.isVowel())
neededVowels--;
if (neededConsonants > 0 && tiles[i].isConsonant())
if (neededConsonants > 0 && tile.isConsonant())
neededConsonants--;
}
// Nothing in the rack, nothing in the bag --> end of the (free)game
if (bag.getNbTiles() == 0 && pld.getNbTiles() == 0)
{
return 1;
throw EndGameException(_("The bag is empty"));
}
// Check whether it is possible to complete the rack properly
if (bag.getNbVowels() < neededVowels ||
bag.getNbConsonants() < neededConsonants)
{
return 1;
throw EndGameException(_("Not enough vowels or consonants to complete the rack"));
}
// End of game condition
if (iCheck)
{
// FIXME: redundant checks?
if (bag.getNbVowels() < neededVowels ||
bag.getNbConsonants() < neededConsonants ||
(bag.getNbTiles() + tiles.size()) == 1)
{
return 1;
throw EndGameException(_("Not enough vowels or consonants to complete the rack"));
}
}
@ -386,7 +495,7 @@ int Game::helperSetRackRandom(unsigned int p, bool iCheck, set_rack_mode mode)
// requirements will be met.
while (bag.getNbTiles() != 0 && pld.getNbTiles() < RACK_SIZE)
{
Tile l = bag.selectRandom();
const Tile &l = bag.selectRandom();
bag.takeTile(l);
pld.addNew(l);
}
@ -396,9 +505,9 @@ int Game::helperSetRackRandom(unsigned int p, bool iCheck, set_rack_mode mode)
// Bad luck... we have to reject the rack
vector<Tile> rejectedTiles;
pld.getAllTiles(rejectedTiles);
for (unsigned int i = 0; i < rejectedTiles.size(); i++)
BOOST_FOREACH(const Tile &rejTile, rejectedTiles)
{
bag.replaceTile(rejectedTiles[i]);
bag.replaceTile(rejTile);
}
pld.reset();
// Do not mark the rack as rejected if it was empty
@ -420,13 +529,13 @@ int Game::helperSetRackRandom(unsigned int p, bool iCheck, set_rack_mode mode)
// Actually this should never happen, but it doesn't hurt to check...
// FIXME: this test is not completely right, because it supposes no
// letter can be at the same time a vowel and a consonant
return 3;
throw EndGameException("Not enough vowels or consonants to complete the rack");
}
// Get the required vowels and consonants first
for (unsigned int i = 0; i < neededVowels; ++i)
{
Tile l = bag.selectRandomVowel();
const Tile &l = bag.selectRandomVowel();
bag.takeTile(l);
pld.addNew(l);
// Handle the case where the vowel can also be considered
@ -436,7 +545,7 @@ int Game::helperSetRackRandom(unsigned int p, bool iCheck, set_rack_mode mode)
}
for (unsigned int i = 0; i < neededConsonants; ++i)
{
Tile l = bag.selectRandomConsonant();
const Tile &l = bag.selectRandomConsonant();
bag.takeTile(l);
pld.addNew(l);
}
@ -447,7 +556,7 @@ int Game::helperSetRackRandom(unsigned int p, bool iCheck, set_rack_mode mode)
// Now complete the rack with truly random letters
while (bag.getNbTiles() != 0 && pld.getNbTiles() < RACK_SIZE)
{
Tile l = bag.selectRandom();
const Tile &l = bag.selectRandom();
bag.takeTile(l);
pld.addNew(l);
}
@ -461,21 +570,21 @@ int Game::helperSetRackRandom(unsigned int p, bool iCheck, set_rack_mode mode)
// Post-condition check. This should never fail, of course :)
ASSERT(pld.checkRack(min, min), "helperSetRackRandom() is buggy!");
#if 0
// Until now we didn't modify anything except local variables.
// Let's "commit" the changes
m_players[p]->setCurrentRack(pld);
#endif
return 0;
return pld;
}
bool Game::rackInBag(const Rack &iRack, const Bag &iBag) const
{
const vector<Tile>& allTiles = m_dic.getAllTiles();
vector<Tile>::const_iterator it;
for (it = allTiles.begin(); it != allTiles.end(); it++)
BOOST_FOREACH(const Tile &t, m_dic.getAllTiles())
{
if (iRack.in(*it) > iBag.in(*it))
if (iRack.in(t) > iBag.in(t))
return false;
}
return true;
@ -492,13 +601,21 @@ int Game::helperSetRackManual(unsigned int p, bool iCheck, const wstring &iLette
PlayedRack pld;
pld.setManual(iLetters);
#ifdef REAL_BAG_MODE
vector<Tile> allTiles;
m_players[p]->getCurrentRack().getAllTiles(allTiles);
BOOST_FOREACH(const Tile &tile, allTiles)
{
m_bag.replaceTile(tile);
}
#else
Rack rack;
pld.getRack(rack);
if (!rackInBag(rack, m_bag))
{
pld.reset();
return 1;
}
#endif
if (iCheck)
{
@ -509,9 +626,27 @@ int Game::helperSetRackManual(unsigned int p, bool iCheck, const wstring &iLette
else
min = 1;
if (!pld.checkRack(min, min))
{
#ifdef REAL_BAG_MODE
// Changing the rack failed, so we restore the tiles we
// just removed
BOOST_FOREACH(const Tile &tile, allTiles)
{
m_bag.takeTile(tile);
}
#endif
return 2;
}
}
#ifdef REAL_BAG_MODE
pld.getAllTiles(allTiles);
BOOST_FOREACH(const Tile &tile, allTiles)
{
m_bag.takeTile(tile);
}
#endif
m_players[p]->setCurrentRack(pld);
return 0;
@ -524,8 +659,10 @@ int Game::helperSetRackManual(unsigned int p, bool iCheck, const wstring &iLette
unsigned int Game::getNHumanPlayers() const
{
unsigned int count = 0;
for (unsigned int i = 0; i < getNPlayers(); i++)
count += (getPlayer(i).isHuman() ? 1 : 0);
BOOST_FOREACH(const Player *player, m_players)
{
count += (player->isHuman() ? 1 : 0);
}
return count;
}
@ -563,7 +700,7 @@ void Game::nextPlayer()
int Game::checkPlayedWord(const wstring &iCoord,
const wstring &iWord, Round &oRound)
const wstring &iWord, Round &oRound) const
{
ASSERT(getNPlayers() != 0, "Expected at least one player");
@ -634,12 +771,3 @@ int Game::checkPlayedWord(const wstring &iCoord,
return 0;
}
/****************************************************************/
/****************************************************************/
/// Local Variables:
/// mode: c++
/// mode: hs-minor
/// c-basic-offset: 4
/// indent-tabs-mode: nil
/// End:

View file

@ -98,7 +98,11 @@ public:
/// Get the board
const Board& getBoard() const { return m_board; }
/// Get the bag
#ifdef REAL_BAG_MODE
Bag getBag() const;
#else
const Bag& getBag() const { return m_bag; }
#endif
/// Get the history of the game */
const History& getHistory() const { return m_history; }
@ -217,15 +221,14 @@ protected:
/// Dictionary currently associated to the game
const Dictionary & m_dic;
/// Bag
Bag m_bag;
/// Board
Board m_board;
/// Bag
Bag m_bag;
/**
* History of the game.
* The vector is indexed by the number of turns in the game
*/
History m_history;
@ -237,16 +240,18 @@ protected:
* Helper functions
*********************************************************/
/**
* Return the rack obtained from the given one, after playing the
* given move.
* The move is supposed to be possible for the given rack.
*/
static Rack helperComputeRackForMove(const Rack &iOldRack, const Move &iMove);
/** Play a Move for the given player, updating game history */
void helperPlayMove(unsigned int iPlayerId, const Move &iMove);
/**
* Set the rack randomly for the player p
* Possible return values:
* 0: everything went fine
* 1: the game is over
* 3: there is no chance to set the rack with the vowels/consonants
* constraints
* Complete the given rack randomly.
*
* Completing a rack randomly is more complex than it seems, because we
* must take into account several constraints:
@ -266,7 +271,8 @@ protected:
* This also means we have to check whether completing the rack with the
* requirements is possible...
*/
int helperSetRackRandom(unsigned int p, bool iCheck, set_rack_mode mode);
PlayedRack helperSetRackRandom(const PlayedRack &iPld,
bool iCheck, set_rack_mode mode) const;
/**
* Set the rack for the player p with the given letters
@ -292,6 +298,8 @@ protected:
*/
bool rackInBag(const Rack &iRack, const Bag &iBag) const;
#ifdef REAL_BAG_MODE
#else
/**
* The realBag is the current bag minus all the racks
* present in the game. It represents the actual
@ -301,6 +309,7 @@ protected:
* it is important to set m_currPlayer accurately before!
*/
void realBag(Bag &iBag) const;
#endif
/**
* This function checks whether it is legal to play the given word at the
@ -309,7 +318,7 @@ protected:
* Possible return values: same as the play() method
*/
int checkPlayedWord(const wstring &iCoord,
const wstring &iWord, Round &oRound);
const wstring &iWord, Round &oRound) const;
/**
* load games from File using the first format.
@ -345,9 +354,3 @@ private:
#endif /* _GAME_H_ */
/// Local Variables:
/// mode: c++
/// mode: hs-minor
/// c-basic-offset: 4
/// indent-tabs-mode: nil
/// End:

View file

@ -34,3 +34,9 @@ const char *GameException::what() const throw()
return m_message.c_str();
}
EndGameException::EndGameException(const string &iMessage)
: GameException(iMessage)
{
}

View file

@ -42,4 +42,10 @@ class GameException: public std::exception
};
class EndGameException: public GameException
{
public:
EndGameException(const std::string &iMessage);
};
#endif

View file

@ -269,10 +269,3 @@ void GameFactory::printVersion() const
<< "see the file named COPYING for details." << endl;
}
/// Local Variables:
/// mode: c++
/// mode: hs-minor
/// c-basic-offset: 4
/// indent-tabs-mode: nil
/// End:

View file

@ -107,9 +107,3 @@ private:
#endif // _GAME_FACTORY_H_
/// Local Variables:
/// mode: c++
/// mode: hs-minor
/// c-basic-offset: 4
/// indent-tabs-mode: nil
/// End:

View file

@ -124,8 +124,7 @@ Game* Game::gameLoadFormat_14(FILE *fin, const Dictionary& iDic)
/* rack */
strncpy(rack, token, sizeof(rack));
static_cast<Training*>(pGame)->setRack(RACK_MANUAL, false,
convertToWc(rack));
static_cast<Training*>(pGame)->setRackManual(false, convertToWc(rack));
/* word */
token = strtok(NULL, delim);
@ -601,9 +600,3 @@ void Game::gameSaveFormat_15(ostream &out) const
}
}
/// Local Variables:
/// mode: c++
/// mode: hs-minor
/// c-basic-offset: 4
/// indent-tabs-mode: nil
/// End:

View file

@ -19,12 +19,7 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*****************************************************************************/
/**
* \file history.cpp
* \brief Game history system
* \author Antoine Fraboulet
* \date 2005
*/
#include <boost/foreach.hpp>
#include <string>
#include "rack.h"
@ -36,11 +31,6 @@
#include "debug.h"
/* ******************************************************** */
/* ******************************************************** */
/* ******************************************************** */
History::History()
{
Turn* t = new Turn();
@ -51,9 +41,9 @@ History::History()
History::~History()
{
for (unsigned int i = 0; i < m_history.size(); i++)
BOOST_FOREACH(Turn *turn, m_history)
{
delete m_history[i];
delete turn;
}
}
@ -103,7 +93,8 @@ bool History::beforeFirstRound() const
}
void History::playMove(unsigned int iPlayer, unsigned int iTurn, const Move &iMove)
void History::playMove(unsigned int iPlayer, unsigned int iTurn,
const Move &iMove, const Rack &iNewRack)
{
Turn * current_turn = m_history.back();
@ -112,39 +103,10 @@ void History::playMove(unsigned int iPlayer, unsigned int iTurn, const Move &iMo
current_turn->setPlayer(iPlayer);
current_turn->setMove(iMove);
// Get what was the rack for the current turn
Rack rack;
current_turn->getPlayedRack().getRack(rack);
if (iMove.getType() == Move::VALID_ROUND)
{
// Remove the played tiles from the rack
const Round &round = iMove.getRound();
for (unsigned int i = 0; i < round.getWordLen(); i++)
{
if (round.isPlayedFromRack(i))
{
if (round.isJoker(i))
rack.remove(Tile::Joker());
else
rack.remove(round.getTile(i));
}
}
}
else if (iMove.getType() == Move::CHANGE_LETTERS)
{
// Remove the changed tiles from the rack
const wstring & changed = iMove.getChangedLetters();
for (unsigned int i = 0; i < changed.size(); ++i)
{
rack.remove(Tile(changed[i]));
}
}
// Create a new turn
Turn * next_turn = new Turn();
PlayedRack pldrack;
pldrack.setOld(rack);
pldrack.setOld(iNewRack);
next_turn->setPlayedRack(pldrack);
m_history.push_back(next_turn);
}
@ -181,22 +143,10 @@ wstring History::toString() const
_swprintf(buff, 4, L"%ld", m_history.size());
rs = L"history size = " + wstring(buff) + L"\n\n";
#endif
for (unsigned int i = 0; i < m_history.size(); i++)
BOOST_FOREACH(const Turn *turn, m_history)
{
Turn *t = m_history[i];
rs += t->toString() + L"\n";
rs += turn->toString() + L"\n";
}
return rs;
}
/* ******************************************************** */
/* ******************************************************** */
/* ******************************************************** */
/// Local Variables:
/// mode: c++
/// mode: hs-minor
/// c-basic-offset: 4
/// indent-tabs-mode: nil
/// End:

View file

@ -19,13 +19,6 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*****************************************************************************/
/**
* \file history.h
* \brief Game history system
* \author Antoine Fraboulet
* \date 2005
*/
#ifndef _HISTORY_H
#define _HISTORY_H
@ -91,7 +84,8 @@ class History
* A new turn is created with the unplayed letters in the rack
* 03 sept 2000: We have to sort the tiles according to the new rules
*/
void playMove(unsigned int player, unsigned int turn, const Move &iMove);
void playMove(unsigned int player, unsigned int turn,
const Move &iMove, const Rack &iNewRack);
/// Remove last turn
void removeLastTurn();
@ -105,9 +99,3 @@ class History
#endif
/// Local Variables:
/// mode: c++
/// mode: hs-minor
/// c-basic-offset: 4
/// indent-tabs-mode: nil
/// End:

View file

@ -63,10 +63,10 @@ const Move & Player::getLastMove() const
}
void Player::endTurn(const Move &iMove, unsigned int iTurn)
void Player::endTurn(const Move &iMove, unsigned int iTurn, const Rack &iNewRack)
{
addPoints(iMove.getScore());
m_history.playMove(m_id, iTurn, iMove);
m_history.playMove(m_id, iTurn, iMove, iNewRack);
}
void Player::removeLastTurn()
@ -89,12 +89,3 @@ wstring Player::toString() const
return res;
}
/****************************************************************/
/****************************************************************/
/// Local Variables:
/// mode: c++
/// mode: hs-minor
/// c-basic-offset: 4
/// indent-tabs-mode: nil
/// End:

View file

@ -30,6 +30,7 @@
using std::wstring;
class Turn;
class Rack;
/**
@ -84,7 +85,7 @@ public:
* The score of the player is updated with the one of the move, if it is
* meaningful.
*/
void endTurn(const Move &iMove, unsigned int iTurn);
void endTurn(const Move &iMove, unsigned int iTurn, const Rack &iNewRack);
wstring toString() const;
@ -118,9 +119,3 @@ public:
#endif
/// Local Variables:
/// mode: c++
/// mode: hs-minor
/// c-basic-offset: 4
/// indent-tabs-mode: nil
/// End:

View file

@ -19,12 +19,7 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*****************************************************************************/
/**
* \file pldrack.cpp
* \brief Improved Rack class with old and new tiles
* \author Antoine Fraboulet & Olivier Teuliere
* \date 2002 - 2005
*/
#include <boost/foreach.hpp>
#include <algorithm>
#include "pldrack.h"
@ -87,33 +82,30 @@ void PlayedRack::resetNew()
void PlayedRack::getOld(Rack &oRack) const
{
vector<Tile>::const_iterator it;
oRack.clear();
for (it = m_oldTiles.begin(); it != m_oldTiles.end(); it++)
BOOST_FOREACH(const Tile &tile, m_oldTiles)
{
oRack.add(*it);
oRack.add(tile);
}
}
void PlayedRack::getNew(Rack &oRack) const
{
vector<Tile>::const_iterator it;
oRack.clear();
for (it = m_newTiles.begin(); it != m_newTiles.end(); it++)
BOOST_FOREACH(const Tile &tile, m_newTiles)
{
oRack.add(*it);
oRack.add(tile);
}
}
void PlayedRack::getRack(Rack &oRack) const
{
vector<Tile>::const_iterator it;
getOld(oRack);
for (it = m_newTiles.begin(); it != m_newTiles.end(); it++)
BOOST_FOREACH(const Tile &tile, m_newTiles)
{
oRack.add(*it);
oRack.add(tile);
}
}
@ -168,19 +160,18 @@ void PlayedRack::setManual(const wstring& iLetters)
bool PlayedRack::checkRack(unsigned int cMin, unsigned int vMin) const
{
vector<Tile>::const_iterator it;
unsigned int v = 0;
unsigned int c = 0;
for (it = m_oldTiles.begin(); it != m_oldTiles.end(); it++)
BOOST_FOREACH(const Tile &tile, m_oldTiles)
{
if (it->isVowel()) v++;
if (it->isConsonant()) c++;
if (tile.isVowel()) v++;
if (tile.isConsonant()) c++;
}
for (it = m_newTiles.begin(); it != m_newTiles.end(); it++)
BOOST_FOREACH(const Tile &tile, m_newTiles)
{
if (it->isVowel()) v++;
if (it->isConsonant()) c++;
if (tile.isVowel()) v++;
if (tile.isConsonant()) c++;
}
return (v >= vMin) && (c >= cMin);
}
@ -204,17 +195,15 @@ void PlayedRack::shuffle()
wstring PlayedRack::toString(display_mode mode) const
{
wstring s;
vector<Tile>::const_iterator it;
if (mode >= RACK_EXTRA && m_reject)
{
s += L"-";
}
if (getNbOld() > 0)
BOOST_FOREACH(const Tile &tile, m_oldTiles)
{
for (it = m_oldTiles.begin(); it != m_oldTiles.end(); it++)
s += it->toChar();
s += tile.toChar();
}
if (mode > RACK_SIMPLE && getNbOld() > 0 && getNbNew() > 0)
@ -222,18 +211,11 @@ wstring PlayedRack::toString(display_mode mode) const
s += L"+";
}
if (getNbNew() > 0)
BOOST_FOREACH(const Tile &tile, m_newTiles)
{
for (it = m_newTiles.begin(); it != m_newTiles.end(); it++)
s += it->toChar();
s += tile.toChar();
}
return s;
}
/// Local Variables:
/// mode: c++
/// mode: hs-minor
/// c-basic-offset: 4
/// indent-tabs-mode: nil
/// End:

View file

@ -19,13 +19,6 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*****************************************************************************/
/**
* \file pldrack.h
* \brief Improved Rack class with old and new tiles
* \author Antoine Fraboulet & Olivier Teuliere
* \date 2002 - 2005
*/
#ifndef _PLAYEDRACK_H_
#define _PLAYEDRACK_H_
@ -94,9 +87,3 @@ private:
#endif
/// Local Variables:
/// mode: c++
/// mode: hs-minor
/// c-basic-offset: 4
/// indent-tabs-mode: nil
/// End:

View file

@ -19,13 +19,6 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*****************************************************************************/
/**
* \file rack.cpp
* \brief Rack class : multiset of tiles
* \author Antoine Fraboulet & Olivier Teuliere
* \date 2002 - 2007
*/
#include "rack.h"
#include "dic.h"
#include "encoding.h"
@ -79,9 +72,3 @@ wstring Rack::toString() const
return rs;
}
/// Local Variables:
/// mode: c++
/// mode: hs-minor
/// c-basic-offset: 4
/// indent-tabs-mode: nil
/// End:

View file

@ -19,13 +19,6 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*****************************************************************************/
/**
* \file rack.h
* \brief Rack class : multiset of tiles
* \author Antoine Fraboulet & Olivier Teuliere
* \date 2002 - 2007
*/
#ifndef _RACK_H_
#define _RACK_H_
@ -65,9 +58,3 @@ private:
#endif
/// Local Variables:
/// mode: c++
/// mode: hs-minor
/// c-basic-offset: 4
/// indent-tabs-mode: nil
/// End:

View file

@ -19,13 +19,6 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*****************************************************************************/
/**
* \file results.cc
* \brief Search result storage class
* \author Olivier Teulière & Antoine Fraboulet
* \date 2005
*/
#include <algorithm>
#include <functional>
#include <cwctype>
@ -129,12 +122,3 @@ void Results::sortByPoints()
std::sort(m_rounds.begin(), m_rounds.end(), lp);
}
/****************************************************************/
/****************************************************************/
/// Local Variables:
/// mode: c++
/// mode: hs-minor
/// c-basic-offset: 4
/// indent-tabs-mode: nil
/// End:

View file

@ -19,13 +19,6 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*****************************************************************************/
/**
* \file results.h
* \brief Search result storage class
* \author Olivier Teulière & Antoine Fraboulet
* \date 2005
*/
#ifndef _RESULTS_H_
#define _RESULTS_H_
@ -68,12 +61,3 @@ private:
#endif
/****************************************************************/
/****************************************************************/
/// Local Variables:
/// mode: c++
/// mode: hs-minor
/// c-basic-offset: 4
/// indent-tabs-mode: nil
/// End:

View file

@ -167,9 +167,3 @@ wstring Round::toString() const
return rs;
}
/// Local Variables:
/// mode: c++
/// mode: hs-minor
/// c-basic-offset: 4
/// indent-tabs-mode: nil
/// End:

View file

@ -95,9 +95,3 @@ private:
#endif
/// Local Variables:
/// mode: c++
/// mode: hs-minor
/// c-basic-offset: 4
/// indent-tabs-mode: nil
/// End:

View file

@ -78,9 +78,3 @@ private:
#endif
/// Local Variables:
/// mode: c++
/// mode: hs-minor
/// c-basic-offset: 4
/// indent-tabs-mode: nil
/// End:

View file

@ -50,10 +50,12 @@ Training::Training(const Dictionary &iDic)
}
int Training::setRackRandom(bool iCheck, set_rack_mode mode)
void Training::setRackRandom(bool iCheck, set_rack_mode mode)
{
m_results.clear();
return helperSetRackRandom(m_currPlayer, iCheck, mode);
const PlayedRack &newRack =
helperSetRackRandom(getCurrentPlayer().getCurrentRack(), iCheck, mode);
m_players[m_currPlayer]->setCurrentRack(newRack);
}
@ -86,10 +88,10 @@ int Training::setRack(set_rack_mode iMode, bool iCheck, const wstring &iLetters)
res = setRackManual(iCheck, iLetters);
break;
case RACK_ALL:
res = setRackRandom(iCheck, iMode);
setRackRandom(iCheck, iMode);
break;
case RACK_NEW:
res = setRackRandom(iCheck, iMode);
setRackRandom(iCheck, iMode);
break;
}
return res;
@ -109,12 +111,10 @@ int Training::play(const wstring &iCoord, const wstring &iWord)
Move move(round);
// Update the rack and the score of the current player
// Player::endTurn() must be called before Game::helperPlayMove().
// Player::endTurn() must be called before Game::helperPlayMove()
// (called here in endTurn()).
// See the big comment in game.cpp, line 96
m_players[m_currPlayer]->endTurn(move, m_history.getSize());
// Everything is OK, we can play the word
helperPlayMove(m_currPlayer, move);
recordPlayerMove(move, m_currPlayer);
// Next turn
endTurn();
@ -123,6 +123,21 @@ int Training::play(const wstring &iCoord, const wstring &iWord)
}
void Training::recordPlayerMove(const Move &iMove, unsigned int p)
{
ASSERT(p < getNPlayers(), "Wrong player number");
// Get what was the rack for the current turn
Rack oldRack;
m_players[p]->getCurrentRack().getRack(oldRack);
// Compute the new rack
const Rack &newRack = helperComputeRackForMove(oldRack, iMove);
// Record the invalid move of the player
m_players[p]->endTurn(iMove, m_history.getSize(), newRack);
}
int Training::start()
{
if (getNPlayers() != 0)
@ -135,7 +150,11 @@ int Training::start()
void Training::endTurn()
{
// Nothing to do, but this method is kept for consistency with other modes
m_results.clear();
// Play the word on the board
const Move &move = m_players[m_currPlayer]->getLastMove();
helperPlayMove(m_currPlayer, move);
}
@ -155,11 +174,7 @@ int Training::playResult(unsigned int n)
Move move(m_results.get(n));
// Update the rack and the score of the current player
m_players[m_currPlayer]->endTurn(move, m_history.getSize());
// Update the game
helperPlayMove(m_currPlayer, move);
m_results.clear();
recordPlayerMove(move, m_currPlayer);
// Next turn
endTurn();
@ -196,12 +211,3 @@ wstring Training::getTestPlayWord() const
return m_testRound.getWord();
}
/****************************************************************/
/****************************************************************/
/// Local Variables:
/// mode: c++
/// mode: hs-minor
/// c-basic-offset: 4
/// indent-tabs-mode: nil
/// End:

View file

@ -59,8 +59,18 @@ public:
const Results& getResults() const { return m_results; };
int playResult(unsigned int);
int setRackRandom(bool, set_rack_mode);
/**
* Complete (or reset) the rack randomly.
* @exception EndGameException if it is impossible to complete the rack
* for some reason...
*/
void setRackRandom(bool, set_rack_mode);
int setRackManual(bool iCheck, const wstring &iLetters);
/**
* @Deprecated: use setRackRandom() or setRackManual() instead.
*/
int setRack(set_rack_mode iMode, bool iCheck, const wstring &iLetters);
/*************************
@ -85,6 +95,9 @@ private:
/// Private constructor and destructor to force using the GameFactory class
Training(const Dictionary &iDic);
/// Record a player move
void recordPlayerMove(const Move &iMove, unsigned int p);
void endTurn();
/// Search results, with all the possible rounds
@ -96,9 +109,3 @@ private:
#endif /* _TRAINING_H_ */
/// Local Variables:
/// mode: c++
/// mode: hs-minor
/// c-basic-offset: 4
/// indent-tabs-mode: nil
/// End:

View file

@ -19,13 +19,6 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*****************************************************************************/
/**
* \file turn.cpp
* \brief Game turn (= id + pldrack + move)
* \author Antoine Fraboulet
* \date 2005
*/
#include "turn.h"
@ -55,9 +48,3 @@ wstring Turn::toString(bool iShowExtraSigns) const
return rs;
}
/// Local Variables:
/// mode: c++
/// mode: hs-minor
/// c-basic-offset: 4
/// indent-tabs-mode: nil
/// End:

View file

@ -19,13 +19,6 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*****************************************************************************/
/**
* \file turn.h
* \brief Game turn (= id + pldrack + move)
* \author Antoine Fraboulet
* \date 2005
*/
#ifndef _TURN_H
#define _TURN_H
@ -72,9 +65,3 @@ private:
#endif
/// Local Variables:
/// mode: c++
/// mode: hs-minor
/// c-basic-offset: 4
/// indent-tabs-mode: nil
/// End:

View file

@ -18,6 +18,7 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*****************************************************************************/
#include <boost/foreach.hpp>
#include <vector>
#include <QtGui/QTreeView>
#include <QtGui/QStandardItemModel>
@ -72,18 +73,17 @@ void BagWidget::updateModel()
if (m_game == NULL)
return;
const vector<Tile>& allTiles = m_game->getDic().getAllTiles();
vector<Tile>::const_iterator it;
for (it = allTiles.begin(); it != allTiles.end(); ++it)
const Bag &bag = m_game->getBag();
BOOST_FOREACH(const Tile &tile, m_game->getDic().getAllTiles())
{
unsigned int nb = m_game->getBag().in(*it);
unsigned int nb = bag.in(tile);
if (nb != 0)
{
int rowNum = m_model->rowCount();
m_model->insertRow(rowNum);
m_model->setData(m_model->index(rowNum, 0),
qfw(wstring(nb, it->toChar())));
m_model->setData(m_model->index(rowNum, 1), it->getPoints());
qfw(wstring(nb, tile.toChar())));
m_model->setData(m_model->index(rowNum, 1), tile.getPoints());
}
}
//resizeColumnToContents(0);

View file

@ -25,6 +25,7 @@
#include "qtcommon.h"
#include "dic.h"
#include "game.h"
#include "game_exception.h"
#include "training.h"
#include "player.h"
#include "results.h"
@ -204,8 +205,15 @@ void TrainingWidget::on_pushButtonRack_clicked()
{
// FIXME: first parameter is hardcoded
m_game->removeTestPlay();
m_game->setRackRandom(true, Game::RACK_ALL);
emit gameUpdated();
try
{
m_game->setRackRandom(true, Game::RACK_ALL);
emit gameUpdated();
}
catch (GameException &e)
{
emit notifyProblem(e.what());
}
}
@ -213,8 +221,15 @@ void TrainingWidget::on_pushButtonComplement_clicked()
{
// FIXME: first parameter is hardcoded
m_game->removeTestPlay();
m_game->setRackRandom(true, Game::RACK_NEW);
emit gameUpdated();
try
{
m_game->setRackRandom(true, Game::RACK_NEW);
emit gameUpdated();
}
catch (GameException &e)
{
emit notifyProblem(e.what());
}
}

View file

@ -18,6 +18,8 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*****************************************************************************/
#include <boost/foreach.hpp>
#include <iomanip>
#include <string>
#include <stdlib.h>
@ -178,20 +180,18 @@ void GameIO::printBoardMultipliers2(ostream &out, const Game &iGame)
void GameIO::printNonPlayed(ostream &out, const Game &iGame)
{
const vector<Tile>& allTiles = iGame.getDic().getAllTiles();
vector<Tile>::const_iterator it;
for (it = allTiles.begin(); it != allTiles.end(); it++)
const Bag &bag = iGame.getBag();
BOOST_FOREACH(const Tile &tile, iGame.getDic().getAllTiles())
{
if (iGame.getBag().in(*it) > 9)
if (bag.in(tile) > 9)
out << " ";
out << setw(2) << convertToMb(it->toChar());
out << setw(2) << convertToMb(tile.toChar());
}
out << endl;
for (it = allTiles.begin(); it != allTiles.end(); it++)
BOOST_FOREACH(const Tile &tile, iGame.getDic().getAllTiles())
{
out << " " << iGame.getBag().in(*it);
out << " " << bag.in(tile);
}
out << endl;
}