diff options
Diffstat (limited to '')
| -rw-r--r-- | cpp/examples/move_convert.cpp | 24 | ||||
| -rw-r--r-- | cpp/examples/solve_h48h3k2.cpp | 91 | ||||
| -rw-r--r-- | cpp/nissy.cpp | 289 | ||||
| -rw-r--r-- | cpp/nissy.h | 174 |
4 files changed, 345 insertions, 233 deletions
diff --git a/cpp/examples/move_convert.cpp b/cpp/examples/move_convert.cpp new file mode 100644 index 0000000..11398df --- /dev/null +++ b/cpp/examples/move_convert.cpp | |||
| @@ -0,0 +1,24 @@ | |||
| 1 | /* A simple example showing how to move a cube and print it in H48 format. */ | ||
| 2 | |||
| 3 | #include "../nissy.h" | ||
| 4 | #include <iostream> | ||
| 5 | |||
| 6 | int main() { | ||
| 7 | nissy::cube c; | ||
| 8 | if (!c.move("R' U' F").ok()) { | ||
| 9 | std::cout << "Error moving the cube!" << std::endl; | ||
| 10 | return 1; | ||
| 11 | } | ||
| 12 | |||
| 13 | auto string_or_error = c.to_string("H48"); | ||
| 14 | if (std::holds_alternative<nissy::error>(string_or_error)) { | ||
| 15 | std::cout << "Error converting cube!" << std::endl; | ||
| 16 | return 1; | ||
| 17 | } | ||
| 18 | |||
| 19 | auto str = std::get<std::string>(string_or_error); | ||
| 20 | std::cout << "Cube in H48 format after R' U' F:" << std::endl | ||
| 21 | << str << std::endl; | ||
| 22 | |||
| 23 | return 0; | ||
| 24 | } | ||
diff --git a/cpp/examples/solve_h48h3k2.cpp b/cpp/examples/solve_h48h3k2.cpp new file mode 100644 index 0000000..6639c55 --- /dev/null +++ b/cpp/examples/solve_h48h3k2.cpp | |||
| @@ -0,0 +1,91 @@ | |||
| 1 | /* Simple demo for an H48 solver */ | ||
| 2 | |||
| 3 | #include "../nissy.h" | ||
| 4 | #include <filesystem> | ||
| 5 | #include <fstream> | ||
| 6 | #include <iostream> | ||
| 7 | #include <string> | ||
| 8 | |||
| 9 | extern "C" { | ||
| 10 | long long nissy_setlogger(void (*)(const char *)); | ||
| 11 | } | ||
| 12 | |||
| 13 | int main() { | ||
| 14 | // Get verbose output | ||
| 15 | nissy_setlogger([](const char* s) { std::cout << s; }); | ||
| 16 | |||
| 17 | // Get the scramble from the user | ||
| 18 | std::cout << "Enter scramble: "; | ||
| 19 | std::string scramble; | ||
| 20 | std::getline(std::cin, scramble); | ||
| 21 | |||
| 22 | // Apply scramble to a solved cube | ||
| 23 | nissy::cube c; | ||
| 24 | if (!c.move(scramble).ok()) { | ||
| 25 | std::cout << "Invalid scramble!" << std::endl; | ||
| 26 | return 1; | ||
| 27 | } | ||
| 28 | |||
| 29 | // Ask for a limit on the solution's length | ||
| 30 | int maxmoves; | ||
| 31 | std::cout << "Maximum number of moves: "; | ||
| 32 | std::cin >> maxmoves; | ||
| 33 | |||
| 34 | // Load the solver | ||
| 35 | auto h48h3k2 = std::get<nissy::solver>(nissy::solver::get("h48h3k2")); | ||
| 36 | std::filesystem::path tableDir("tables"); | ||
| 37 | std::filesystem::create_directories(tableDir); // Ignored if dir exists | ||
| 38 | std::filesystem::path tableFile("tables/" + h48h3k2.id); | ||
| 39 | |||
| 40 | // If the table is not present, generate it | ||
| 41 | if (!std::filesystem::exists(tableFile)) { | ||
| 42 | std::cout << "Data for h48h3k2 solver was not found, " | ||
| 43 | << "generating it..." << std::endl; | ||
| 44 | auto err = h48h3k2.generate_data(); | ||
| 45 | if (!err.ok()) { | ||
| 46 | std::cout << "Unexpected error! Error code: " | ||
| 47 | << err.value << std::endl; | ||
| 48 | return 1; | ||
| 49 | } | ||
| 50 | std::ofstream ofs(tableFile, std::ios::binary); | ||
| 51 | ofs.write(reinterpret_cast<char *>(h48h3k2.data.data()), | ||
| 52 | h48h3k2.size); | ||
| 53 | std::cout << "Table generated and written to " | ||
| 54 | << tableFile << std::endl; | ||
| 55 | ofs.close(); | ||
| 56 | } | ||
| 57 | // Otherwise read it from file | ||
| 58 | else { | ||
| 59 | std::cout << "Loading data table from file" << std::endl; | ||
| 60 | std::ifstream ifs(tableFile, std::ios::binary); | ||
| 61 | h48h3k2.read_data(ifs); | ||
| 62 | ifs.close(); | ||
| 63 | std::cout << "Data loaded, checking table..." << std::endl; | ||
| 64 | auto err = h48h3k2.check_data(); | ||
| 65 | if (!err.ok()) { | ||
| 66 | std::cout << "Error reading data table from file! " | ||
| 67 | << "Error code: " << err.value << std::endl; | ||
| 68 | return 1; | ||
| 69 | } | ||
| 70 | std::cout << "Data table loaded" << std::endl; | ||
| 71 | } | ||
| 72 | |||
| 73 | // Solve | ||
| 74 | auto solve_result = h48h3k2.solve(c, nissy::nissflag::NORMAL, | ||
| 75 | 0, maxmoves, 1, -1, 8); | ||
| 76 | |||
| 77 | // Write the result | ||
| 78 | if (!solve_result.err.ok()) { | ||
| 79 | std::cout << "Error solving! Error code: " << | ||
| 80 | solve_result.err.value << std::endl; | ||
| 81 | return 1; | ||
| 82 | } | ||
| 83 | |||
| 84 | if (solve_result.solutions.size() == 0) | ||
| 85 | std::cout << "No solution found!" << std::endl; | ||
| 86 | else | ||
| 87 | std::cout << "Solution: " << | ||
| 88 | solve_result.solutions[0] << std::endl; | ||
| 89 | |||
| 90 | return 0; | ||
| 91 | } | ||
diff --git a/cpp/nissy.cpp b/cpp/nissy.cpp index 7987f6c..ad0eb7c 100644 --- a/cpp/nissy.cpp +++ b/cpp/nissy.cpp | |||
| @@ -6,6 +6,8 @@ TODO: add more documentation (here and in README.md) | |||
| 6 | 6 | ||
| 7 | #include "./nissy.h" | 7 | #include "./nissy.h" |
| 8 | 8 | ||
| 9 | #include <fstream> | ||
| 10 | |||
| 9 | extern "C" { | 11 | extern "C" { |
| 10 | long long nissy_compose(const char *, const char *, char *); | 12 | long long nissy_compose(const char *, const char *, char *); |
| 11 | long long nissy_inverse(const char *, char *); | 13 | long long nissy_inverse(const char *, char *); |
| @@ -26,191 +28,214 @@ extern "C" { | |||
| 26 | } | 28 | } |
| 27 | 29 | ||
| 28 | namespace nissy { | 30 | namespace nissy { |
| 29 | namespace utils { | ||
| 30 | void fixstr(std::string& str) | ||
| 31 | { | ||
| 32 | size_t n = str.find('\0'); | ||
| 33 | str.resize(n); | ||
| 34 | } | ||
| 35 | |||
| 36 | std::variant<cube_t, error_t> | ||
| 37 | cube_or_error(const char *r, long long e) | ||
| 38 | { | ||
| 39 | if (e < 0) | ||
| 40 | return error_t{e}; | ||
| 41 | return cube_t{r}; | ||
| 42 | } | ||
| 43 | 31 | ||
| 44 | std::variant<std::string, error_t> | 32 | /* Definition of constants with const qualifier */ |
| 45 | string_or_error(const char *cstr, long long e) | 33 | const nissflag nissflag::NORMAL{1}; |
| 46 | { | 34 | const nissflag nissflag::INVERSE{2}; |
| 47 | if (e < 0) | 35 | const nissflag nissflag::MIXED{4}; |
| 48 | return error_t{e}; | 36 | const nissflag nissflag::LINEAR{3}; |
| 37 | const nissflag nissflag::ALL{7}; | ||
| 49 | 38 | ||
| 50 | std::string str{cstr}; | 39 | const error error::OK{0}; |
| 51 | fixstr(str); | 40 | const error error::UNSOLVABLE{-1}; |
| 52 | return str; | 41 | const error error::INVALID_CUBE{-10}; |
| 53 | } | 42 | const error error::UNSOLVABLE_CUBE{-11}; |
| 43 | const error error::INVALID_MOVES{-20}; | ||
| 44 | const error error::INVALID_TRANS{-30}; | ||
| 45 | const error error::INVALID_FORMAT{-40}; | ||
| 46 | const error error::INVALID_SOLVER{-50}; | ||
| 47 | const error error::NULL_POINTER{-60}; | ||
| 48 | const error error::BUFFER_SIZE{-61}; | ||
| 49 | const error error::DATA{-70}; | ||
| 50 | const error error::OPTIONS{-80}; | ||
| 51 | const error error::UNKNOWN{-999}; | ||
| 54 | 52 | ||
| 55 | std::function<void(const char *)> | 53 | namespace size { |
| 56 | char_str_fn(std::function<void(std::string&)> f) | 54 | constexpr size_t B32 = 22; |
| 57 | { | 55 | constexpr size_t H48 = 88; |
| 58 | return [&](const char *cc){ | 56 | constexpr size_t CUBE_MAX = H48; |
| 59 | std::string str{cc}; | 57 | constexpr size_t TRANSFORMATION = 12; |
| 60 | f(str); | 58 | constexpr size_t DATAID = 255; |
| 61 | }; | ||
| 62 | } | ||
| 63 | } | 59 | } |
| 64 | |||
| 65 | std::variant<cube_t, error_t> | ||
| 66 | compose(const cube_t& cube, const cube_t& permutation) | ||
| 67 | { | ||
| 68 | char result[size::B32]; | ||
| 69 | 60 | ||
| 70 | auto error = nissy_compose(cube.value.c_str(), | 61 | bool error::ok() const { return value >= 0; } |
| 71 | permutation.value.c_str(), result); | ||
| 72 | 62 | ||
| 73 | return utils::cube_or_error(result, error); | 63 | cube::cube() {} |
| 74 | } | ||
| 75 | 64 | ||
| 76 | std::variant<cube_t, error_t> | 65 | error cube::move(const std::string& moves) |
| 77 | inverse(const cube_t& cube) | ||
| 78 | { | 66 | { |
| 79 | char result[size::B32]; | 67 | char result[size::B32]; |
| 80 | 68 | long long err = nissy_applymoves( | |
| 81 | auto error = nissy_inverse(cube.value.c_str(), result); | 69 | m_b32.c_str(), moves.c_str(), result); |
| 82 | 70 | if (err < 0) | |
| 83 | return utils::cube_or_error(result, error); | 71 | return error{err}; |
| 72 | m_b32 = result; | ||
| 73 | return error::OK; | ||
| 84 | } | 74 | } |
| 85 | 75 | ||
| 86 | std::variant<cube_t, error_t> | 76 | error cube::transform(const std::string& trans) |
| 87 | applymoves(const cube_t& cube, const moves_t& moves) | ||
| 88 | { | 77 | { |
| 89 | char result[size::B32]; | 78 | char result[size::B32]; |
| 79 | long long err = nissy_applytrans( | ||
| 80 | m_b32.c_str(), trans.c_str(), result); | ||
| 81 | if (err < 0) | ||
| 82 | return error{err}; | ||
| 83 | m_b32 = result; | ||
| 84 | return error::OK; | ||
| 85 | } | ||
| 90 | 86 | ||
| 91 | auto error = nissy_applymoves(cube.value.c_str(), | 87 | void cube::invert() |
| 92 | moves.value.c_str(), result); | 88 | { |
| 93 | 89 | char result[size::B32]; | |
| 94 | return utils::cube_or_error(result, error); | 90 | nissy_inverse(m_b32.c_str(), result); |
| 91 | m_b32 = result; | ||
| 95 | } | 92 | } |
| 96 | 93 | ||
| 97 | std::variant<cube_t, error_t> | 94 | void cube::compose(const cube& other) |
| 98 | applytrans(const cube_t& cube, const trans_t& trans) | ||
| 99 | { | 95 | { |
| 100 | char result[size::B32]; | 96 | char result[size::B32]; |
| 97 | nissy_compose( | ||
| 98 | m_b32.c_str(), other.to_string().c_str(), result); | ||
| 99 | m_b32 = result; | ||
| 100 | } | ||
| 101 | 101 | ||
| 102 | auto error = nissy_applytrans(cube.value.c_str(), | 102 | std::string cube::to_string() const { return m_b32; } |
| 103 | trans.value.c_str(), result); | ||
| 104 | 103 | ||
| 105 | return utils::cube_or_error(result, error); | 104 | std::variant<std::string, error> |
| 105 | cube::to_string(const std::string& format) const | ||
| 106 | { | ||
| 107 | char result[size::CUBE_MAX]; | ||
| 108 | auto err = nissy_convert("B32", format.c_str(), | ||
| 109 | m_b32.c_str(), size::CUBE_MAX, result); | ||
| 110 | if (err < 0) | ||
| 111 | return error{err}; | ||
| 112 | else | ||
| 113 | return result; | ||
| 106 | } | 114 | } |
| 107 | 115 | ||
| 108 | std::variant<std::string, error_t> | 116 | std::variant<cube, error> |
| 109 | convert(const cube_format_t& format_in, | 117 | cube::from_string(const std::string& str) |
| 110 | const cube_format_t& format_out, const std::string& cube_string) | ||
| 111 | { | 118 | { |
| 112 | char result[size::CUBE_MAX]; | 119 | return from_string(str, "B32"); |
| 120 | } | ||
| 113 | 121 | ||
| 114 | auto error = nissy_convert(format_in.value.c_str(), | 122 | std::variant<cube, error> |
| 115 | format_out.value.c_str(), cube_string.c_str(), | 123 | cube::from_string(const std::string& str, const std::string& format) |
| 116 | size::CUBE_MAX, result); | 124 | { |
| 125 | char result[size::B32]; | ||
| 126 | cube c; | ||
| 127 | auto err = nissy_convert(format.c_str(), | ||
| 128 | "B32", c.m_b32.c_str(), size::B32, result); | ||
| 129 | if (err < 0) | ||
| 130 | return error{err}; | ||
| 131 | c.m_b32 = result; | ||
| 132 | return c; | ||
| 133 | } | ||
| 117 | 134 | ||
| 118 | return utils::string_or_error(result, error); | 135 | std::variant<cube, error> |
| 136 | cube::get(long long ep, long long eo, long long cp, long long co) | ||
| 137 | { | ||
| 138 | return get(ep, eo, cp, co, "fix"); | ||
| 119 | } | 139 | } |
| 120 | 140 | ||
| 121 | std::variant<cube_t, error_t> | 141 | std::variant<cube, error> |
| 122 | getcube(long long ep, long long eo, long long cp, long long co, | 142 | cube::get(long long ep, long long eo, long long cp, long long co, |
| 123 | const std::string& options) | 143 | const std::string& options) |
| 124 | { | 144 | { |
| 125 | char result[size::B32]; | 145 | char result[size::B32]; |
| 126 | 146 | cube c; | |
| 127 | auto error = nissy_getcube(ep, eo, cp, co, options.c_str(), | 147 | auto err = nissy_getcube( |
| 128 | result); | 148 | ep, eo, cp, co, options.c_str(), result); |
| 129 | 149 | if (err < 0) | |
| 130 | return utils::cube_or_error(result, error); | 150 | return error{err}; |
| 151 | c.m_b32 = result; | ||
| 152 | return c; | ||
| 131 | } | 153 | } |
| 132 | 154 | ||
| 133 | std::variant<std::pair<size_t, std::string>, error_t> | 155 | error solver::generate_data() |
| 134 | solverinfo(const solver_t& solver) | ||
| 135 | { | 156 | { |
| 136 | char dataid[size::DATAID]; | 157 | data.resize(size); |
| 137 | 158 | auto err = nissy_gendata(name.c_str(), | |
| 138 | auto error = nissy_solverinfo(solver.value.c_str(), dataid); | 159 | size, reinterpret_cast<char *>(data.data())); |
| 139 | if (error < 0) | 160 | return error{err}; |
| 140 | return error_t{error}; | ||
| 141 | |||
| 142 | return std::pair{error, dataid}; | ||
| 143 | } | 161 | } |
| 144 | 162 | ||
| 145 | std::variant<solver_data_t, error_t> | 163 | void solver::read_data(std::ifstream& ifs) |
| 146 | gendata(const solver_t& solver) | ||
| 147 | { | 164 | { |
| 148 | char dataid[size::DATAID]; | 165 | data.resize(size); |
| 149 | 166 | ifs.read(reinterpret_cast<char *>(data.data()), size); | |
| 150 | auto error = nissy_solverinfo(solver.value.c_str(), dataid); | ||
| 151 | if (error < 0) | ||
| 152 | return error_t{error}; | ||
| 153 | |||
| 154 | size_t sz = error; | ||
| 155 | std::vector<std::byte> buffer(sz); | ||
| 156 | error = nissy_gendata(solver.value.c_str(), sz, | ||
| 157 | reinterpret_cast<char *>(buffer.data())); | ||
| 158 | if (error < 0) | ||
| 159 | return error_t{error}; | ||
| 160 | |||
| 161 | return solver_data_t{buffer}; | ||
| 162 | } | 167 | } |
| 163 | 168 | ||
| 164 | std::optional<error_t> | 169 | error solver::check_data() const |
| 165 | checkdata(const solver_data_t& data) | ||
| 166 | { | 170 | { |
| 167 | auto error = nissy_checkdata(data.value.size(), | 171 | auto err = nissy_checkdata(data.size(), |
| 168 | reinterpret_cast<const char *>(data.value.data())); | 172 | reinterpret_cast<const char *>(data.data())); |
| 173 | return error{err}; | ||
| 174 | } | ||
| 169 | 175 | ||
| 170 | if (error < 0) | 176 | void solver::unload_data() |
| 171 | return error_t{error}; | 177 | { |
| 172 | return std::nullopt; | 178 | data.resize(0); |
| 173 | } | 179 | } |
| 174 | 180 | ||
| 175 | std::variant<solve_result_t, error_t> | 181 | solver::solve_result |
| 176 | solve(const cube_t& cube, const solver_t& solver, | 182 | solver::solve(const cube& cube, nissflag niss, unsigned minmoves, |
| 177 | nissflag_t niss, unsigned minmoves, unsigned maxmoves, | 183 | unsigned maxmoves, unsigned maxsols, int optimal, int threads) |
| 178 | unsigned maxsolutions, int optimal, int threads, | ||
| 179 | const solver_data_t& data) | ||
| 180 | { | 184 | { |
| 181 | const size_t len = 3 * (maxmoves+1) * maxsolutions; | 185 | const size_t len = 3 * (maxmoves+1) * maxsols; |
| 182 | char csols[len]; | 186 | std::vector<char> csols(len); |
| 183 | long long cstats[size::SOLVE_STATS]; | 187 | solver::solve_result result; |
| 184 | 188 | ||
| 185 | auto error = nissy_solve(cube.value.c_str(), | 189 | auto err = nissy_solve(cube.to_string().c_str(), |
| 186 | solver.value.c_str(), niss.value, minmoves, maxmoves, | 190 | name.c_str(), niss.value, minmoves, maxmoves, maxsols, |
| 187 | maxsolutions, optimal, threads, data.value.size(), | 191 | optimal, threads, data.size(), |
| 188 | reinterpret_cast<const char *>(data.value.data()), | 192 | reinterpret_cast<const char *>(data.data()), len, |
| 189 | len, csols, cstats); | 193 | csols.data(), result.stats.data()); |
| 194 | result.err = error{err}; | ||
| 190 | 195 | ||
| 191 | if (error < 0) | 196 | if (err < 0) |
| 192 | return error_t{error}; | 197 | return result; |
| 198 | |||
| 199 | // TODO: is this special case actually needed? Remove if not | ||
| 200 | if (err == 0) { | ||
| 201 | result.solutions = {}; | ||
| 202 | return result; | ||
| 203 | } | ||
| 193 | 204 | ||
| 194 | std::vector<std::string> sols; | 205 | std::string_view strsols(csols.data()); |
| 195 | std::string_view strsols(csols); | ||
| 196 | for (auto r : strsols | std::views::split('\n')) | 206 | for (auto r : strsols | std::views::split('\n')) |
| 197 | sols.push_back(std::string{r.begin(), r.end()}); | 207 | if (r.begin() != r.end()) |
| 208 | result.solutions.push_back( | ||
| 209 | std::string{r.begin(), r.end()}); | ||
| 198 | 210 | ||
| 199 | return solve_result_t{sols, std::to_array(cstats)}; | 211 | return result; |
| 200 | } | 212 | } |
| 201 | 213 | ||
| 202 | std::variant<unsigned, error_t> | 214 | std::variant<solver, error> solver::get(const std::string& name) |
| 203 | countmoves(const moves_t& moves) | 215 | { |
| 216 | char dataid[size::DATAID]; | ||
| 217 | auto err = nissy_solverinfo(name.c_str(), dataid); | ||
| 218 | if (err < 0) | ||
| 219 | return error{err}; | ||
| 220 | solver s(name); | ||
| 221 | s.size = (unsigned)err; | ||
| 222 | s.id = std::string{dataid}; | ||
| 223 | return s; | ||
| 224 | } | ||
| 225 | |||
| 226 | solver::solver(const std::string& str) : name{str} {} | ||
| 227 | |||
| 228 | std::variant<unsigned, error> | ||
| 229 | count_moves(const std::string& moves) | ||
| 204 | { | 230 | { |
| 205 | auto error = nissy_countmoves(moves.value.c_str()); | 231 | auto err = nissy_countmoves(moves.c_str()); |
| 206 | if (error < 0) | 232 | if (err < 0) |
| 207 | return error_t{error}; | 233 | return error{err}; |
| 208 | return (unsigned)error; | 234 | return (unsigned)err; |
| 209 | } | 235 | } |
| 210 | 236 | ||
| 211 | void setlogger(std::function<void(std::string&)> log) | 237 | void set_logger(const std::function<void(const char *)>& log) |
| 212 | { | 238 | { |
| 213 | nissy_setlogger( | 239 | nissy_setlogger(log.target<void(const char *)>()); |
| 214 | utils::char_str_fn(log).target<void(const char *)>()); | ||
| 215 | } | 240 | } |
| 216 | } | 241 | } |
diff --git a/cpp/nissy.h b/cpp/nissy.h index e336c7a..7ab466d 100644 --- a/cpp/nissy.h +++ b/cpp/nissy.h | |||
| @@ -15,119 +15,91 @@ C++20 header file for nissy. | |||
| 15 | #include <vector> | 15 | #include <vector> |
| 16 | 16 | ||
| 17 | namespace nissy { | 17 | namespace nissy { |
| 18 | /* Some constants for size for I/O buffers */ | ||
| 19 | namespace size { | ||
| 20 | constexpr size_t B32 = 22; | ||
| 21 | constexpr size_t H48 = 88; | ||
| 22 | constexpr size_t CUBE_MAX = H48; | ||
| 23 | constexpr size_t TRANSFORMATION = 12; | ||
| 24 | constexpr size_t SOLVE_STATS = 10; | ||
| 25 | constexpr size_t DATAID = 255; | ||
| 26 | } | ||
| 27 | 18 | ||
| 28 | /* Some structs definitions for better type safety */ | 19 | class nissflag { |
| 29 | struct nissflag_t { unsigned value; }; | 20 | public: |
| 30 | struct error_t { long long value; }; | 21 | unsigned value; |
| 31 | struct cube_t { std::string value; }; | ||
| 32 | struct moves_t { std::string value; }; | ||
| 33 | struct trans_t { std::string value; }; | ||
| 34 | struct cube_format_t { std::string value; }; | ||
| 35 | struct solver_t { std::string value; }; | ||
| 36 | struct solver_data_t { std::vector<std::byte> value; }; | ||
| 37 | struct solve_result_t { | ||
| 38 | std::vector<std::string> solutions; | ||
| 39 | std::array<long long, size::SOLVE_STATS> stats; | ||
| 40 | }; | ||
| 41 | |||
| 42 | /* Flags for NISS options */ | ||
| 43 | namespace nissflag { | ||
| 44 | constexpr nissflag_t NORMAL{1}; | ||
| 45 | constexpr nissflag_t INVERSE{2}; | ||
| 46 | constexpr nissflag_t MIXED{4}; | ||
| 47 | constexpr nissflag_t LINEAR{NORMAL.value | INVERSE.value}; | ||
| 48 | constexpr nissflag_t ALL{LINEAR.value | MIXED.value}; | ||
| 49 | } | ||
| 50 | |||
| 51 | /* Error codes */ | ||
| 52 | namespace error { | ||
| 53 | constexpr error_t UNSOLVABLE{-1}; | ||
| 54 | constexpr error_t INVALID_CUBE{-10}; | ||
| 55 | constexpr error_t UNSOLVABLE_CUBE{-11}; | ||
| 56 | constexpr error_t INVALID_MOVES{-20}; | ||
| 57 | constexpr error_t INVALID_TRANS{-30}; | ||
| 58 | constexpr error_t INVALID_FORMAT{-40}; | ||
| 59 | constexpr error_t INVALID_SOLVER{-50}; | ||
| 60 | constexpr error_t NULL_POINTER{-60}; | ||
| 61 | constexpr error_t BUFFER_SIZE{-61}; | ||
| 62 | constexpr error_t DATA{-70}; | ||
| 63 | constexpr error_t OPTIONS{-80}; | ||
| 64 | constexpr error_t UNKNOWN{-999}; | ||
| 65 | } | ||
| 66 | |||
| 67 | /* Cube constants */ | ||
| 68 | namespace cube { | ||
| 69 | const cube_t SOLVED{"ABCDEFGH=ABCDEFGHIJKL"}; | ||
| 70 | } | ||
| 71 | 22 | ||
| 72 | std::variant<cube_t, error_t> inverse( | 23 | static const nissflag NORMAL; |
| 73 | const cube_t& cube | 24 | static const nissflag INVERSE; |
| 74 | ); | 25 | static const nissflag MIXED; |
| 26 | static const nissflag LINEAR; | ||
| 27 | static const nissflag ALL; | ||
| 28 | }; | ||
| 75 | 29 | ||
| 76 | std::variant<cube_t, error_t> applymoves( | 30 | class error { |
| 77 | const cube_t& cube, | 31 | public: |
| 78 | const moves_t& moves | 32 | long long value; |
| 79 | ); | 33 | bool ok() const; |
| 80 | 34 | ||
| 81 | std::variant<cube_t, error_t> applytrans( | 35 | static const error OK; |
| 82 | const cube_t& cube, | 36 | static const error UNSOLVABLE; |
| 83 | const trans_t& trans | 37 | static const error INVALID_CUBE; |
| 84 | ); | 38 | static const error UNSOLVABLE_CUBE; |
| 39 | static const error INVALID_MOVES; | ||
| 40 | static const error INVALID_TRANS; | ||
| 41 | static const error INVALID_FORMAT; | ||
| 42 | static const error INVALID_SOLVER; | ||
| 43 | static const error NULL_POINTER; | ||
| 44 | static const error BUFFER_SIZE; | ||
| 45 | static const error DATA; | ||
| 46 | static const error OPTIONS; | ||
| 47 | static const error UNKNOWN; | ||
| 48 | }; | ||
| 85 | 49 | ||
| 86 | std::variant<std::string, error_t> convert( | 50 | class cube { |
| 87 | const cube_format_t& format_in, | 51 | public: |
| 88 | const cube_format_t& format_out, | 52 | cube(); |
| 89 | const std::string& cube_string | 53 | error move(const std::string&); |
| 90 | ); | 54 | error transform(const std::string&); |
| 55 | void invert(); | ||
| 56 | void compose(const cube&); | ||
| 57 | std::string to_string() const; | ||
| 58 | std::variant<std::string, error> to_string( | ||
| 59 | const std::string& format) const; | ||
| 91 | 60 | ||
| 92 | std::variant<cube_t, error_t> getcube( | 61 | static std::variant<cube, error> from_string( |
| 93 | long long ep, | 62 | const std::string&); |
| 94 | long long eo, | 63 | static std::variant<cube, error> from_string( |
| 95 | long long cp, | 64 | const std::string& str, const std::string& format); |
| 96 | long long co, | 65 | static std::variant<cube, error> get( |
| 97 | const std::string& options | 66 | long long ep, long long eo, long long cp, long long co); |
| 98 | ); | 67 | static std::variant<cube, error> get( |
| 68 | long long ep, long long eo, long long cp, long long co, | ||
| 69 | const std::string& options); | ||
| 99 | 70 | ||
| 100 | std::variant<std::pair<size_t, std::string>, error_t> solverinfo( | 71 | private: |
| 101 | const solver_t& solver | 72 | std::string m_b32{"ABCDEFGH=ABCDEFGHIJKL"}; |
| 102 | ); | 73 | }; |
| 103 | 74 | ||
| 104 | std::variant<solver_data_t, error_t> gendata( | 75 | class solver { |
| 105 | const solver_t& solver | 76 | public: |
| 106 | ); | 77 | struct solve_result { |
| 78 | error err; | ||
| 79 | std::vector<std::string> solutions; | ||
| 80 | std::array<long long, 10> stats; | ||
| 81 | }; | ||
| 107 | 82 | ||
| 108 | std::optional<error_t> checkdata( | 83 | const std::string name; |
| 109 | const solver_data_t& data | 84 | size_t size; |
| 110 | ); | 85 | std::string id; |
| 86 | std::vector<std::byte> data; | ||
| 111 | 87 | ||
| 112 | std::variant<solve_result_t, error_t> solve( | 88 | error generate_data(); |
| 113 | const cube_t& cube, | 89 | void read_data(std::ifstream&); |
| 114 | const solver_t& solver, | 90 | error check_data() const; |
| 115 | nissflag_t niss, | 91 | void unload_data(); |
| 116 | unsigned minmoves, | 92 | solve_result solve(const cube&, nissflag, unsigned minmoves, |
| 117 | unsigned maxmoves, | 93 | unsigned maxmoves, unsigned maxsols, int optimal, |
| 118 | unsigned maxsolutions, | 94 | int threads); |
| 119 | int optimal, | ||
| 120 | int threads, | ||
| 121 | const solver_data_t& data | ||
| 122 | ); | ||
| 123 | 95 | ||
| 124 | std::variant<unsigned, error_t> countmoves( | 96 | static std::variant<solver, error> get(const std::string&); |
| 125 | const moves_t& moves | 97 | private: |
| 126 | ); | 98 | solver(const std::string& name); |
| 99 | }; | ||
| 127 | 100 | ||
| 128 | void setlogger( | 101 | std::variant<unsigned, error> count_moves(const std::string&); |
| 129 | std::function<void(std::string&)> log | 102 | void set_logger(const std::function<void(const char*)>&); |
| 130 | ); | ||
| 131 | } | 103 | } |
| 132 | 104 | ||
| 133 | #endif | 105 | #endif |
