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)
: m_player(ioPlayer), m_eventType(iEvent), m_points(iPoints)
{
ASSERT(iEvent == PENALTY || iEvent == END_GAME || iPoints >= 0,
"Negative points not allowed");
ASSERT(iEvent != PENALTY || iPoints <= 0,
"Positive points not allowed");
// Solos and warnings are always positive
ASSERT(iEvent != SOLO || iPoints >= 0, "Negative points not allowed");
ASSERT(iEvent != WARNING || iPoints >= 0, "Negative 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
{
return getTypedGame<Topping>(m_game).getTriedMoves();

View file

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

View file

@ -38,7 +38,9 @@
#include "player.h"
#include "turn.h"
#include "cmd/topping_move_cmd.h"
#include "cmd/player_rack_cmd.h"
#include "cmd/player_move_cmd.h"
#include "cmd/player_event_cmd.h"
#include "cmd/game_move_cmd.h"
#include "encoding.h"
@ -105,8 +107,7 @@ void Topping::tryWord(const wstring &iWord, const wstring &iCoord, int iElapsed)
else
{
// End the turn
// FIXME
recordPlayerMove(move, *m_players[m_currPlayer]);
recordPlayerMove(move, *m_players[m_currPlayer], iElapsed);
// Next turn
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 &)
{
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
LOG_INFO("Player " << ioPlayer.getId() << " plays: " << lfw(iMove.toString()));
ASSERT(iMove.isValid(), "Only valid rounds should be played");
// 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
// PlayerMoveCmd::execute() must be called before Game::helperPlayMove()
// (called in this class in endTurn()).
// See the big comment in game.cpp, line 96
Command *pCmd = new PlayerMoveCmd(ioPlayer, iMove);
Command *pCmd = new PlayerMoveCmd(ioPlayer, newMove);
accessNavigation().addAndExecute(pCmd);
}
@ -144,12 +181,18 @@ bool Topping::isFinished() const
void Topping::endTurn()
{
// Play the word on the board
const Move &move = m_players[m_currPlayer]->getLastMove();
// Play the top move on the board
const Move &move = getTopMove();
Command *pCmd = new GameMoveCmd(*this, move, m_currPlayer);
accessNavigation().addAndExecute(pCmd);
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();
}
@ -174,7 +217,7 @@ void Topping::addPlayer(Player *iPlayer)
Move Topping::getTopMove() const
{
BestResults results;
results.search(getDic(), getBoard(), m_players[0]->getCurrentRack().getRack(),
results.search(getDic(), getBoard(), getHistory().getCurrentRack().getRack(),
getHistory().beforeFirstRound());
ASSERT(results.size() != 0, "No top move found");
return Move(results.get(0));

View file

@ -77,12 +77,25 @@ public:
*/
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 constructor and destructor to force using the GameFactory class
Topping(const GameParams &iParams, const Game *iMasterGame);
/// Record a player move
void recordPlayerMove(const Move &iMove, Player &ioPlayer);
void recordPlayerMove(const Move &iMove, Player &ioPlayer, int iElapsed);
void endTurn();

View file

@ -20,7 +20,7 @@
#include <QtGui/QStandardItemModel>
#include <QtGui/QMenu>
#include <QtGui/QHeaderView>
#include <QtGui/QMessageBox>
#include <QtGui/QSortFilterProxyModel>
#include "topping_widget.h"
@ -60,7 +60,7 @@ ToppingWidget::ToppingWidget(QWidget *parent, PlayModel &iPlayModel,
TimerWidget *timerWidget = new TimerWidget(this, iTimerModel);
timerWidget->setEnabled(false);
iTimerModel.setChronoMode(true);
//iTimerModel.setChronoMode(true);
QObject::connect(&iTimerModel, SIGNAL(expired()),
this, SLOT(timeoutPenalty()));
layout->addWidget(timerWidget);
@ -228,15 +228,26 @@ void ToppingWidget::playWord(const wstring &iWord, const wstring &iCoord)
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()
{
// TODO
LOG_INFO("Timeout penalty given");
// Show the solution to the player in a dialog box
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();
}