summaryrefslogtreecommitdiff
path: root/game.cpp
diff options
context:
space:
mode:
authorJohn Fultz <jfultz@wolfram.com>2016-07-07 11:32:02 -0500
committerJohn Fultz <jfultz@wolfram.com>2016-07-07 11:44:45 -0500
commite1592dfbc6972dda664d7e1a3c208a9921691149 (patch)
tree0307551e3d0fac2702c5e7c0fb488bba02f97cb6 /game.cpp
parent3d46663b8d7221ee84c656715d18cfbdc28a0e85 (diff)
Fix problems entering games with unknown racks.
If you're entering games with unknown racks, Quackle can get confused about which player has how many tiles in the end game. This is because the racks may have been set to have less than 7 tiles, and some of the tiles "in the bag" may actually belong on another player's rack. Fixed this by... * Adding a mechanism which tracks the actual count of tiles in the bag and on the rack in GamePosition. This count is independent of what's actually on the rack. * If the game is about to end because the bag and rack are empty, check to see if the rack *should* have been empty. If not, pull tiles from another player's rack. This code might fail for games of more than two players. * If the game should be ending because the bag and rack are empty, but the rack isn't actually empty, then dump the files to another player's rack. Once again, this code doesn't take into account >2 players.
Diffstat (limited to 'game.cpp')
-rw-r--r--game.cpp48
1 files changed, 44 insertions, 4 deletions
diff --git a/game.cpp b/game.cpp
index 242556c..041f756 100644
--- a/game.cpp
+++ b/game.cpp
@@ -70,7 +70,7 @@ void Game::setPlayers(const PlayerList &list)
void Game::addPosition()
{
addClonePosition();
- m_positions.lastPosition().incrementTurn();
+ m_positions.lastPosition().incrementTurn(&history());
m_positions.setCurrentLocation(m_positions.lastLocation());
@@ -186,7 +186,7 @@ void Game::commitMove(const Move &move)
///////////
GamePosition::GamePosition(const PlayerList &players)
- : m_players(players), m_currentPlayer(m_players.end()), m_playerOnTurn(m_players.end()), m_turnNumber(0), m_nestedness(0), m_scorelessTurnsInARow(0), m_gameOver(false)
+ : m_players(players), m_currentPlayer(m_players.end()), m_playerOnTurn(m_players.end()), m_turnNumber(0), m_nestedness(0), m_scorelessTurnsInARow(0), m_gameOver(false), m_tilesInBag(m_bag.fullBagTileCount() - (QUACKLE_PARAMETERS->rackSize() * m_players.size())), m_tilesOnRack(QUACKLE_PARAMETERS->rackSize())
{
setEmptyBoard();
resetMoveMade();
@@ -194,7 +194,7 @@ GamePosition::GamePosition(const PlayerList &players)
}
GamePosition::GamePosition(const GamePosition &position)
- : m_players(position.m_players), m_moves(position.m_moves), m_moveMade(position.m_moveMade), m_committedMove(position.m_committedMove), m_turnNumber(position.m_turnNumber), m_nestedness(position.m_nestedness), m_scorelessTurnsInARow(position.m_scorelessTurnsInARow), m_gameOver(position.m_gameOver), m_board(position.m_board), m_bag(position.m_bag), m_drawingOrder(position.m_drawingOrder), m_explanatoryNote(position.m_explanatoryNote)
+ : m_players(position.m_players), m_moves(position.m_moves), m_moveMade(position.m_moveMade), m_committedMove(position.m_committedMove), m_turnNumber(position.m_turnNumber), m_nestedness(position.m_nestedness), m_scorelessTurnsInARow(position.m_scorelessTurnsInARow), m_gameOver(position.m_gameOver), m_tilesInBag(position.m_tilesInBag), m_tilesOnRack(position.m_tilesOnRack), m_board(position.m_board), m_bag(position.m_bag), m_drawingOrder(position.m_drawingOrder), m_explanatoryNote(position.m_explanatoryNote)
{
// reset iterator
if (position.turnNumber() == 0)
@@ -219,6 +219,8 @@ const GamePosition &GamePosition::operator=(const GamePosition &position)
m_nestedness = position.m_nestedness;
m_scorelessTurnsInARow = position.m_scorelessTurnsInARow;
m_gameOver = position.m_gameOver;
+ m_tilesInBag = position.m_tilesInBag;
+ m_tilesOnRack = position.m_tilesOnRack;
m_board = position.m_board;
m_bag = position.m_bag;
m_drawingOrder = position.m_drawingOrder;
@@ -747,7 +749,7 @@ void GamePosition::resetBag()
m_bag.prepareFullBag();
}
-bool GamePosition::incrementTurn()
+bool GamePosition::incrementTurn(const History* history)
{
if (gameOver() || m_players.empty())
return false;
@@ -767,6 +769,44 @@ bool GamePosition::incrementTurn()
// now moveTiles is the tiles that are in play but not on rack
removeLetters(moveTiles.tiles());
+ if (history)
+ {
+ PlayerList::iterator nextCurrentPlayer(m_currentPlayer);
+ nextCurrentPlayer++;
+ if (nextCurrentPlayer == m_players.end())
+ nextCurrentPlayer = m_players.begin();
+ const Quackle::PositionList positions(history->positionsFacedBy((*nextCurrentPlayer).id()));
+ if (positions.size() > 0)
+ m_tilesOnRack = positions.back().m_tilesOnRack;
+ m_tilesOnRack -= m_moveMade.usedTiles().size();
+ while (m_tilesInBag > 0 && m_tilesOnRack < QUACKLE_PARAMETERS->rackSize())
+ {
+ m_tilesInBag--;
+ m_tilesOnRack++;
+ }
+ if (m_tilesInBag == 0)
+ {
+ // We can get off on our counting with unknown racks.
+ // Shift tiles around if that happens.
+ Rack otherPlayerRack = nextCurrentPlayer->rack();
+ if (m_tilesOnRack == 0 && !remainingRack.empty())
+ {
+ otherPlayerRack.load(remainingRack.tiles());
+ remainingRack = remainingRack - remainingRack;
+ }
+ else if (m_tilesOnRack != 0 && remainingRack.empty())
+ {
+ int tilesToMove = m_tilesOnRack;
+ while (otherPlayerRack.tiles().size() > 0 && tilesToMove > 0)
+ {
+ LetterString oneAtATime = otherPlayerRack.tiles().substr(0, 1);
+ otherPlayerRack.unload(oneAtATime);
+ remainingRack.load(oneAtATime);
+ }
+ }
+ nextCurrentPlayer->setRack(otherPlayerRack);
+ }
+ }
// update our current player's score before possibly
// adding endgame bonuses