Added auto-execution of commands when clearing future commands.

The goal is to automatically replay commands involving AI, so that the user cannot be 'blocked'.
This commit is contained in:
Olivier Teulière 2008-11-30 20:55:45 +00:00
parent 59345dbbdf
commit 67306bec3e
10 changed files with 48 additions and 12 deletions

View file

@ -23,7 +23,7 @@
Command::Command()
: m_executed(false)
: m_executed(false), m_autoExecution(true)
{
}

View file

@ -58,6 +58,17 @@ class Command
*/
bool isExecuted() const { return m_executed; }
/**
* Mark the command as auto-executable, which means that it will
* be automatically executed if the commands history is cleared
* just before this command.
* Auto-executable commands correspond to commands for AI players,
* for which the user cannot change the behaviour.
*/
void setAutoExecution(bool autoExec) { m_autoExecution = autoExec; }
/// Return true if the command is auto-executable
virtual bool isAutoExecution() const { return m_autoExecution; }
/**
* Description of the command, for debugging purposes
*/
@ -69,6 +80,7 @@ class Command
private:
bool m_executed;
bool m_autoExecution;
};
#endif

View file

@ -61,12 +61,12 @@ int Duplicate::play(const wstring &iCoord, const wstring &iWord)
if (res == 0)
{
// Everything is OK, we can play the word
recordPlayerMove(Move(round), currPlayer);
recordPlayerMove(Move(round), currPlayer, true);
}
else
{
// Record the invalid move of the player
recordPlayerMove(Move(iWord, iCoord), currPlayer);
recordPlayerMove(Move(iWord, iCoord), currPlayer, true);
}
// Little hack to handle duplicate games with only AI players.
@ -93,7 +93,7 @@ void Duplicate::playAI(unsigned int p)
ASSERT(false, "AI tried to cheat!");
}
recordPlayerMove(move, *player);
recordPlayerMove(move, *player, false);
}
@ -164,12 +164,14 @@ void Duplicate::tryEndTurn()
}
void Duplicate::recordPlayerMove(const Move &iMove, Player &ioPlayer)
void Duplicate::recordPlayerMove(const Move &iMove, Player &ioPlayer, bool isForHuman)
{
Command *pCmd = new PlayerMoveCmd(ioPlayer, iMove);
pCmd->setAutoExecution(!isForHuman);
accessNavigation().addAndExecute(pCmd);
Command *pCmd2 = new MarkPlayedCmd(*this, ioPlayer.getId(), true);
pCmd2->setAutoExecution(!isForHuman);
accessNavigation().addAndExecute(pCmd2);
}

View file

@ -95,7 +95,7 @@ private:
Duplicate(const Dictionary &iDic);
/// Record a player move
void recordPlayerMove(const Move &iMove, Player &ioPlayer);
void recordPlayerMove(const Move &iMove, Player &ioPlayer, bool isForHuman);
/// Make the AI player whose ID is p play its turn
void playAI(unsigned int p);

View file

@ -66,14 +66,14 @@ int FreeGame::play(const wstring &iCoord, const wstring &iWord)
Move move(round);
// Update the rack and the score of the current player
recordPlayerMove(move, *m_players[m_currPlayer]);
recordPlayerMove(move, *m_players[m_currPlayer], true);
}
else
{
Move move(iWord, iCoord);
// Record the invalid move of the player
recordPlayerMove(move, *m_players[m_currPlayer]);
recordPlayerMove(move, *m_players[m_currPlayer], true);
}
// Next turn
@ -100,15 +100,17 @@ void FreeGame::playAI(unsigned int p)
}
// Update the rack and the score of the current player
recordPlayerMove(move, *player);
recordPlayerMove(move, *player, false);
endTurn();
}
void FreeGame::recordPlayerMove(const Move &iMove, Player &ioPlayer)
void FreeGame::recordPlayerMove(const Move &iMove, Player &ioPlayer,
bool isForHuman)
{
Command *pCmd = new PlayerMoveCmd(ioPlayer, iMove);
pCmd->setAutoExecution(!isForHuman);
accessNavigation().addAndExecute(pCmd);
}
@ -275,7 +277,7 @@ int FreeGame::pass(const wstring &iToChange)
Move move(iToChange);
// End the player's turn
recordPlayerMove(move, player);
recordPlayerMove(move, player, true);
// Next game turn
endTurn();

View file

@ -86,7 +86,7 @@ private:
void playAI(unsigned int p);
/// Record a player move
void recordPlayerMove(const Move &iMove, Player &ioPlayer);
void recordPlayerMove(const Move &iMove, Player &ioPlayer, bool isForHuman);
/// Finish the current turn
int endTurn();

View file

@ -145,6 +145,11 @@ void Navigation::lastTurn()
void Navigation::clearFuture()
{
// Replay the auto-execution turns
// (i.e. turns where only the AI was involved)
while (!isLastTurn() && m_turnCommands[m_currTurn]->isAutoExecution())
nextTurn();
// When there is no future, don't do anything
if (isLastTurn())
return;

View file

@ -59,6 +59,7 @@ void Training::setRackRandom(bool iCheck, set_rack_mode mode)
const PlayedRack &newRack =
helperSetRackRandom(getCurrentPlayer().getCurrentRack(), iCheck, mode);
Command *pCmd = new PlayerRackCmd(*m_players[m_currPlayer], newRack);
pCmd->setAutoExecution(false);
accessNavigation().addAndExecute(pCmd);
}
@ -130,6 +131,7 @@ void Training::recordPlayerMove(const Move &iMove, Player &ioPlayer)
// (called in this class in endTurn()).
// See the big comment in game.cpp, line 96
Command *pCmd = new PlayerMoveCmd(ioPlayer, iMove);
pCmd->setAutoExecution(false);
accessNavigation().addAndExecute(pCmd);
}

View file

@ -69,6 +69,17 @@ void TurnCmd::doUndo()
}
bool TurnCmd::isAutoExecution() const
{
BOOST_FOREACH(Command *cmd, m_commands)
{
if (!cmd->isAutoExecution())
return false;
}
return true;
}
wstring TurnCmd::toString() const
{
wostringstream oss;

View file

@ -46,6 +46,8 @@ class TurnCmd: public Command
bool isEmpty() const { return m_commands.empty(); }
virtual bool isAutoExecution() const;
virtual wstring toString() const;
protected: