summaryrefslogtreecommitdiff
path: root/quacker
diff options
context:
space:
mode:
authorpommicket <pommicket@gmail.com>2025-08-08 10:42:40 -0400
committerpommicket <pommicket@gmail.com>2025-08-08 10:42:40 -0400
commit551c51c02649aeb38d72002d6bb70b58dbee1eb2 (patch)
treec8b7117657854171105c14e8568a6ec8c489e30f /quacker
parent91af6685bdbfad63a035bb7997a8f3d2eb20d64a (diff)
MacondoBackend
Diffstat (limited to 'quacker')
-rw-r--r--quacker/CMakeLists.txt2
-rw-r--r--quacker/macondo.cpp98
-rw-r--r--quacker/macondo.h24
-rw-r--r--quacker/macondobackend.cpp110
-rw-r--r--quacker/macondobackend.h48
-rw-r--r--quacker/quacker.cpp7
6 files changed, 187 insertions, 102 deletions
diff --git a/quacker/CMakeLists.txt b/quacker/CMakeLists.txt
index ac60a7d..966e8f6 100644
--- a/quacker/CMakeLists.txt
+++ b/quacker/CMakeLists.txt
@@ -40,6 +40,7 @@ set(QUACKLE_SOURCES
lexicondialog.cpp
lister.cpp
macondo.cpp
+ macondobackend.cpp
main.cpp
movebox.cpp
newgame.cpp
@@ -74,6 +75,7 @@ set(QUACKLE_HEADERS
lexicondialog.h
lister.h
macondo.h
+ macondobackend.h
movebox.h
newgame.h
noteeditor.h
diff --git a/quacker/macondo.cpp b/quacker/macondo.cpp
index e5ccf8e..83e4553 100644
--- a/quacker/macondo.cpp
+++ b/quacker/macondo.cpp
@@ -1,14 +1,12 @@
#include "macondo.h"
+#include "macondobackend.h"
#include "quacker.h"
#include <QGridLayout>
#include <QPushButton>
-#include <QProcess>
#include <QTimer>
-#include <random>
-Macondo::Macondo(TopLevel *topLevel) : View() {
- m_topLevel = topLevel;
+Macondo::Macondo(Quackle::Game *game) : QWidget() {
m_updateTimer = new QTimer(this);
QGridLayout *layout = new QGridLayout(this);
m_simulateButton = new QPushButton(tr("Simulate"));
@@ -16,94 +14,30 @@ Macondo::Macondo(TopLevel *topLevel) : View() {
layout->setAlignment(Qt::AlignTop);
const char *home = getenv("HOME");
// TODO: configurable path
- m_execPath = home ? home : "/";
- m_execPath += "/apps/macondo/macondo";
+ std::string execPath = home ? home : "/";
+ execPath += "/apps/macondo/macondo";
+ MacondoBackend::InitOptions initOptions(execPath);
+ m_backend = new MacondoBackend(game, initOptions);
connect(m_simulateButton, SIGNAL(clicked()), this, SLOT(simulate()));
connect(m_updateTimer, SIGNAL(timeout()), this, SLOT(updateResults()));
m_updateTimer->setInterval(1000);
}
void Macondo::simulate() {
- if (m_process) return;
- printf("running macondo %s\n", m_execPath.c_str());
- m_process = new QProcess;
- QStringList args;
- m_process->start(m_execPath.c_str(), args);
- connect(m_process, SIGNAL(started()), this, SLOT(processStarted()));
- connect(m_process, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(processFinished(int, QProcess::ExitStatus)));
- m_command = Command::Simulate;
+ MacondoBackend::SimulateOptions options;
+ m_backend->simulate(options);
+ m_updateTimer->start();
}
-void Macondo::processStarted() {
- m_updateTimer->start();
- loadGCG();
- switch (m_command) {
- case Command::None:
- throw "process started with no command";
- case Command::Simulate:
- m_process->write("gen\nsim\n");
- m_runningSimulation = true;
+void Macondo::updateResults() {
+ switch (m_backend->command()) {
+ case MacondoCommand::None:
break;
- case Command::Solve:
+ case MacondoCommand::Simulate:
+ m_backend->getSimResults();
+ break;
+ case MacondoCommand::Solve:
// TODO
break;
}
}
-
-void Macondo::killProcess() {
- if (m_process) {
- m_process->kill();
- }
-}
-
-void Macondo::processFinished(int, QProcess::ExitStatus) {
- delete m_process;
- m_process = nullptr;
-}
-
-Macondo::~Macondo() {
- killProcess();
-}
-
-void Macondo::loadGCG() {
- std::default_random_engine rand;
- std::uniform_int_distribution<int> distribution(0, 26);
- // save game file with random name
- char filename[] = "tmpGameXXXXXXXXXXXX.gcg";
- for (int i = 0; filename[i]; i++) {
- if (filename[i] == 'X') {
- filename[i] = distribution(rand) + 'A';
- }
- }
- m_topLevel->writeFile(filename);
- std::stringstream commands;
- commands << "load " << filename << "\n"
- << "turn " << m_viewingPlyNumber << "\n";
- m_process->write(commands.str().c_str());
-}
-
-void Macondo::updateResults() {
- if (m_runningSimulation) {
- m_process->write("sim show\n");
- }
- QByteArray data = m_process->readAllStandardError();
- printf("%s",data.constData());
- data = m_process->readAllStandardOutput();
- printf("%s", data.constData());
- fflush(stdout);
-}
-
-void Macondo::positionChanged(const Quackle::GamePosition *position) {
- int playerIndex = 0, numPlayers = position->players().size();
- for (const Quackle::Player &player: position->players()) {
- if (player.id() == position->playerOnTurn().id()) {
- break;
- }
- playerIndex++;
- }
- if (playerIndex >= numPlayers) {
- throw "couldn't find player in player list";
- }
- m_viewingPlyNumber = (position->turnNumber() - 1) * numPlayers
- + playerIndex;
-}
diff --git a/quacker/macondo.h b/quacker/macondo.h
index b8dbf73..77af35f 100644
--- a/quacker/macondo.h
+++ b/quacker/macondo.h
@@ -1,38 +1,28 @@
-#include <QProcess>
#include <QWidget>
-#include "view.h"
-
-
class QPushButton;
class QTimer;
-class TopLevel;
+namespace Quackle {
+ class Game;
+}
+class MacondoBackend;
-class Macondo : public View {
+class Macondo : public QWidget {
Q_OBJECT
public:
- Macondo(TopLevel *topLevel);
- ~Macondo();
+ Macondo(Quackle::Game *);
public slots:
void simulate();
void updateResults();
- void processStarted();
- void processFinished(int, QProcess::ExitStatus);
- virtual void positionChanged(const Quackle::GamePosition *position);
private:
enum class Command {
None,
Simulate,
Solve,
};
- void loadGCG();
- void killProcess();
- TopLevel *m_topLevel;
QPushButton *m_simulateButton;
QTimer *m_updateTimer;
- std::string m_execPath;
- QProcess *m_process = nullptr;
+ MacondoBackend *m_backend;
int m_viewingPlyNumber = 0;
- bool m_runningSimulation = false;
Command m_command = Command::None;
};
diff --git a/quacker/macondobackend.cpp b/quacker/macondobackend.cpp
new file mode 100644
index 0000000..e172b9d
--- /dev/null
+++ b/quacker/macondobackend.cpp
@@ -0,0 +1,110 @@
+#include "macondobackend.h"
+#include "quackleio/gcgio.h"
+#include "game.h"
+
+#include <QFile>
+#include <QProcess>
+#include <QTextStream>
+#include <random>
+
+static int getPlyNumber(const Quackle::GamePosition &position) {
+ int playerIndex = 0, numPlayers = position.players().size();
+ for (const Quackle::Player &player: position.players()) {
+ if (player.id() == position.playerOnTurn().id()) {
+ break;
+ }
+ playerIndex++;
+ }
+ if (playerIndex >= numPlayers) {
+ throw "couldn't find player in player list";
+ }
+ return (position.turnNumber() - 1) * numPlayers
+ + playerIndex;
+}
+
+
+MacondoBackend::MacondoBackend(Quackle::Game *game, const InitOptions &options) {
+ m_execPath = options.execPath;
+ m_game = game;
+}
+
+void MacondoBackend::simulate(const SimulateOptions &) {
+ if (m_process) return;
+ printf("running macondo %s\n", m_execPath.c_str());
+ m_process = new QProcess;
+ QStringList args;
+ m_process->start(m_execPath.c_str(), args);
+ connect(m_process, SIGNAL(started()), this, SLOT(processStarted()));
+ connect(m_process, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(processFinished(int, QProcess::ExitStatus)));
+ m_command = MacondoCommand::Simulate;
+}
+
+void MacondoBackend::processStarted() {
+ loadGCG();
+ switch (m_command) {
+ case MacondoCommand::None:
+ throw "process started with no command";
+ case MacondoCommand::Simulate:
+ m_process->write("gen\nsim\n");
+ m_runningSimulation = true;
+ break;
+ case MacondoCommand::Solve:
+ // TODO
+ break;
+ }
+}
+
+void MacondoBackend::loadGCG() {
+ std::random_device randDev;
+ std::mt19937 rand(randDev());
+ std::uniform_int_distribution<int> distribution(0, 26);
+ if (!m_tempGCG.empty()) {
+ remove(m_tempGCG.c_str());
+ }
+ // save game file with random name
+ char filename[] = "tmpGameXXXXXXXXXXXX.gcg";
+ for (int i = 0; filename[i]; i++) {
+ if (filename[i] == 'X') {
+ filename[i] = distribution(rand) + 'A';
+ }
+ }
+ m_tempGCG = filename;
+ QuackleIO::GCGIO gcg;
+ {
+ QFile file(filename);
+ file.open(QIODevice::WriteOnly | QIODevice::Text);
+ QTextStream fileStream(&file);
+ gcg.write(*m_game, fileStream);
+ }
+ std::stringstream commands;
+ commands << "load " << filename << "\n"
+ << "turn " << getPlyNumber(m_game->currentPosition()) << "\n";
+ m_process->write(commands.str().c_str());
+}
+
+void MacondoBackend::killProcess() {
+ if (m_process) {
+ m_process->kill();
+ }
+}
+
+void MacondoBackend::processFinished(int, QProcess::ExitStatus) {
+ delete m_process;
+ m_process = nullptr;
+}
+
+std::string MacondoBackend::getSimResults() {
+ if (m_runningSimulation) {
+ m_process->write("sim show\n");
+ }
+ QByteArray data = m_process->readAllStandardError();
+ fprintf(stderr,"%s",data.constData());
+ data = m_process->readAllStandardOutput();
+ printf("%s", data.constData());
+ fflush(stdout);
+ return "";
+}
+
+MacondoBackend::~MacondoBackend() {
+ killProcess();
+}
diff --git a/quacker/macondobackend.h b/quacker/macondobackend.h
new file mode 100644
index 0000000..dfda0c5
--- /dev/null
+++ b/quacker/macondobackend.h
@@ -0,0 +1,48 @@
+#ifndef MACONDO_BACKEND_H_
+#define MACONDO_BACKEND_H_
+
+#include <QObject>
+#include <QProcess>
+
+namespace Quackle {
+ class Game;
+}
+
+enum class MacondoCommand {
+ None,
+ Simulate,
+ Solve,
+};
+
+class MacondoBackend: public QObject {
+Q_OBJECT
+public:
+ struct InitOptions {
+ inline InitOptions(std::string execPath) {
+ this->execPath = execPath;
+ }
+ std::string execPath;
+ };
+ MacondoBackend(Quackle::Game *game, const InitOptions &);
+ struct SimulateOptions {
+ inline SimulateOptions() {}
+ };
+ void simulate(const SimulateOptions &);
+ ~MacondoBackend();
+ std::string getSimResults();
+ inline MacondoCommand command() const { return m_command; }
+protected slots:
+ void processStarted();
+ void processFinished(int, QProcess::ExitStatus);
+private:
+ void loadGCG();
+ void killProcess();
+ std::string m_execPath;
+ std::string m_tempGCG;
+ QProcess *m_process = nullptr;
+ bool m_runningSimulation = false;
+ Quackle::Game *m_game;
+ MacondoCommand m_command = MacondoCommand::None;
+};
+
+#endif
diff --git a/quacker/quacker.cpp b/quacker/quacker.cpp
index af50d2f..3502c3a 100644
--- a/quacker/quacker.cpp
+++ b/quacker/quacker.cpp
@@ -1293,7 +1293,10 @@ void TopLevel::loadFile(const QString &filename)
}
QTextStream stream(&file);
+ delete m_game;
m_game = logania->read(stream, QuackleIO::Logania::MaintainBoardPreparation);
+ delete m_macondo;
+ m_macondo = new Macondo(m_game);
file.close();
@@ -2001,9 +2004,7 @@ void TopLevel::createWidgets()
m_history = new History;
plugIntoHistoryMatrix(m_history);
- m_macondo = new Macondo(this);
- plugIntoMatrix(m_macondo);
- plugIntoPositionMatrix(m_macondo);
+ m_macondo = new Macondo(m_game);
m_tabWidget = new QTabWidget;
m_tabWidget->addTab(m_history, tr("Histor&y"));