From 97b5778172572504c8dfbe173b18281e786270c0 Mon Sep 17 00:00:00 2001 From: Sebastiano Tronto Date: Fri, 25 Apr 2025 16:18:26 +0200 Subject: Initial commit --- qt-widgets/README.md | 8 ++++ qt-widgets/adapter.cpp | 46 +++++++++++++++++++++ qt-widgets/adapter.h | 35 ++++++++++++++++ qt-widgets/main.cpp | 11 ++++++ qt-widgets/nissyqt.pro | 18 +++++++++ qt-widgets/nissywindow.cpp | 35 ++++++++++++++++ qt-widgets/nissywindow.h | 36 +++++++++++++++++ qt-widgets/nissywindow.ui | 33 ++++++++++++++++ qt-widgets/solvercfgwidget.cpp | 90 ++++++++++++++++++++++++++++++++++++++++++ qt-widgets/solvercfgwidget.h | 43 ++++++++++++++++++++ qt-widgets/solvercfgwidget.ui | 81 +++++++++++++++++++++++++++++++++++++ 11 files changed, 436 insertions(+) create mode 100644 qt-widgets/README.md create mode 100644 qt-widgets/adapter.cpp create mode 100644 qt-widgets/adapter.h create mode 100644 qt-widgets/main.cpp create mode 100644 qt-widgets/nissyqt.pro create mode 100644 qt-widgets/nissywindow.cpp create mode 100644 qt-widgets/nissywindow.h create mode 100644 qt-widgets/nissywindow.ui create mode 100644 qt-widgets/solvercfgwidget.cpp create mode 100644 qt-widgets/solvercfgwidget.h create mode 100644 qt-widgets/solvercfgwidget.ui (limited to 'qt-widgets') diff --git a/qt-widgets/README.md b/qt-widgets/README.md new file mode 100644 index 0000000..f19c5b4 --- /dev/null +++ b/qt-widgets/README.md @@ -0,0 +1,8 @@ +# QT-widgets implementation of a nissy UI + +This is a UI for nissy written using +[QT Widgets](https://doc.qt.io/qt-6/qtwidgets-index.html) + +You can't actually build or run this as is, because it relies on +an older version of the C++ bindings for nissy. I'll fix it +at some point, maybe. diff --git a/qt-widgets/adapter.cpp b/qt-widgets/adapter.cpp new file mode 100644 index 0000000..c15181c --- /dev/null +++ b/qt-widgets/adapter.cpp @@ -0,0 +1,46 @@ +#include "adapter.h" + +#include +#include +#include +#include +#include + +NissyAdapter::NissyAdapter() +{ + auto sid = nissy::solverinfo(defaultOptimalSolver); + auto [sz, dataid] = std::get>(sid); + const std::string path = "../nissy-core/tables/" + dataid; + + std::filesystem::path filePath(path); + if (std::filesystem::file_size(filePath) != static_cast(sz)) + qDebug("Error in file size!"); // TODO: better handle error, gentable + + optimalSolverData.value.resize(sz); + std::ifstream ifs(path, std::ios::binary); + ifs.read(reinterpret_cast(optimalSolverData.value.data()), sz); + ifs.close(); +} + +NissyAdapter::~NissyAdapter() {} + +void NissyAdapter::solve(SolverConfiguration cfg) +{ + auto se = nissy::solve(cfg.cube, defaultOptimalSolver, + nissy::nissflag::NORMAL, cfg.minmoves, cfg.maxmoves, + cfg.maxsolutions, cfg.optimal, cfg.threads, optimalSolverData); + if (std::holds_alternative(se)) { + auto code = std::get(se).value; + emit solveDone(QString("Error " + code)); + return; + } + + auto [sols, stats] = std::get(se); + if (sols.size() == 0) { + emit solveDone(QString("No solution found")); + } else { + auto solstr = std::accumulate( + sols.begin(), sols.end(), std::string{}); + emit solveDone(QString::fromStdString(solstr)); + } +} diff --git a/qt-widgets/adapter.h b/qt-widgets/adapter.h new file mode 100644 index 0000000..9fc35fa --- /dev/null +++ b/qt-widgets/adapter.h @@ -0,0 +1,35 @@ +#ifndef ADAPTER_H +#define ADAPTER_H + +#include "../nissy-core/cpp/nissy.h" + +#include +#include +#include + +struct SolverConfiguration { + nissy::cube cube{nissy::cube::SOLVED}; + unsigned minmoves{0}; + unsigned maxmoves{20}; + unsigned maxsolutions{1}; + int optimal{-1}; + int threads{8}; +}; + +class NissyAdapter : public QObject { + Q_OBJECT + +public: + NissyAdapter(); + ~NissyAdapter(); + void solve(SolverConfiguration); + +signals: + void solveDone(QString); + +private: + static constexpr nissy::solver defaultOptimalSolver{"h48h3k2"}; + nissy::solver_data_t optimalSolverData; +}; + +#endif diff --git a/qt-widgets/main.cpp b/qt-widgets/main.cpp new file mode 100644 index 0000000..5addb96 --- /dev/null +++ b/qt-widgets/main.cpp @@ -0,0 +1,11 @@ +#include "nissywindow.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + NissyWindow w; + w.show(); + return a.exec(); +} diff --git a/qt-widgets/nissyqt.pro b/qt-widgets/nissyqt.pro new file mode 100644 index 0000000..43f198c --- /dev/null +++ b/qt-widgets/nissyqt.pro @@ -0,0 +1,18 @@ +# Source files +SOURCES = main.cpp adapter.cpp nissywindow.cpp solvercfgwidget.cpp +HEADERS = adapter.h nissywindow.h solvercfgwidget.h +FORMS = nissywindow.ui solvercfgwidget.ui + +# Add nissy backend headers and code +SOURCES += ../nissy-core/cpp/nissy.cpp +HEADERS += ../nissy-core/cpp/nissy.h + +# Compiler configuration +CONFIG += qt debug c++20 +LIBS += ../nissy-core/nissy.o +QT += widgets concurrent + +# Destination folders for generated files +MOC_DIR = generated_files +UI_DIR = generated_files +OBJECTS_DIR = build diff --git a/qt-widgets/nissywindow.cpp b/qt-widgets/nissywindow.cpp new file mode 100644 index 0000000..98cfc86 --- /dev/null +++ b/qt-widgets/nissywindow.cpp @@ -0,0 +1,35 @@ +#include "nissywindow.h" +#include "./ui_nissywindow.h" +#include "nissy/cpp/nissy.h" + +#include + +NissyWindow::NissyWindow(QWidget *parent) + : QMainWindow(parent), ui(new Ui::NissyWindow) +{ + ui->setupUi(this); + + QObject::connect(ui->solverCfgWidget, + SIGNAL(solveRequest(const SolverConfiguration&)), this, + SLOT(startSolve(const SolverConfiguration&))); + QObject::connect(&adapter, SIGNAL(solveDone(QString)), this, + SLOT(showSolutions(QString))); +} + +NissyWindow::~NissyWindow() +{ + delete ui; +} + +void NissyWindow::startSolve(const SolverConfiguration& config) +{ + ui->solverCfgWidget->lockSubmit(); + ui->solutionsLabel->setText("Loading solutions..."); + auto _ = QtConcurrent::run(&NissyAdapter::solve, &adapter, config); +} + +void NissyWindow::showSolutions(QString solutions) { + QString header = QString("Solution(s) found:\n"); + ui->solutionsLabel->setText(header + solutions); + ui->solverCfgWidget->unlockSubmit(); +} diff --git a/qt-widgets/nissywindow.h b/qt-widgets/nissywindow.h new file mode 100644 index 0000000..c2e7b44 --- /dev/null +++ b/qt-widgets/nissywindow.h @@ -0,0 +1,36 @@ +#ifndef NISSYWINDOW_H +#define NISSYWINDOW_H + +#include "adapter.h" +#include "solvercfgwidget.h" + +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE +namespace Ui { +class NissyWindow; +} +QT_END_NAMESPACE + +class NissyWindow : public QMainWindow +{ + Q_OBJECT + +public: + NissyWindow(QWidget *parent = nullptr); + ~NissyWindow(); + +private slots: + void showSolutions(QString); + void startSolve(const SolverConfiguration&); + +private: + Ui::NissyWindow *ui; + NissyAdapter adapter; +}; + +#endif diff --git a/qt-widgets/nissywindow.ui b/qt-widgets/nissywindow.ui new file mode 100644 index 0000000..6b11229 --- /dev/null +++ b/qt-widgets/nissywindow.ui @@ -0,0 +1,33 @@ + + +NissyWindow + + + + + 0 + 0 + 800 + 600 + + + + Nissy 3.0 - preview + + + + + + + + + + + + + + + + + + diff --git a/qt-widgets/solvercfgwidget.cpp b/qt-widgets/solvercfgwidget.cpp new file mode 100644 index 0000000..8027fe5 --- /dev/null +++ b/qt-widgets/solvercfgwidget.cpp @@ -0,0 +1,90 @@ +#include "solvercfgwidget.h" +#include "./ui_solvercfgwidget.h" + +enum class ScrambleState { empty, valid, invalid }; + +ScrambleState getScrambleState(const std::string&); + +SolverCfgWidget::SolverCfgWidget(QWidget *parent) + : QWidget(parent), ui(new Ui::SolverCfgWidget) +{ + ui->setupUi(this); + onScrambleChanged(ui->scrambleEditor->text()); + + nmovesValidator = new QIntValidator(0, 20, this); + ui->minMovesEditor->setValidator(nmovesValidator); + ui->maxMovesEditor->setValidator(nmovesValidator); + + QObject::connect(ui->scrambleEditor, + SIGNAL(textChanged(const QString&)), this, + SLOT(onScrambleChanged(const QString&))); + QObject::connect(ui->scrambleEditor, SIGNAL(returnPressed()), + this, SLOT(onScrambleSubmitted())); + QObject::connect(ui->solveButton, SIGNAL(clicked()), + this, SLOT(onScrambleSubmitted())); +} + +SolverCfgWidget::~SolverCfgWidget() +{ + delete nmovesValidator; + delete ui; +} + +void SolverCfgWidget::lockSubmit() +{ + submitLocked = true; + onScrambleChanged(ui->scrambleEditor->text()); +} + +void SolverCfgWidget::unlockSubmit() +{ + submitLocked = false; + onScrambleChanged(ui->scrambleEditor->text()); +} + +void SolverCfgWidget::onScrambleChanged(const QString& text) +{ + auto scrambleState = getScrambleState(text.toStdString()); + switch (scrambleState) { + case ScrambleState::empty: + ui->solveButton->setEnabled(false); + ui->scrambleEditor->setStyleSheet(""); + break; + case ScrambleState::valid: + ui->solveButton->setEnabled(!submitLocked); + ui->scrambleEditor->setStyleSheet(""); + break; + case ScrambleState::invalid: + ui->solveButton->setEnabled(false); + ui->scrambleEditor->setStyleSheet("border : 2px solid red"); + break; + } +} + +void SolverCfgWidget::onScrambleSubmitted() +{ + std::string scramble = ui->scrambleEditor->text().toStdString(); + auto state = getScrambleState(scramble); + if (state != ScrambleState::valid) + return; + + SolverConfiguration sc { + .cube = std::get(nissy::applymoves( + nissy::cube::SOLVED, nissy::moves_t{scramble})), + .minmoves = ui->minMovesEditor->text().toUInt(), + .maxmoves = ui->maxMovesEditor->text().toUInt(), + }; + emit solveRequest(sc); +} + +ScrambleState getScrambleState(const std::string& s) +{ + if (std::all_of(s.begin(), s.end(), + [](std::string::value_type c){ return std::isspace(c); })) + return ScrambleState::empty; + + auto c = nissy::applymoves(nissy::cube::SOLVED, nissy::moves_t{s}); + return std::holds_alternative(c) ? + ScrambleState::invalid : ScrambleState::valid; +} + diff --git a/qt-widgets/solvercfgwidget.h b/qt-widgets/solvercfgwidget.h new file mode 100644 index 0000000..b6494c8 --- /dev/null +++ b/qt-widgets/solvercfgwidget.h @@ -0,0 +1,43 @@ +#ifndef SOLVERCFGWIDGET_H +#define SOLVERCFGWIDGET_H + +#include "adapter.h" + +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE +namespace Ui { +class SolverCfgWidget; +} +QT_END_NAMESPACE + +class SolverCfgWidget : public QWidget +{ + Q_OBJECT + +public: + SolverCfgWidget(QWidget *parent); + ~SolverCfgWidget(); + + void lockSubmit(); + void unlockSubmit(); + +signals: + void solveRequest(const SolverConfiguration&); + +private slots: + void onScrambleChanged(const QString&); + void onScrambleSubmitted(); + +private: + bool submitLocked; + QIntValidator *nmovesValidator; + + Ui::SolverCfgWidget *ui; +}; + +#endif diff --git a/qt-widgets/solvercfgwidget.ui b/qt-widgets/solvercfgwidget.ui new file mode 100644 index 0000000..19ff082 --- /dev/null +++ b/qt-widgets/solvercfgwidget.ui @@ -0,0 +1,81 @@ + + +SolverCfgWidget + + + + + + + + + + Enter your scramble here... + + + + + + + + Solve! + + + + + + + + + + + + Min moves + + + + + + + + + 25 + 20 + + + + + 0 + + + + + + + + Max moves + + + > + + + + + + 25 + 20 + + + + + 20 + + + + + + + + + + -- cgit v1.3