summaryrefslogtreecommitdiff
path: root/quacker/macondobackend.cpp
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/macondobackend.cpp
parent91af6685bdbfad63a035bb7997a8f3d2eb20d64a (diff)
MacondoBackend
Diffstat (limited to 'quacker/macondobackend.cpp')
-rw-r--r--quacker/macondobackend.cpp110
1 files changed, 110 insertions, 0 deletions
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();
+}