diff options
author | John Fultz <jfultz@wolfram.com> | 2016-07-03 02:54:38 -0500 |
---|---|---|
committer | John Fultz <jfultz@wolfram.com> | 2016-07-03 02:54:38 -0500 |
commit | da2f20720facda706be06b5813ab20057d5b4de9 (patch) | |
tree | e2d266054b384d7d5a5fd38c19bf18d1f952ed61 | |
parent | 0cda99549250c87ab9c9b20044767a7615e279c6 (diff) |
Fix problems with "ex n" where n is a number.
Found a crash where you enter "ex 4" twice,
and it would crash. This led me to look up
how this was implemented, and it wasn't
very robust. It also didn't save properly in
the GCG. So I created a new move type
which I called a BlindExchange and implemented
it throughout the system.
-rw-r--r-- | game.cpp | 7 | ||||
-rw-r--r-- | move.cpp | 19 | ||||
-rw-r--r-- | move.h | 4 | ||||
-rw-r--r-- | quacker/boarddisplay.cpp | 2 | ||||
-rw-r--r-- | quacker/graphicalreporter.cpp | 1 | ||||
-rw-r--r-- | quacker/quacker.cpp | 4 | ||||
-rw-r--r-- | quackleio/gcgio.cpp | 15 | ||||
-rw-r--r-- | quackleio/util.cpp | 4 | ||||
-rw-r--r-- | reporter.cpp | 1 |
9 files changed, 44 insertions, 13 deletions
@@ -357,6 +357,11 @@ int GamePosition::validateMove(const Move &move) const } break; + case Move::BlindExchange: + if (!exchangeAllowed()) + ret |= TooLateExchange; + break; + case Move::UnusedTilesBonus: case Move::TimePenalty: ret = InvalidAction; @@ -783,7 +788,7 @@ bool GamePosition::incrementTurn() } } - if ((m_moveMade.action == Move::Place && m_moveMade.effectiveScore() == 0) || m_moveMade.action == Move::Exchange || m_moveMade.action == Move::Pass) + if ((m_moveMade.action == Move::Place && m_moveMade.effectiveScore() == 0) || m_moveMade.action == Move::Exchange || m_moveMade.action == Move::BlindExchange || m_moveMade.action == Move::Pass) ++m_scorelessTurnsInARow; else m_scorelessTurnsInARow = 0; @@ -48,6 +48,10 @@ bool operator==(const Move &move1, const Move &move2) ret = (Quackle::String::alphabetize(move1.tiles()) == Quackle::String::alphabetize(move2.tiles())); break; + case Quackle::Move::BlindExchange: + ret = (move1.tiles().length() == move2.tiles().length()); + break; + case Quackle::Move::Pass: case Quackle::Move::Nonmove: case Quackle::Move::TimePenalty: @@ -124,6 +128,7 @@ UVString Move::xml() const break; case Exchange: + case BlindExchange: actionString = MARK_UV("exchange"); includeTiles = true; break; @@ -180,10 +185,12 @@ UVString Move::toString() const { UVOStringStream ss; - if (action == Quackle::Move::Pass) - ss << "- "; - else if (action == Quackle::Move::Exchange) - ss << "-" << QUACKLE_ALPHABET_PARAMETERS->userVisible(m_tiles); + if (action == Quackle::Move::Pass) + ss << "- "; + else if (action == Quackle::Move::Exchange) + ss << "-" << QUACKLE_ALPHABET_PARAMETERS->userVisible(m_tiles); + else if (action == Quackle::Move::BlindExchange) + ss << "-" << m_tiles.length(); else if (action == Quackle::Move::Nonmove) ss << "nonmove"; else if (action == Quackle::Move::TimePenalty) @@ -290,11 +297,11 @@ Move Move::createChallengedPhoney(int zeroIndexedRow, int zeroIndexedColumn, boo return move; } -Move Move::createExchangeMove(LetterString tilesToExchange) +Move Move::createExchangeMove(LetterString tilesToExchange, bool isBlind) { Move move; - move.action = Move::Exchange; + move.action = isBlind ? Move::BlindExchange : Move::Exchange; move.setTiles(tilesToExchange); move.score = 0; @@ -43,7 +43,7 @@ namespace Quackle class Move { public: - enum Action { Place = 0, Exchange, Pass, UnusedTilesBonus, TimePenalty, Nonmove }; + enum Action { Place = 0, Exchange, BlindExchange, Pass, UnusedTilesBonus, TimePenalty, Nonmove }; // creates a pass move with 0 equity; // tiles is "", score and equity are zero @@ -124,7 +124,7 @@ public: static Move createChallengedPhoney(UVString placeString, LetterString word); static Move createChallengedPhoney(int zeroIndexedRow, int zeroIndexedColumn, bool horizontal, LetterString word); - static Move createExchangeMove(LetterString tilesToExchange); + static Move createExchangeMove(LetterString tilesToExchange, bool isBlind); static Move createUnusedTilesBonus(LetterString unusedTiles, int bonus); static Move createTimePenalty(int penalty); static Move createPassMove(); diff --git a/quacker/boarddisplay.cpp b/quacker/boarddisplay.cpp index 2f570c6..85b551b 100644 --- a/quacker/boarddisplay.cpp +++ b/quacker/boarddisplay.cpp @@ -178,7 +178,7 @@ void BoardWithQuickEntry::processCommand(const QString &command) if (isPass) move = Quackle::Move::createPassMove(); else - move = Quackle::Move::createExchangeMove(encodedLetters); + move = Quackle::Move::createExchangeMove(encodedLetters, isIntConvertable); } else { diff --git a/quacker/graphicalreporter.cpp b/quacker/graphicalreporter.cpp index 2fb0842..a7ca9f5 100644 --- a/quacker/graphicalreporter.cpp +++ b/quacker/graphicalreporter.cpp @@ -192,6 +192,7 @@ void GraphicalReporter::reportPosition(const Quackle::GamePosition &position, Qu } case Quackle::Move::Exchange: + case Quackle::Move::BlindExchange: default: item = QuackleIO::Util::moveToDetailedString(*it); break; diff --git a/quacker/quacker.cpp b/quacker/quacker.cpp index be70c14..ffe6531 100644 --- a/quacker/quacker.cpp +++ b/quacker/quacker.cpp @@ -396,7 +396,9 @@ void TopLevel::setCandidateMove(const Quackle::Move &move) ensureUpToDateSimulatorMoveList(); } - if (!m_game->currentPosition().currentPlayer().racksAreKnown() && !m_game->currentPosition().currentPlayer().rack().contains(prettiedMove.usedTiles())) + if (!m_game->currentPosition().currentPlayer().racksAreKnown() && + !m_game->currentPosition().currentPlayer().rack().contains(prettiedMove.usedTiles()) && + prettiedMove.action != Quackle::Move::BlindExchange) { m_game->currentPosition().setCurrentPlayerRack(Quackle::Rack(prettiedMove.usedTiles())); } diff --git a/quackleio/gcgio.cpp b/quackleio/gcgio.cpp index dfe23a0..9209be5 100644 --- a/quackleio/gcgio.cpp +++ b/quackleio/gcgio.cpp @@ -168,10 +168,21 @@ Quackle::Game *GCGIO::read(QTextStream &stream, int flags) else if (firstMoveBite.startsWith("-")) { const QString exchangedLetters = firstMoveBite.right(firstMoveBite.length() - 1); - if (exchangedLetters.isEmpty()) + bool isLetterCount = false; + uint letterCount = exchangedLetters.toUInt(&isLetterCount); + + if (exchangedLetters.isEmpty() || (isLetterCount && letterCount == 0)) move = Quackle::Move::createPassMove(); + else if (isLetterCount) + { + Quackle::LetterString encodedLetters; + + for (uint i = 0; i < letterCount; ++i) + encodedLetters.push_back(QUACKLE_BLANK_MARK); + move = Quackle::Move::createExchangeMove(encodedLetters, true); + } else - move = Quackle::Move::createExchangeMove(Util::encode(exchangedLetters)); + move = Quackle::Move::createExchangeMove(Util::encode(exchangedLetters), false); } else if (firstMoveBite.startsWith("(time)")) { diff --git a/quackleio/util.cpp b/quackleio/util.cpp index 5530f16..901c65e 100644 --- a/quackleio/util.cpp +++ b/quackleio/util.cpp @@ -55,6 +55,10 @@ QString Util::moveToDetailedString(const Quackle::Move &move) ret = QObject::tr("Exch. %1").arg(prettyTiles); break; + case Quackle::Move::BlindExchange: + ret = QObject::tr("Exch. %1").arg(move.tiles().length()); + break; + case Quackle::Move::UnusedTilesBonus: ret = QObject::tr("2*(%1)").arg(letterStringToQString(Util::alphagram(move.usedTiles()))); break; diff --git a/reporter.cpp b/reporter.cpp index c844afa..7054763 100644 --- a/reporter.cpp +++ b/reporter.cpp @@ -156,6 +156,7 @@ void Reporter::reportPosition(const GamePosition &position, ComputerPlayer *comp break; case Move::Exchange: + case Move::BlindExchange: s << MARK_UV("xch"); break; |