diff options
Diffstat (limited to 'quacker')
-rw-r--r-- | quacker/macondo.cpp | 41 | ||||
-rw-r--r-- | quacker/macondo.h | 8 | ||||
-rw-r--r-- | quacker/macondobackend.cpp | 75 | ||||
-rw-r--r-- | quacker/macondobackend.h | 2 | ||||
-rw-r--r-- | quacker/quacker.cpp | 26 | ||||
-rw-r--r-- | quacker/quacker.h | 3 |
6 files changed, 116 insertions, 39 deletions
diff --git a/quacker/macondo.cpp b/quacker/macondo.cpp index f92f89b..3048195 100644 --- a/quacker/macondo.cpp +++ b/quacker/macondo.cpp @@ -21,7 +21,7 @@ Macondo::Macondo(Quackle::Game *game) : View() { execPath += "/apps/macondo/macondo"; initOptions = std::make_unique<MacondoInitOptions>(execPath); m_backend = new MacondoBackend(game, *initOptions); - connect(m_backend, SIGNAL(gotSimMoves(const Quackle::MoveList &)), this, SLOT(gotSimMoves(const Quackle::MoveList &))); + connect(m_backend, SIGNAL(gotMoves(const Quackle::MoveList &)), this, SLOT(gotMoves(const Quackle::MoveList &))); m_solve = new QPushButton(tr("Solve")); m_solve->setDisabled(true); QGridLayout *layout = new QGridLayout(this); @@ -36,26 +36,35 @@ Macondo::~Macondo() { } void Macondo::simulate() { - if (m_backend->isRunning()) + if (m_isSolving) { + // don't start a simulation if we're solving a (pre-)endgame + return; + } + if (isRunning()) stop(); clearMoves(); MacondoSimulateOptions options; m_backend->simulate(options, m_movesFromKibitzer); } +bool Macondo::isRunning() const { + return m_backend->isRunning(); +} + void Macondo::solve() { bool wasSolving = m_isSolving; - if (m_backend->isRunning()) + if (isRunning()) stop(); clearMoves(); if (wasSolving) { - m_solve->setText(tr("Solve")); + emit stoppedSolver(); } else { + emit runningSolver(); MacondoSolveOptions options; m_backend->solve(options); - m_solve->setText(tr("Stop")); m_isSolving = true; } + updateSolveButton(); } void Macondo::gameChanged(Quackle::Game *game) { @@ -68,27 +77,37 @@ void Macondo::stop() { m_backend->stop(); m_anyUpdates = false; m_isSolving = false; + updateSolveButton(); } bool Macondo::useForSimulation() const { return m_useMacondo->isChecked(); } -void Macondo::gotSimMoves(const Quackle::MoveList &moves) { +void Macondo::gotMoves(const Quackle::MoveList &moves) { + printf("aaa moves\n"); m_moves = moves; m_anyUpdates = true; } void Macondo::positionChanged(const Quackle::GamePosition *position) { - if (!m_backend->isRunning()) { + if (!isRunning()) { // perhaps new moves were generated m_movesFromKibitzer = position->moves(); - } - int tilesLeft = position->unseenBag().size(); - if (!position->gameOver() && tilesLeft <= 7) { + } + m_tilesUnseen = position->gameOver() ? 0 : position->unseenBag().size(); + updateSolveButton(); +} + +// update "Solve" button text and enabledness* +void Macondo::updateSolveButton() { + if (isRunning()) { + m_solve->setText(tr("Stop")); + m_solve->setDisabled(false); + } else if (m_tilesUnseen > 0 && m_tilesUnseen <= 7) { m_solve->setText(tr("Solve endgame")); m_solve->setDisabled(false); - } else if (!position->gameOver() && tilesLeft <= 10) { + } else if (m_tilesUnseen > 7 && m_tilesUnseen <= 10) { m_solve->setText(tr("Solve pre-endgame")); m_solve->setDisabled(false); } else { diff --git a/quacker/macondo.h b/quacker/macondo.h index 4fcf758..638456f 100644 --- a/quacker/macondo.h +++ b/quacker/macondo.h @@ -27,20 +27,26 @@ public: m_anyUpdates = false; return any; } + bool isRunning() const; +signals: + void runningSolver(); + void stoppedSolver(); public slots: void simulate(); void solve(); void gameChanged(Quackle::Game *game) override; void positionChanged(const Quackle::GamePosition *position) override; private slots: - void gotSimMoves(const Quackle::MoveList &moves); + void gotMoves(const Quackle::MoveList &moves); private: + void updateSolveButton(); QCheckBox *m_useMacondo; QPushButton *m_solve; Quackle::Game *m_game; MacondoBackend *m_backend; Quackle::MoveList m_moves; Quackle::MoveList m_movesFromKibitzer; + int m_tilesUnseen = 93; int m_viewingPlyNumber = 0; bool m_anyUpdates = false; bool m_isSolving = false; diff --git a/quacker/macondobackend.cpp b/quacker/macondobackend.cpp index 5837092..59db5cf 100644 --- a/quacker/macondobackend.cpp +++ b/quacker/macondobackend.cpp @@ -148,6 +148,24 @@ static double parseEquity(const string &equityString) { return equity; } +static Quackle::Move createPlaceMove(const string &placement, const string &prettyTiles) { + string dotDescription; + for (size_t i = 0; i < prettyTiles.size();) { + size_t j = prettyTiles.find("(", i); + if (j == string::npos) { + dotDescription += prettyTiles.substr(i); + break; + } + dotDescription += prettyTiles.substr(i, j) + "."; + i = prettyTiles.find(")", j); + if (i == string::npos) throw "mismatched parentheses"; + i++; + } + auto move = Quackle::Move::createPlaceMove(placement, QUACKLE_ALPHABET_PARAMETERS->encode(dotDescription)); + move.setPrettyTiles(QUACKLE_ALPHABET_PARAMETERS->encode(prettyTiles)); + return move; +} + // parse move from Macondo sim static Quackle::Move extractSimMove(const string &play) { vector<string> words = splitWords(play); @@ -179,24 +197,11 @@ static Quackle::Move extractSimMove(const string &play) { } else { // normal play const string &placement = words[0]; - const string &description = words[1]; + const string &prettyTiles = words[1]; const string &scoreString = words[2 + !plays7]; const string &winString = words[3 + !plays7]; const string &equityString = words[4 + !plays7]; - string dotDescription; - for (size_t i = 0; i < description.size();) { - size_t j = description.find("(", i); - if (j == string::npos) { - dotDescription += description.substr(i); - break; - } - dotDescription += description.substr(i, j) + "."; - i = description.find(")", j); - if (i == string::npos) throw "mismatched parentheses"; - i++; - } - Quackle::Move move = Quackle::Move::createPlaceMove(placement, QUACKLE_ALPHABET_PARAMETERS->encode(dotDescription)); - move.setPrettyTiles(QUACKLE_ALPHABET_PARAMETERS->encode(description)); + Quackle::Move move = createPlaceMove(placement, prettyTiles); move.score = parseScore(scoreString); move.win = parseWinRate(winString); move.equity = parseEquity(equityString); @@ -246,9 +251,36 @@ static bool extractEndgameMove(QByteArray &processOutput, Quackle::Move &move) { seqStart += bestSeqMarker.length(); string sequenceStr(processOutput.data() + seqStart, processOutput.size() - seqStart); vector<string> sequence = splitLines(sequenceStr); - printf("got sequence:\n"); - for (const string &moveStr: sequence) { - printf(" | %s\n",moveStr.c_str()); + // TODO: do something with rest of moves? or just extract first move? + const string &firstMove = sequence[0]; + vector<string> moveWords = splitWords(firstMove); + if (moveWords.size() == 4) { + const string &placement = moveWords[1]; + const string &prettyTiles = moveWords[2]; + const string &scoreInParentheses = moveWords[3]; + move = createPlaceMove(placement, prettyTiles); + int score = 0; + bool scoreIsValid = scoreInParentheses[0] == '(' && scoreInParentheses.back() == ')'; + try { + size_t scoreLen = 0; + score = std::stoi(scoreInParentheses.substr(1), &scoreLen); + scoreIsValid = scoreLen == scoreInParentheses.length() - 2; + } catch (const std::invalid_argument &) { + } catch (const std::out_of_range &) { + } + if (scoreIsValid) { + move.score = score; + } else { + qWarning("bad move score syntax: %s", scoreInParentheses.c_str()); + } + processOutput.clear(); + return true; + } else if (moveWords.size() == 3 && moveWords[1] == "Pass" && moveWords[2] == "(0)") { + move = Quackle::Move::createPassMove(); + processOutput.clear(); + return true; + } else { + qWarning("bad move syntax: %s", firstMove.c_str()); } processOutput.clear(); return false; @@ -274,7 +306,7 @@ void MacondoBackend::timer() { if (!moves.empty()) { // at this point the GCG is definitely fully loaded removeTempGCG(); - emit gotSimMoves(moves); + emit gotMoves(moves); } } break; @@ -290,7 +322,10 @@ void MacondoBackend::timer() { } Quackle::Move move; if (extractEndgameMove(m_processOutput, move)) { - std::cout << "Move: " << move << std::endl; + Quackle::MoveList list; + list.push_back(move); + printf("EMIT\n"); + emit gotMoves(list); } } break; diff --git a/quacker/macondobackend.h b/quacker/macondobackend.h index dcc161d..ebb68d8 100644 --- a/quacker/macondobackend.h +++ b/quacker/macondobackend.h @@ -31,7 +31,7 @@ public: // stop current Macondo analysis void stop(); signals: - void gotSimMoves(const Quackle::MoveList &moves); + void gotMoves(const Quackle::MoveList &moves); private slots: void processStarted(); void processFinished(int, QProcess::ExitStatus); diff --git a/quacker/quacker.cpp b/quacker/quacker.cpp index b54e364..3d8d8d4 100644 --- a/quacker/quacker.cpp +++ b/quacker/quacker.cpp @@ -1052,15 +1052,19 @@ void TopLevel::ensureUpToDateSimulatorMoveList() void TopLevel::simulate(bool startSimulation) { m_simulateAction->setChecked(startSimulation); + + if (m_macondo->isRunning() && !startSimulation) { + // stop Macondo + m_macondo->stop(); + m_simulationTimer->stop(); + return; + } // it's not so useful to have sim control show/hide // like this //m_simulatorWidget->setVisible(startSimulation); if (m_macondo->useForSimulation()) { - if (startSimulation) - m_macondo->simulate(); - else - m_macondo->stop(); + m_macondo->simulate(); } if (startSimulation) { @@ -1076,6 +1080,15 @@ void TopLevel::simulateToggled(bool startSimulation) if (!m_game->hasPositions()) return; + if (startSimulation) { + // this function is called for the Macondo solver as well, + // so make sure user can stop solver through button in top bar. + m_simulateAction->setEnabled(true); + } else { + // restore previous enabledness* of Simulate action + m_simulateAction->setEnabled(!m_game->currentPosition().moves().empty()); + } + simulate(startSimulation); if (startSimulation) @@ -1254,8 +1267,9 @@ void TopLevel::incrementSimulation() if (!m_simulateAction->isChecked()) return; - if (m_macondo->useForSimulation()) { + if (m_macondo->isRunning()) { if (m_macondo->anyUpdates()) { + printf("aaa update\n"); updateMoveViews(); updateSimViews(); } @@ -2026,6 +2040,8 @@ void TopLevel::createWidgets() m_macondo = new Macondo(m_game); plugIntoMatrix(m_macondo); plugIntoPositionMatrix(m_macondo); + connect(m_macondo, SIGNAL(runningSolver()), this, SLOT(simulate())); + connect(m_macondo, SIGNAL(stoppedSolver()), this, SLOT(stopSimulation())); m_tabWidget = new QTabWidget; m_tabWidget->addTab(m_history, tr("Histor&y")); diff --git a/quacker/quacker.h b/quacker/quacker.h index 399deee..9570890 100644 --- a/quacker/quacker.h +++ b/quacker/quacker.h @@ -116,7 +116,8 @@ public slots: void htmlReport(); void graphicalReport(); void commitTopChoice(); - void simulate(bool startSimulation); + void simulate(bool startSimulation = true); + inline void stopSimulation() { simulate(false); } void simulateToggled(bool startSimulation); void clearSimulationResults(); |