adapter.cpp (3990B)
1 #include "adapter.h" 2 3 #include <fstream> 4 #include <sstream> 5 #include <string> 6 #include <vector> 7 #include <QDebug> 8 #include <QtConcurrent/QtConcurrent> 9 10 const std::string tablesdir = "../nissy-core/tables/"; 11 12 void logWrapper(const char *str, void *data) 13 { 14 auto f = *reinterpret_cast<std::function<void(std::string)>*>(data); 15 f(std::string{str}); 16 } 17 18 NissyAdapter::NissyAdapter() 19 { 20 // TODO: this list must be kept in sync with UI code, it is a bit ugly 21 std::vector<std::string> solverNames { 22 "h48h0k4", 23 "h48h1k2", 24 "h48h2k2", 25 "h48h3k2", 26 "h48h7k2", 27 }; 28 29 for (auto s : solverNames) 30 initSolver(s); 31 32 writeLog = [&](std::string str) { 33 emit appendLog(QString::fromStdString(str)); 34 }; 35 36 nissy::set_logger(&logWrapper, &writeLog); 37 } 38 39 void NissyAdapter::initSolver(const std::string& s) { 40 auto se = nissy::solver::get(s); 41 if (std::holds_alternative<nissy::error>(se)) { 42 qDebug("Error loading solver!"); 43 return; 44 } 45 auto ss = std::get<nissy::solver>(se); 46 solvers.push_back(ss); 47 } 48 49 bool NissyAdapter::loadSolverData(nissy::solver& solver) { 50 if (solver.data_checked) 51 return true; 52 53 std::filesystem::path filePath(tablesdir + solver.id); 54 if (!std::filesystem::exists(filePath)) { 55 logLine("Data file for solver " + solver.name + " not found, " 56 "generating it..."); 57 auto err = solver.generate_data(); 58 if (!err.ok()) { 59 emit solverError(QString("Error generating data!")); 60 return false; 61 } 62 std::filesystem::create_directory(tablesdir); 63 std::ofstream ofs(filePath, std::ios::binary); 64 ofs.write(reinterpret_cast<char *>(solver.data.data()), 65 solver.size); 66 ofs.close(); 67 logLine("Data generated succesfully"); 68 } else { 69 logLine("Reading data for solver " + solver.name + 70 " from file"); 71 std::ifstream ifs(filePath, std::ios::binary); 72 solver.read_data(ifs); 73 ifs.close(); 74 logLine("Data loaded"); 75 } 76 77 logLine("Checking data integrity " 78 "(this is done only once per solver per session)..."); 79 if (!solver.check_data().ok()) { 80 emit solverError(QString("Error reading data!")); 81 return false; 82 } 83 logLine("Data checked"); 84 85 return true; 86 } 87 88 Q_INVOKABLE bool NissyAdapter::isValidScramble(QString qscr) 89 { 90 nissy::cube c; 91 return c.move(qscr.toStdString()).ok(); 92 } 93 94 Q_INVOKABLE void NissyAdapter::requestSolve( 95 QString scramble, 96 QString solver, 97 int minmoves, 98 int maxmoves, 99 int maxsolutions, 100 int optimal 101 ) 102 { 103 nissy::cube c; 104 if (!c.move(scramble.toStdString()).ok()) { 105 emit solverError(QString("Unexpected error: invalid scramble")); 106 return; 107 } 108 109 nissy::solver *ss = nullptr; 110 for (auto& s : solvers) 111 if (s.name == solver) 112 ss = &s; 113 if (ss == nullptr) { 114 std::string msg = "Error: solver '" + solver.toStdString() 115 + "' not available"; 116 emit solverError(QString::fromStdString(msg)); 117 return; 118 } 119 120 SolveOptions opts{c, ss, (unsigned)minmoves, (unsigned)maxmoves, 121 (unsigned)maxsolutions, (unsigned)optimal}; 122 auto _ = QtConcurrent::run(&NissyAdapter::startSolve, this, opts); 123 return; 124 } 125 126 void NissyAdapter::startSolve(SolveOptions opts) 127 { 128 loadSolverData(*opts.solver); 129 130 auto result = opts.solver->solve(opts.cube, nissy::nissflag::NORMAL, 131 opts.minmoves, opts.maxmoves, opts.maxsolutions, opts.optimal, 8); 132 133 if (!result.err.ok()) { 134 std::string msg = "Error computing solutions: " + 135 std::to_string(result.err.value); 136 emit solverError(QString::fromStdString(msg)); 137 return; 138 } 139 140 auto& sols = result.solutions; 141 if (sols.size() == 0) { 142 emit solutionsReady("No solution found", ""); 143 } else { 144 std::stringstream hs; 145 hs << "Found " << sols.size() << " solution" 146 << (sols.size() > 1 ? "s:" : ":"); 147 148 std::stringstream ss; 149 for (auto s : sols) { 150 auto n = nissy::count_moves(s).value; 151 ss << s << " (" << n << ")" << std::endl; // TODO: remove last newline 152 } 153 emit solutionsReady(QString::fromStdString(hs.str()), 154 QString::fromStdString(ss.str())); 155 } 156 } 157 158 void NissyAdapter::logLine(std::string str) 159 { 160 std::stringstream ss; 161 ss << str << std::endl; 162 writeLog(ss.str()); 163 }