mirror of
git://git.savannah.nongnu.org/eliot.git
synced 2025-01-18 10:26:15 +01:00
Arbitration mode: allow setting the rack randomly
This commit is contained in:
parent
9c82c8f7bc
commit
25a36ec9cd
12 changed files with 204 additions and 14 deletions
|
@ -18,9 +18,14 @@
|
|||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*****************************************************************************/
|
||||
|
||||
#include <algorithm> // For transform
|
||||
#include <cwctype> // For towupper
|
||||
|
||||
#include "arbitration.h"
|
||||
#include "rack.h"
|
||||
#include "player.h"
|
||||
#include "turn_cmd.h"
|
||||
#include "game_rack_cmd.h"
|
||||
#include "settings.h"
|
||||
#include "encoding.h"
|
||||
#include "debug.h"
|
||||
|
@ -35,6 +40,38 @@ Arbitration::Arbitration(const GameParams &iParams)
|
|||
}
|
||||
|
||||
|
||||
void Arbitration::setRackRandom()
|
||||
{
|
||||
undoCurrentRack();
|
||||
|
||||
const PlayedRack &newRack =
|
||||
helperSetRackRandom(getHistory().getCurrentRack(), true, RACK_NEW);
|
||||
setGameAndPlayersRack(newRack);
|
||||
|
||||
// Clear the results if everything went well
|
||||
m_results.clear();
|
||||
}
|
||||
|
||||
|
||||
void Arbitration::setRackManual(const wstring &iLetters)
|
||||
{
|
||||
undoCurrentRack();
|
||||
|
||||
// Letters can be lowercase or uppercase as they are
|
||||
// coming from user input. We do not consider a lowercase
|
||||
// letter to be a joker which has been assigned to a letter.
|
||||
// As a result, we simply make all the letters uppercase
|
||||
wstring upperLetters = iLetters;
|
||||
std::transform(upperLetters.begin(), upperLetters.end(),
|
||||
upperLetters.begin(), towupper);
|
||||
const PlayedRack &newRack = helperSetRackManual(true, upperLetters);
|
||||
setGameAndPlayersRack(newRack);
|
||||
|
||||
// Clear the results if everything went well
|
||||
m_results.clear();
|
||||
}
|
||||
|
||||
|
||||
void Arbitration::search()
|
||||
{
|
||||
// Search for the current player
|
||||
|
@ -83,3 +120,19 @@ void Arbitration::finalizeTurn()
|
|||
// FIXME arbitration end
|
||||
}
|
||||
|
||||
|
||||
void Arbitration::undoCurrentRack()
|
||||
{
|
||||
// The interface is supposed to make sure we are never in this case
|
||||
ASSERT(getNavigation().isLastTurn(),
|
||||
"Cannot change rack for an old turn");
|
||||
|
||||
// TODO
|
||||
// Find the PlayerMoveCmd we want to undo
|
||||
const GameRackCmd *cmd =
|
||||
getNavigation().getCurrentTurn().findMatchingCmd<GameRackCmd>();
|
||||
ASSERT(cmd != 0, "No matching GameRackCmd found");
|
||||
|
||||
accessNavigation().dropFrom(*cmd);
|
||||
}
|
||||
|
||||
|
|
|
@ -35,6 +35,20 @@ class Arbitration: public Duplicate
|
|||
DEFINE_LOGGER();
|
||||
friend class GameFactory;
|
||||
public:
|
||||
/**
|
||||
* Complete (or reset) the rack randomly.
|
||||
* @exception EndGameException if it is impossible to complete the rack
|
||||
* for some reason...
|
||||
*/
|
||||
void setRackRandom();
|
||||
|
||||
/**
|
||||
* Set the rack with the given letters
|
||||
* @exception EndGameException if the game is over
|
||||
* @exception GameException if any other error occurs
|
||||
*/
|
||||
void setRackManual(const wstring &iLetters);
|
||||
|
||||
void search();
|
||||
const Results& getResults() const { return m_results; }
|
||||
|
||||
|
@ -47,6 +61,9 @@ private:
|
|||
// Private constructor to force using the GameFactory class
|
||||
Arbitration(const GameParams &iParams);
|
||||
|
||||
/// Undo the current rack, and subsequent commands
|
||||
void undoCurrentRack();
|
||||
|
||||
/// Search results, with all the possible rounds up to a predefined limit
|
||||
LimitResults m_results;
|
||||
|
||||
|
|
|
@ -134,19 +134,7 @@ void Duplicate::start()
|
|||
|
||||
const PlayedRack &newRack =
|
||||
helperSetRackRandom(getHistory().getCurrentRack(), true, RACK_NEW);
|
||||
// Set the game rack
|
||||
Command *pCmd = new GameRackCmd(*this, newRack);
|
||||
accessNavigation().addAndExecute(pCmd);
|
||||
LOG_INFO("Setting players rack to '" + lfw(newRack.toString()) + "'");
|
||||
// All the players have the same rack
|
||||
BOOST_FOREACH(Player *player, m_players)
|
||||
{
|
||||
Command *pCmd = new PlayerRackCmd(*player, newRack);
|
||||
accessNavigation().addAndExecute(pCmd);
|
||||
// Nobody has played yet in this round
|
||||
Command *pCmd2 = new MarkPlayedCmd(*this, player->getId(), false);
|
||||
accessNavigation().addAndExecute(pCmd2);
|
||||
}
|
||||
setGameAndPlayersRack(newRack);
|
||||
}
|
||||
catch (EndGameException &e)
|
||||
{
|
||||
|
@ -420,3 +408,22 @@ void Duplicate::setMasterMove(const Move &iMove)
|
|||
accessNavigation().addAndExecute(pCmd);
|
||||
}
|
||||
|
||||
|
||||
void Duplicate::setGameAndPlayersRack(const PlayedRack &iRack)
|
||||
{
|
||||
// Set the game rack
|
||||
Command *pCmd = new GameRackCmd(*this, iRack);
|
||||
accessNavigation().addAndExecute(pCmd);
|
||||
LOG_INFO("Setting players rack to '" + lfw(iRack.toString()) + "'");
|
||||
// All the players have the same rack
|
||||
BOOST_FOREACH(Player *player, m_players)
|
||||
{
|
||||
Command *pCmd = new PlayerRackCmd(*player, iRack);
|
||||
accessNavigation().addAndExecute(pCmd);
|
||||
// Nobody has played yet in this round
|
||||
Command *pCmd2 = new MarkPlayedCmd(*this, player->getId(), false);
|
||||
accessNavigation().addAndExecute(pCmd2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -23,10 +23,11 @@
|
|||
|
||||
#include "game.h"
|
||||
#include "move.h"
|
||||
#include "command.h"
|
||||
#include "logging.h"
|
||||
|
||||
class Player;
|
||||
class PlayedRack;
|
||||
class Move;
|
||||
|
||||
using std::string;
|
||||
using std::wstring;
|
||||
|
@ -114,6 +115,9 @@ protected:
|
|||
/// Cancel the last move of a player (in the current turn)
|
||||
void undoPlayerMove(Player &ioPlayer);
|
||||
|
||||
/// Helper function to set the game rack and the players rack at the same time
|
||||
void setGameAndPlayersRack(const PlayedRack &iRack);
|
||||
|
||||
/**
|
||||
* This function does not terminate the turn itself, but performs some
|
||||
* checks to know whether or not it should be terminated (with a call to
|
||||
|
|
|
@ -197,6 +197,12 @@ void Navigation::clearFuture()
|
|||
}
|
||||
|
||||
|
||||
void Navigation::dropFrom(const Command &iCmd)
|
||||
{
|
||||
m_turnCommands.back()->dropFrom(iCmd);
|
||||
}
|
||||
|
||||
|
||||
const vector<TurnCmd *> & Navigation::getTurns() const
|
||||
{
|
||||
return m_turnCommands;
|
||||
|
|
|
@ -68,6 +68,11 @@ class Navigation
|
|||
*/
|
||||
void clearFuture();
|
||||
|
||||
/**
|
||||
* Remove the commands of the last turn, starting from the given one.
|
||||
*/
|
||||
void dropFrom(const Command &iCmd);
|
||||
|
||||
const vector<TurnCmd *> & getTurns() const;
|
||||
const TurnCmd & getCurrentTurn() const;
|
||||
|
||||
|
|
|
@ -238,6 +238,17 @@ int PublicGame::freeGamePass(const wstring &iToChange)
|
|||
|
||||
/***************************/
|
||||
|
||||
void PublicGame::arbitrationSetRackRandom()
|
||||
{
|
||||
getTypedGame<Arbitration>(m_game).setRackRandom();
|
||||
}
|
||||
|
||||
|
||||
void PublicGame::arbitrationSetRackManual(const wstring &iLetters)
|
||||
{
|
||||
getTypedGame<Arbitration>(m_game).setRackManual(iLetters);
|
||||
}
|
||||
|
||||
void PublicGame::arbitrationSearch()
|
||||
{
|
||||
return getTypedGame<Arbitration>(m_game).search();
|
||||
|
|
|
@ -242,6 +242,20 @@ public:
|
|||
* the Arbitration mode
|
||||
***************/
|
||||
|
||||
/**
|
||||
* Complete the rack randomly.
|
||||
* @exception EndGameException if it is impossible to complete the rack
|
||||
* for some reason...
|
||||
*/
|
||||
void arbitrationSetRackRandom();
|
||||
|
||||
/**
|
||||
* Set the rack manually
|
||||
* @exception EndGameException if the game is over
|
||||
* @exception GameException if any other error occurs
|
||||
*/
|
||||
void arbitrationSetRackManual(const wstring &iLetters);
|
||||
|
||||
void arbitrationSearch();
|
||||
const Results& arbitrationGetResults() const;
|
||||
|
||||
|
|
|
@ -113,6 +113,33 @@ void TurnCmd::dropNonExecutedCommands()
|
|||
}
|
||||
|
||||
|
||||
void TurnCmd::dropFrom(const Command &iCmd)
|
||||
{
|
||||
// Find the command index
|
||||
unsigned idx = m_commands.size();
|
||||
for (unsigned i = 0; i < m_commands.size(); ++i)
|
||||
{
|
||||
if (m_commands[i] == &iCmd)
|
||||
{
|
||||
idx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ASSERT(idx != m_commands.size(), "Cannot find command to drop");
|
||||
LOG_DEBUG("Deleting last turn commands, starting from " << idx);
|
||||
|
||||
while (m_commands.size() > idx)
|
||||
{
|
||||
if (m_commands.back()->isExecuted())
|
||||
m_commands.back()->undo();
|
||||
delete m_commands.back();
|
||||
m_commands.pop_back();
|
||||
}
|
||||
if (m_firstNotExecuted > m_commands.size())
|
||||
m_firstNotExecuted = m_commands.size();
|
||||
}
|
||||
|
||||
|
||||
bool TurnCmd::isFullyExecuted() const
|
||||
{
|
||||
return m_firstNotExecuted == m_commands.size();
|
||||
|
|
|
@ -109,6 +109,9 @@ class TurnCmd
|
|||
/// Drop the non-executed commands. Use it with care...
|
||||
void dropNonExecutedCommands();
|
||||
|
||||
/// Drop (and undo if needed) all the commands, starting with the given one. Use it with care...
|
||||
void dropFrom(const Command &iCmd);
|
||||
|
||||
/**
|
||||
* Find the command matching the given predicate, or 0 if not found.
|
||||
* The commands are iterated from the last one to the first one,
|
||||
|
|
|
@ -124,6 +124,10 @@ ArbitrationWidget::ArbitrationWidget(QWidget *parent,
|
|||
QObject::connect(lineEditRack, SIGNAL(textChanged(const QString&)),
|
||||
this, SLOT(clearResults()));
|
||||
|
||||
// Set a random rack
|
||||
QObject::connect(buttonRandom, SIGNAL(clicked()),
|
||||
this, SLOT(setRackRandom()));
|
||||
|
||||
// Display a preview of the selected word on the board
|
||||
QObject::connect(treeViewResults->selectionModel(),
|
||||
SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)),
|
||||
|
@ -214,6 +218,11 @@ void ArbitrationWidget::refresh()
|
|||
QString qrack = qfw(pldRack.toString(PlayedRack::RACK_SIMPLE));
|
||||
if (qrack != lineEditRack->text())
|
||||
lineEditRack->setText(qrack);
|
||||
|
||||
if (m_game->isFinished())
|
||||
{
|
||||
setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -379,6 +388,39 @@ int ArbitrationWidget::addSingleMove(const Move &iMove, int moveType,
|
|||
}
|
||||
|
||||
|
||||
void ArbitrationWidget::setRackRandom()
|
||||
{
|
||||
ASSERT(m_game->isLastTurn(), "The Random button should have been disabled");
|
||||
|
||||
// Warn if some players have already played
|
||||
bool someoneHasPlayed = false;
|
||||
for (unsigned int i = 0; i < m_game->getNbPlayers(); ++i)
|
||||
{
|
||||
if (m_game->hasPlayed(i))
|
||||
someoneHasPlayed = true;
|
||||
}
|
||||
if (someoneHasPlayed)
|
||||
{
|
||||
QString msg = _q("Some player(s) already have an assigned move. "
|
||||
"These moves will be lost if you change the rack.");
|
||||
QString question = _q("Do you really want to change the rack?");
|
||||
if (!QtCommon::requestConfirmation(msg, question))
|
||||
return;
|
||||
}
|
||||
|
||||
m_game->removeTestRound();
|
||||
try
|
||||
{
|
||||
m_game->arbitrationSetRackRandom();
|
||||
emit gameUpdated();
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
emit notifyProblem(_q(e.what()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ArbitrationWidget::resultsFilterChanged(const QString &iFilter)
|
||||
{
|
||||
treeViewResults->clearSelection();
|
||||
|
|
|
@ -57,6 +57,7 @@ public slots:
|
|||
void refresh();
|
||||
|
||||
private slots:
|
||||
void setRackRandom();
|
||||
void on_buttonSearch_clicked();
|
||||
void on_checkBoxHideAssigned_toggled(bool);
|
||||
void resultsFilterChanged(const QString &);
|
||||
|
|
Loading…
Reference in a new issue