diff options
-rw-r--r-- | bag.cpp | 9 | ||||
-rw-r--r-- | bag.h | 3 | ||||
-rw-r--r-- | game.cpp | 48 | ||||
-rw-r--r-- | game.h | 5 | ||||
-rw-r--r-- | preendgame.cpp | 2 | ||||
-rw-r--r-- | rack.cpp | 9 | ||||
-rw-r--r-- | rack.h | 4 |
7 files changed, 73 insertions, 7 deletions
@@ -55,6 +55,15 @@ void Bag::prepareFullBag() m_tiles.push_back(letter); } +int Bag::fullBagTileCount() +{ + int tileCount = 0; + // we start at 0 because we want to include blanks etcetera + for (Letter letter = 0; letter <= QUACKLE_ALPHABET_PARAMETERS->lastLetter(); ++letter) + tileCount += QUACKLE_ALPHABET_PARAMETERS->count(letter); + return tileCount; +} + void Bag::toss(const LetterString &letters) { const LetterString::const_iterator end(letters.end()); @@ -72,6 +72,9 @@ public: // use this to start out your bag for use void prepareFullBag(); + // Assuming a full bag, how many tiles would that be? + int fullBagTileCount(); + // whether there are no tiles left in the bag bool empty() const; @@ -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 @@ -34,6 +34,7 @@ namespace Quackle { class ComputerPlayer; +class History; class HistoryLocation { @@ -380,7 +381,7 @@ public: // at start of game.) // If applicable, this player's score is also incremented by score of move // made. - bool incrementTurn(); + bool incrementTurn(const History* history = NULL); // Turn numbers in games start from 1. // A turn number of zero indicates a position that is pregame. @@ -426,6 +427,8 @@ protected: unsigned int m_nestedness; int m_scorelessTurnsInARow; bool m_gameOver; + int m_tilesInBag; + int m_tilesOnRack; Quackle::Board m_board; diff --git a/preendgame.cpp b/preendgame.cpp index 227598f..fe9a356 100644 --- a/preendgame.cpp +++ b/preendgame.cpp @@ -167,7 +167,7 @@ MoveList Preendgame::moves(int nmoves) tempPosition.setOppRack((*it).rack); tempPosition.setMoveMade(*moveIt); - tempPosition.incrementTurn(); + tempPosition.incrementTurn(NULL); tempPosition.makeMove(*moveIt); //tempPosition.incrementNestedness(); @@ -76,6 +76,15 @@ bool Rack::unload(const LetterString &used) return ret; } +void Rack::load(const LetterString &tiles) +{ + for (LetterString::const_iterator it = tiles.begin(); it != tiles.end(); ++it) + { + if (it != QUACKLE_NULL_MARK) + m_tiles += *it; + } +} + bool Rack::contains(const LetterString &used) const { return Rack(*this).unload(used); @@ -57,6 +57,8 @@ public: // in this rack and unloaded bool unload(const LetterString &used); + void load(const LetterString &tiles); + // same as above but nonmutating bool contains(const LetterString &used) const; @@ -99,7 +101,7 @@ inline bool Rack::empty() const } const Quackle::Rack operator-(const Quackle::Rack &rack, const Quackle::Move &move); -const Quackle::Rack operator-(const Quackle::Rack &rack1, const Quackle::Rack &rack); +const Quackle::Rack operator-(const Quackle::Rack &rack1, const Quackle::Rack &rack2); UVOStream &operator<<(UVOStream &o, const Quackle::Rack &rack); |