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