Topping: keep track of the player score

This commit is contained in:
Olivier Teulière 2013-01-11 20:24:47 +01:00
parent 0ea56cc442
commit 7e9dab2e9b
6 changed files with 104 additions and 20 deletions

View file

@ -31,10 +31,11 @@ INIT_LOGGER(game, PlayerEventCmd);
PlayerEventCmd::PlayerEventCmd(Player &ioPlayer, EventType iEvent, int iPoints) PlayerEventCmd::PlayerEventCmd(Player &ioPlayer, EventType iEvent, int iPoints)
: m_player(ioPlayer), m_eventType(iEvent), m_points(iPoints) : m_player(ioPlayer), m_eventType(iEvent), m_points(iPoints)
{ {
ASSERT(iEvent == PENALTY || iEvent == END_GAME || iPoints >= 0, // Solos and warnings are always positive
"Negative points not allowed"); ASSERT(iEvent != SOLO || iPoints >= 0, "Negative points not allowed");
ASSERT(iEvent != PENALTY || iPoints <= 0, ASSERT(iEvent != WARNING || iPoints >= 0, "Negative points not allowed");
"Positive points not allowed"); // Penalties are negative in arbitration mode, but positive in topping mode
// End game points are positive for one player and negative for all the other players
} }

View file

@ -262,6 +262,18 @@ void PublicGame::toppingPlay(const wstring &iWord, const wstring &iCoord, int iE
} }
void PublicGame::toppingTimeOut()
{
getTypedGame<Topping>(m_game).turnTimeOut();
}
void PublicGame::toppingAddPenalty(int iPenalty)
{
getTypedGame<Topping>(m_game).addPenalty(iPenalty);
}
vector<Move> PublicGame::toppingGetTriedMoves() const vector<Move> PublicGame::toppingGetTriedMoves() const
{ {
return getTypedGame<Topping>(m_game).getTriedMoves(); return getTypedGame<Topping>(m_game).getTriedMoves();

View file

@ -226,6 +226,10 @@ public:
void toppingPlay(const wstring &iWord, const wstring &iCoord, int iElapsed); void toppingPlay(const wstring &iWord, const wstring &iCoord, int iElapsed);
void toppingTimeOut();
void toppingAddPenalty(int iPenalty);
vector<Move> toppingGetTriedMoves() const; vector<Move> toppingGetTriedMoves() const;
Move toppingGetTopMove() const; Move toppingGetTopMove() const;

View file

@ -38,7 +38,9 @@
#include "player.h" #include "player.h"
#include "turn.h" #include "turn.h"
#include "cmd/topping_move_cmd.h" #include "cmd/topping_move_cmd.h"
#include "cmd/player_rack_cmd.h"
#include "cmd/player_move_cmd.h" #include "cmd/player_move_cmd.h"
#include "cmd/player_event_cmd.h"
#include "cmd/game_move_cmd.h" #include "cmd/game_move_cmd.h"
#include "encoding.h" #include "encoding.h"
@ -105,8 +107,7 @@ void Topping::tryWord(const wstring &iWord, const wstring &iCoord, int iElapsed)
else else
{ {
// End the turn // End the turn
// FIXME recordPlayerMove(move, *m_players[m_currPlayer], iElapsed);
recordPlayerMove(move, *m_players[m_currPlayer]);
// Next turn // Next turn
endTurn(); endTurn();
@ -114,6 +115,38 @@ void Topping::tryWord(const wstring &iWord, const wstring &iCoord, int iElapsed)
} }
void Topping::turnTimeOut()
{
LOG_INFO("Timeout reached, finishing turn automatically");
m_board.removeTestRound();
// Commented out, because the player already has
// an empty move by default
#if 0
// The player didn't find the move
Command *pCmd = new PlayerMoveCmd(*m_players[m_currPlayer], Move());
accessNavigation().addAndExecute(pCmd);
#endif
// Give a penalty to the player
// XXX: should we give the penalty directly in the NO_MOVE move?
// TODO: get the value from the preferences instead of hard-coding
addPenalty(180);
// Next turn
endTurn();
}
void Topping::addPenalty(int iPenalty)
{
Command *pCmd = new PlayerEventCmd(*m_players[m_currPlayer],
PlayerEventCmd::PENALTY, iPenalty);
accessNavigation().addAndExecute(pCmd);
}
int Topping::play(const wstring &, const wstring &) int Topping::play(const wstring &, const wstring &)
{ {
ASSERT(false, "The play() method should not be called in topping mode"); ASSERT(false, "The play() method should not be called in topping mode");
@ -123,15 +156,19 @@ int Topping::play(const wstring &, const wstring &)
} }
void Topping::recordPlayerMove(const Move &iMove, Player &ioPlayer) void Topping::recordPlayerMove(const Move &iMove, Player &ioPlayer, int iElapsed)
{ {
// FIXME: the score of the player should not be the score of the move in topping mode ASSERT(iMove.isValid(), "Only valid rounds should be played");
LOG_INFO("Player " << ioPlayer.getId() << " plays: " << lfw(iMove.toString())); // Modify the score of the given move, to be the elapsed time
Round copyRound = iMove.getRound();
copyRound.setPoints(iElapsed);
Move newMove(copyRound);
// Update the rack and the score of the current player // Update the rack and the score of the current player
// PlayerMoveCmd::execute() must be called before Game::helperPlayMove() // PlayerMoveCmd::execute() must be called before Game::helperPlayMove()
// (called in this class in endTurn()). // (called in this class in endTurn()).
// See the big comment in game.cpp, line 96 // See the big comment in game.cpp, line 96
Command *pCmd = new PlayerMoveCmd(ioPlayer, iMove); Command *pCmd = new PlayerMoveCmd(ioPlayer, newMove);
accessNavigation().addAndExecute(pCmd); accessNavigation().addAndExecute(pCmd);
} }
@ -144,12 +181,18 @@ bool Topping::isFinished() const
void Topping::endTurn() void Topping::endTurn()
{ {
// Play the word on the board // Play the top move on the board
const Move &move = m_players[m_currPlayer]->getLastMove(); const Move &move = getTopMove();
Command *pCmd = new GameMoveCmd(*this, move, m_currPlayer); Command *pCmd = new GameMoveCmd(*this, move, m_currPlayer);
accessNavigation().addAndExecute(pCmd); accessNavigation().addAndExecute(pCmd);
accessNavigation().newTurn(); accessNavigation().newTurn();
// Make sure that the player has the correct rack
// (in case he didn't find the top, or not the same one)
Command *pCmd2 = new PlayerRackCmd(*m_players[m_currPlayer],
getHistory().getCurrentRack());
accessNavigation().addAndExecute(pCmd2);
// Start next turn... // Start next turn...
start(); start();
} }
@ -174,7 +217,7 @@ void Topping::addPlayer(Player *iPlayer)
Move Topping::getTopMove() const Move Topping::getTopMove() const
{ {
BestResults results; BestResults results;
results.search(getDic(), getBoard(), m_players[0]->getCurrentRack().getRack(), results.search(getDic(), getBoard(), getHistory().getCurrentRack().getRack(),
getHistory().beforeFirstRound()); getHistory().beforeFirstRound());
ASSERT(results.size() != 0, "No top move found"); ASSERT(results.size() != 0, "No top move found");
return Move(results.get(0)); return Move(results.get(0));

View file

@ -77,12 +77,25 @@ public:
*/ */
Move getTopMove() const; Move getTopMove() const;
/**
* Indicate that the player didn't find the top in the allocated time.
* This will play the top on the board, give a points penalty to the player
* and start the next turn.
*/
void turnTimeOut();
/**
* Give an additional penalty to the player (probably because
* he used a hint)
*/
void addPenalty(int iPenalty);
private: private:
/// Private constructor and destructor to force using the GameFactory class /// Private constructor and destructor to force using the GameFactory class
Topping(const GameParams &iParams, const Game *iMasterGame); Topping(const GameParams &iParams, const Game *iMasterGame);
/// Record a player move /// Record a player move
void recordPlayerMove(const Move &iMove, Player &ioPlayer); void recordPlayerMove(const Move &iMove, Player &ioPlayer, int iElapsed);
void endTurn(); void endTurn();

View file

@ -20,7 +20,7 @@
#include <QtGui/QStandardItemModel> #include <QtGui/QStandardItemModel>
#include <QtGui/QMenu> #include <QtGui/QMenu>
#include <QtGui/QHeaderView> #include <QtGui/QMessageBox>
#include <QtGui/QSortFilterProxyModel> #include <QtGui/QSortFilterProxyModel>
#include "topping_widget.h" #include "topping_widget.h"
@ -60,7 +60,7 @@ ToppingWidget::ToppingWidget(QWidget *parent, PlayModel &iPlayModel,
TimerWidget *timerWidget = new TimerWidget(this, iTimerModel); TimerWidget *timerWidget = new TimerWidget(this, iTimerModel);
timerWidget->setEnabled(false); timerWidget->setEnabled(false);
iTimerModel.setChronoMode(true); //iTimerModel.setChronoMode(true);
QObject::connect(&iTimerModel, SIGNAL(expired()), QObject::connect(&iTimerModel, SIGNAL(expired()),
this, SLOT(timeoutPenalty())); this, SLOT(timeoutPenalty()));
layout->addWidget(timerWidget); layout->addWidget(timerWidget);
@ -228,15 +228,26 @@ void ToppingWidget::playWord(const wstring &iWord, const wstring &iCoord)
void ToppingWidget::hintUsed(const AbstractHint &iHint) void ToppingWidget::hintUsed(const AbstractHint &iHint)
{ {
// TODO LOG_INFO("Hint '" << iHint.getName() << "' used for a cost of " << iHint.getCost());
LOG_INFO("Hint " << iHint.getName() << " used for a cost of " << iHint.getCost()); m_game->toppingAddPenalty(iHint.getCost());
emit gameUpdated();
} }
void ToppingWidget::timeoutPenalty() void ToppingWidget::timeoutPenalty()
{ {
// TODO // Show the solution to the player in a dialog box
LOG_INFO("Timeout penalty given"); const Move &move = m_game->toppingGetTopMove();
QMessageBox::information(this, "Eliot - " + _q("End of turn"),
_q("The allocated time for the turn has expired.\n"
"The top is %1 at %2 for %3 points.")
.arg(qfw(move.getRound().getWord()))
.arg(qfw(move.getRound().getCoord().toString()))
.arg(move.getScore()));
// End the turn
m_game->toppingTimeOut();
emit gameUpdated();
} }