summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Fultz <jfultz@wolfram.com>2016-07-03 02:54:38 -0500
committerJohn Fultz <jfultz@wolfram.com>2016-07-03 02:54:38 -0500
commitda2f20720facda706be06b5813ab20057d5b4de9 (patch)
treee2d266054b384d7d5a5fd38c19bf18d1f952ed61
parent0cda99549250c87ab9c9b20044767a7615e279c6 (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.cpp7
-rw-r--r--move.cpp19
-rw-r--r--move.h4
-rw-r--r--quacker/boarddisplay.cpp2
-rw-r--r--quacker/graphicalreporter.cpp1
-rw-r--r--quacker/quacker.cpp4
-rw-r--r--quackleio/gcgio.cpp15
-rw-r--r--quackleio/util.cpp4
-rw-r--r--reporter.cpp1
9 files changed, 44 insertions, 13 deletions
diff --git a/game.cpp b/game.cpp
index 845e864..242556c 100644
--- a/game.cpp
+++ b/game.cpp
@@ -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;
diff --git a/move.cpp b/move.cpp
index eaaf8b6..7f77dc5 100644
--- a/move.cpp
+++ b/move.cpp
@@ -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;
diff --git a/move.h b/move.h
index f4d1827..e628b52 100644
--- a/move.h
+++ b/move.h
@@ -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;