FreeGame: fix an infinite game when all the players keep passing forever.

Now the game ends when all the players passed in the last 3 turns.
This commit is contained in:
Olivier Teulière 2015-02-24 23:28:31 +01:00
parent 8077525893
commit 7f60f532ad
5 changed files with 129 additions and 10 deletions

View file

@ -169,11 +169,18 @@ int FreeGame::endTurn()
catch (EndGameException &e) catch (EndGameException &e)
{ {
// End of the game // End of the game
endGame(); endGame(m_currPlayer);
return 1; return 1;
} }
} }
if (allPlayersPassedThreeTimesInARow())
{
LOG_INFO("All the players passed 3 times consecutively");
endGame(getNPlayers());
return 2;
}
// Next player // Next player
nextPlayer(); nextPlayer();
@ -194,7 +201,7 @@ int FreeGame::endTurn()
// Adjust the scores of the players with the points of the remaining tiles // Adjust the scores of the players with the points of the remaining tiles
void FreeGame::endGame() void FreeGame::endGame(unsigned iWinningPlayer)
{ {
LOG_INFO("End of the game"); LOG_INFO("End of the game");
@ -209,7 +216,9 @@ void FreeGame::endGame()
// We currently handle case 1, and cannot handle case 3 until timers are // We currently handle case 1, and cannot handle case 3 until timers are
// implemented. // implemented.
// For case 2, we need both to detect a blocked situation (not easy...) and // For case 2, we need both to detect a blocked situation (not easy...) and
// to handle it in the endGame() method (very easy). // to handle it in the endGame() method (very easy). As a workaround for
// case 2, we consider that if all players pass 3 times the game ends
// without any winner.
// Add the points of the remaining tiles to the score of the current // Add the points of the remaining tiles to the score of the current
// player (i.e. the first player with an empty rack), and remove them // player (i.e. the first player with an empty rack), and remove them
@ -217,7 +226,7 @@ void FreeGame::endGame()
int addedPoints = 0; int addedPoints = 0;
for (unsigned int i = 0; i < getNPlayers(); i++) for (unsigned int i = 0; i < getNPlayers(); i++)
{ {
if (i != m_currPlayer) if (i != iWinningPlayer)
{ {
const PlayedRack &pld = m_players[i]->getCurrentRack(); const PlayedRack &pld = m_players[i]->getCurrentRack();
pld.getAllTiles(tiles); pld.getAllTiles(tiles);
@ -233,10 +242,13 @@ void FreeGame::endGame()
accessNavigation().addAndExecute(pCmd); accessNavigation().addAndExecute(pCmd);
} }
} }
// Add all the points to the current player // Give all the points to the winning player
Command *pCmd = new PlayerEventCmd(*m_players[m_currPlayer], if (iWinningPlayer < getNPlayers())
PlayerEventCmd::END_GAME, addedPoints); {
accessNavigation().addAndExecute(pCmd); Command *pCmd = new PlayerEventCmd(*m_players[m_currPlayer],
PlayerEventCmd::END_GAME, addedPoints);
accessNavigation().addAndExecute(pCmd);
}
// Lock game // Lock game
m_finished = true; m_finished = true;
@ -307,3 +319,27 @@ int FreeGame::pass(const wstring &iToChange)
return 0; return 0;
} }
bool FreeGame::allPlayersPassedThreeTimesInARow() const
{
const unsigned NB_OF_PASSES = 3;
// Only one player really plays at each turn
const unsigned NB_TURNS_TO_CHECK = NB_OF_PASSES * getNPlayers();
bool result = true;
BOOST_FOREACH(const Player *player, m_players)
{
const History &history = player->getHistory();
result = result && (history.getSize() >= NB_TURNS_TO_CHECK);
for (unsigned turnNb = history.getSize() - NB_TURNS_TO_CHECK;
turnNb < history.getSize();
++turnNb)
{
const Move &move = history.getTurn(turnNb).getMove();
// Players who did not play got a null move for the turn
result = result && (move.isPass() || move.isNull());
}
}
return result;
}

View file

@ -96,14 +96,20 @@ private:
/// Finish the current turn /// Finish the current turn
int endTurn(); int endTurn();
/// Finish the game /**
void endGame(); * Finish the game.
* @param The winning player is given, use an invalid player number to
* indicate that there was no winner (e.g.: all players pass several times)
*/
void endGame(unsigned iWinningPlayer);
/** /**
* Check whether it is legal to change the letters of iToChange. * Check whether it is legal to change the letters of iToChange.
* The return codes are the same as the ones on the pass() method * The return codes are the same as the ones on the pass() method
*/ */
int checkPass(const Player &iPlayer, const wstring &iToChange) const; int checkPass(const Player &iPlayer, const wstring &iToChange) const;
bool allPlayersPassedThreeTimesInARow() const;
}; };
#endif /* _FREEGAME_H_ */ #endif /* _FREEGAME_H_ */

View file

@ -90,6 +90,8 @@ arbitration/load_save 0 # randseed unused
freegame/play 7 freegame/play 7
# The human player always passes, letting the AI player do what it wants # The human player always passes, letting the AI player do what it wants
freegame/passing 1 freegame/passing 1
# Two humans play, and reach the end of the game by passing 3 times consecutively
freegame/passing_3_times 24
# 2 human players, changing letters a lot # 2 human players, changing letters a lot
freegame/change 3 freegame/change 3
# Three AI players # Three AI players

View file

@ -0,0 +1,21 @@
l 2 0
p
p
p
p
p
a t
p BEFH
p
p
p
p
p
p
a S
a T
a p
p
q
q

View file

@ -0,0 +1,54 @@
Using seed: 24
[?] pour l'aide
commande> l 2 0
mode partie libre
[?] pour l'aide
commande> p
commande> p
commande> p
commande> p
commande> p
commande> a t
BEFHLRT
commande> p BEFH
commande> p
commande> p
commande> p
commande> p
commande> p
commande> p
commande> a S
Score 0: -9
Score 1: -18
commande> a T
Rack 0: AEEOPUU
Rack 1: CILORTZ
commande> a p
Game: player 2 out of 2
Game: mode=Free game
Game: history:
N | RACK | SOLUTION | REF | PTS | BONUS
===|==========|================|=====|=====|======
1 | AUEUOEP | (PASS) | - | 0 |
2 | ELBFHTR | (PASS) | - | 0 |
3 | AEEOPUU | (PASS) | - | 0 |
4 | BEFHLRT | (PASS) | - | 0 |
5 | AEEOPUU | (PASS) | - | 0 |
6 | BEFHLRT | [BEFH] | - | 0 |
7 | AEEOPUU | (PASS) | - | 0 |
8 | LRT+COIZ | (PASS) | - | 0 |
9 | AEEOPUU | (PASS) | - | 0 |
10 | CILORTZ | (PASS) | - | 0 |
11 | AEEOPUU | (PASS) | - | 0 |
12 | CILORTZ | (PASS) | - | 0 |
Rack 0: AEEOPUU
Rack 1: CILORTZ
Score 0: -9
Score 1: -18
commande> p
Cannot pass (3)
commande> q
fin du mode partie libre
commande> q