nissy.cpp (5603B)
1 /* 2 C++20 interface for nissy. 3 4 TODO: add more documentation (here and in README.md) 5 */ 6 7 #include "./nissy.h" 8 9 #include <fstream> 10 11 extern "C" { 12 long long nissy_inverse(const char *, char *); 13 long long nissy_applymoves(const char *, const char *, char *); 14 long long nissy_applytrans(const char *, const char *, char *); 15 long long nissy_getcube(long long, long long, long long, long long, 16 long long, const char *, char *); 17 long long nissy_solverinfo(const char *, char *); 18 long long nissy_gendata(const char *, unsigned long long, 19 unsigned char *); 20 long long nissy_checkdata(unsigned long long, const unsigned char *); 21 long long nissy_solve(const char *, const char *, unsigned, unsigned, 22 unsigned, unsigned, unsigned, unsigned, unsigned long long, 23 const unsigned char *, unsigned, char *, long long *, 24 int (*)(void *), void *); 25 long long nissy_countmoves(const char *); 26 long long nissy_setlogger(void (*)(const char *, void *), void *); 27 } 28 29 namespace nissy { 30 31 /* Definition of constants with const qualifier */ 32 const nissflag nissflag::NORMAL{1}; 33 const nissflag nissflag::INVERSE{2}; 34 const nissflag nissflag::MIXED{4}; 35 const nissflag nissflag::LINEAR{3}; 36 const nissflag nissflag::ALL{7}; 37 38 const error error::OK{0}; 39 const error error::UNSOLVABLE_WARNING{-1}; 40 const error error::UNSOLVABLE_ERROR{-11}; 41 const error error::INVALID_CUBE{-10}; 42 const error error::INVALID_MOVES{-20}; 43 const error error::INVALID_TRANS{-30}; 44 const error error::INVALID_SOLVER{-50}; 45 const error error::NULL_POINTER{-60}; 46 const error error::BUFFER_SIZE{-61}; 47 const error error::DATA{-70}; 48 const error error::OPTIONS{-80}; 49 const error error::UNKNOWN{-999}; 50 51 const status status::RUN{0}; 52 const status status::STOP{1}; 53 const status status::PAUSE{2}; 54 55 namespace size { 56 constexpr size_t CUBE = 24; 57 constexpr size_t TRANSFORMATION = 12; 58 constexpr size_t DATAID = 255; 59 } 60 61 bool error::ok() const { return value >= 0; } 62 63 cube::cube() {} 64 65 error cube::move(const std::string& moves) 66 { 67 char result[size::CUBE]; 68 long long err = nissy_applymoves( 69 m_str.c_str(), moves.c_str(), result); 70 if (err < 0) 71 return error{err}; 72 m_str = result; 73 return error::OK; 74 } 75 76 error cube::transform(const std::string& trans) 77 { 78 char result[size::CUBE]; 79 long long err = nissy_applytrans( 80 m_str.c_str(), trans.c_str(), result); 81 if (err < 0) 82 return error{err}; 83 m_str = result; 84 return error::OK; 85 } 86 87 void cube::invert() 88 { 89 char result[size::CUBE]; 90 nissy_inverse(m_str.c_str(), result); 91 m_str = result; 92 } 93 94 std::string cube::to_string() const { return m_str; } 95 96 std::variant<cube, error> 97 cube::from_string(const std::string& str) 98 { 99 /* Check that the cube is valid by making a single move */ 100 char result[size::CUBE]; 101 auto err = nissy_applymoves(str.c_str(), "U", result); 102 if (err < 0) 103 return error{err}; 104 105 cube c; 106 c.m_str = str; 107 return c; 108 } 109 110 std::variant<cube, error> 111 cube::get(long long ep, long long eo, 112 long long cp, long long co, long long orien) 113 { 114 return get(ep, eo, cp, co, orien, "fix"); 115 } 116 117 std::variant<cube, error> 118 cube::get(long long ep, long long eo, long long cp, long long co, 119 long long orient, const std::string& options) 120 { 121 char result[size::CUBE]; 122 cube c; 123 auto err = nissy_getcube(ep, eo, cp, co, orient, 124 options.c_str(), result); 125 if (err < 0) 126 return error{err}; 127 c.m_str = result; 128 return c; 129 } 130 131 error solver::generate_data() 132 { 133 data.resize(size); 134 auto err = nissy_gendata(name.c_str(), 135 size, reinterpret_cast<unsigned char *>(data.data())); 136 return error{err}; 137 } 138 139 void solver::read_data(std::ifstream& ifs) 140 { 141 data.resize(size); 142 ifs.read(reinterpret_cast<char *>(data.data()), size); 143 } 144 145 error solver::check_data() 146 { 147 auto err_value = nissy_checkdata(data.size(), 148 reinterpret_cast<const unsigned char *>(data.data())); 149 error err{err_value}; 150 data_checked = err.ok(); 151 return err; 152 } 153 154 void solver::unload_data() 155 { 156 data.resize(0); 157 } 158 159 solver::solve_result 160 solver::solve(const cube& cube, nissflag niss, unsigned minmoves, 161 unsigned maxmoves, unsigned maxsols, unsigned optimal, 162 unsigned threads, int (*poll_status)(void *), 163 void *poll_status_data) const 164 { 165 solver::solve_result result; 166 167 if (maxsols == 0) { 168 result.solutions = {}; 169 result.err = error::OK; 170 return result; 171 } 172 173 const size_t len = 3 * (maxmoves+1) * maxsols; 174 std::vector<char> csols(len); 175 176 auto err = nissy_solve(cube.to_string().c_str(), 177 name.c_str(), niss.value, minmoves, maxmoves, maxsols, 178 optimal, threads, data.size(), 179 reinterpret_cast<const unsigned char *>(data.data()), len, 180 csols.data(), result.stats.data(), poll_status, 181 poll_status_data); 182 result.err = error{err}; 183 184 if (err < 0) 185 return result; 186 187 std::string_view strsols(csols.data()); 188 for (auto r : strsols | std::views::split('\n')) 189 if (r.begin() != r.end() || 190 r.begin() == strsols.begin()) 191 result.solutions.push_back( 192 std::string{r.begin(), r.end()}); 193 194 return result; 195 } 196 197 std::variant<solver, error> solver::get(const std::string& name) 198 { 199 char dataid[size::DATAID]; 200 auto err = nissy_solverinfo(name.c_str(), dataid); 201 if (err < 0) 202 return error{err}; 203 solver s(name); 204 s.size = (unsigned)err; 205 s.id = std::string{dataid}; 206 return s; 207 } 208 209 solver::solver(const std::string& str) : name{str} {} 210 211 error count_moves(const std::string& moves) 212 { 213 auto err = nissy_countmoves(moves.c_str()); 214 return error{err}; 215 } 216 217 void set_logger(void (*log)(const char *, void *), void *data) 218 { 219 nissy_setlogger(log, data); 220 } 221 }