nissy.cpp (6816B)
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_variations(const char *, const char *, 16 unsigned long long, char*); 17 long long nissy_getcube(long long, long long, long long, long long, 18 long long, const char *, char *); 19 long long nissy_solverinfo(const char *, char *); 20 long long nissy_gendata(const char *, unsigned long long, 21 unsigned char *); 22 long long nissy_checkdata(const char *, unsigned long long, 23 const unsigned char *); 24 long long nissy_solve(const char *, const char *, unsigned, unsigned, 25 unsigned, unsigned, unsigned, unsigned, unsigned long long, 26 const unsigned char *, unsigned, char *, long long *, 27 int (*)(void *), void *); 28 long long nissy_countmoves(const char *); 29 long long nissy_comparemoves(const char *, const char *); 30 long long nissy_setlogger(void (*)(const char *, void *), void *); 31 } 32 33 namespace nissy { 34 35 /* Definition of constants with const qualifier */ 36 const nissflag nissflag::NORMAL{1}; 37 const nissflag nissflag::INVERSE{2}; 38 const nissflag nissflag::MIXED{4}; 39 const nissflag nissflag::LINEAR{3}; 40 const nissflag nissflag::ALL{7}; 41 42 const error error::OK{0}; 43 const error error::UNSOLVABLE_WARNING{-1}; 44 const error error::UNSOLVABLE_ERROR{-11}; 45 const error error::INVALID_CUBE{-10}; 46 const error error::INVALID_MOVES{-20}; 47 const error error::INVALID_TRANS{-30}; 48 const error error::INVALID_SOLVER{-50}; 49 const error error::INVALID_VARIATION{-51}; 50 const error error::NULL_POINTER{-60}; 51 const error error::BUFFER_SIZE{-61}; 52 const error error::DATA{-70}; 53 const error error::OPTIONS{-80}; 54 const error error::UNKNOWN{-999}; 55 56 const status status::RUN{0}; 57 const status status::STOP{1}; 58 const status status::PAUSE{2}; 59 60 const compare_result compare_result::EQUAL{0}; 61 const compare_result compare_result::DIFFERENT{99}; 62 63 namespace size { 64 constexpr size_t CUBE = 24; 65 constexpr size_t TRANSFORMATION = 12; 66 constexpr size_t SOLVE_STATS = 10; 67 constexpr size_t DATAID = 255; 68 constexpr size_t MOVES = 1000; 69 } 70 71 bool error::ok() const { return value >= 0; } 72 73 variation::variation(const std::string& str) : name{str} {} 74 75 variation::variations_result 76 variation::find_variations(const std::string& moves) 77 { 78 variation::variations_result result; 79 80 const size_t len = 3 * size::MOVES * 16; 81 result.solutions.resize(len); 82 83 auto err = nissy_variations(moves.c_str(), name.c_str(), len, 84 result.solutions.data()); 85 86 int size = result.solutions.find_first_of('\0'); 87 result.solutions.resize(size); 88 result.err = error{err}; 89 90 return result; 91 } 92 93 std::variant<variation, error> 94 variation::get(const std::string& name) { 95 char result[10]; 96 variation s(name); 97 98 if (nissy_variations("", name.c_str(), 10, result) < 0) 99 return error::INVALID_VARIATION; 100 else 101 return s; 102 } 103 104 cube::cube() {} 105 106 error cube::move(const std::string& moves) 107 { 108 char result[size::CUBE]; 109 long long err = nissy_applymoves( 110 m_str.c_str(), moves.c_str(), result); 111 if (err < 0) 112 return error{err}; 113 m_str = result; 114 return error::OK; 115 } 116 117 error cube::transform(const std::string& trans) 118 { 119 char result[size::CUBE]; 120 long long err = nissy_applytrans( 121 m_str.c_str(), trans.c_str(), result); 122 if (err < 0) 123 return error{err}; 124 m_str = result; 125 return error::OK; 126 } 127 128 void cube::invert() 129 { 130 char result[size::CUBE]; 131 nissy_inverse(m_str.c_str(), result); 132 m_str = result; 133 } 134 135 std::string cube::to_string() const { return m_str; } 136 137 std::variant<cube, error> 138 cube::from_string(const std::string& str) 139 { 140 /* Check that the cube is valid by making a single move */ 141 char result[size::CUBE]; 142 auto err = nissy_applymoves(str.c_str(), "U", result); 143 if (err < 0) 144 return error{err}; 145 146 cube c; 147 c.m_str = str; 148 return c; 149 } 150 151 std::variant<cube, error> 152 cube::get(long long ep, long long eo, 153 long long cp, long long co, long long orien) 154 { 155 return get(ep, eo, cp, co, orien, "fix"); 156 } 157 158 std::variant<cube, error> 159 cube::get(long long ep, long long eo, long long cp, long long co, 160 long long orient, const std::string& options) 161 { 162 char result[size::CUBE]; 163 cube c; 164 auto err = nissy_getcube(ep, eo, cp, co, orient, 165 options.c_str(), result); 166 if (err < 0) 167 return error{err}; 168 c.m_str = result; 169 return c; 170 } 171 172 error solver::generate_data() 173 { 174 data.resize(size); 175 auto err = nissy_gendata(name.c_str(), 176 size, reinterpret_cast<unsigned char *>(data.data())); 177 return error{err}; 178 } 179 180 void solver::read_data(std::ifstream& ifs) 181 { 182 data.resize(size); 183 ifs.read(reinterpret_cast<char *>(data.data()), size); 184 } 185 186 error solver::check_data() 187 { 188 auto err_value = nissy_checkdata(name.c_str(), data.size(), 189 reinterpret_cast<const unsigned char *>(data.data())); 190 error err{err_value}; 191 data_checked = err.ok(); 192 return err; 193 } 194 195 void solver::unload_data() 196 { 197 data.resize(0); 198 } 199 200 solver::solve_result 201 solver::solve(const cube& cube, nissflag niss, unsigned minmoves, 202 unsigned maxmoves, unsigned maxsols, unsigned optimal, 203 unsigned threads, int (*poll_status)(void *), 204 void *poll_status_data) const 205 { 206 long long stats[size::SOLVE_STATS]; 207 solver::solve_result result; 208 209 if (maxsols == 0) { 210 result.solutions = ""; 211 result.err = error::OK; 212 return result; 213 } 214 215 const size_t len = 3 * (maxmoves+1) * maxsols; 216 result.solutions.resize(len); 217 218 auto err = nissy_solve(cube.to_string().c_str(), 219 name.c_str(), niss.value, minmoves, maxmoves, maxsols, 220 optimal, threads, data.size(), 221 reinterpret_cast<const unsigned char *>(data.data()), len, 222 result.solutions.data(), stats, 223 poll_status, poll_status_data); 224 225 int size = result.solutions.find_first_of('\0'); 226 result.solutions.resize(size); 227 result.err = error{err}; 228 229 return result; 230 } 231 232 std::variant<solver, error> solver::get(const std::string& name) 233 { 234 char dataid[size::DATAID]; 235 auto err = nissy_solverinfo(name.c_str(), dataid); 236 if (err < 0) 237 return error{err}; 238 solver s(name); 239 s.size = (unsigned)err; 240 s.id = std::string{dataid}; 241 return s; 242 } 243 244 solver::solver(const std::string& str) : name{str} {} 245 246 error count_moves(const std::string& moves) 247 { 248 auto err = nissy_countmoves(moves.c_str()); 249 return error{err}; 250 } 251 252 std::variant<error, compare_result> 253 compare_moves(const std::string& m1, const std::string& m2) 254 { 255 auto cmp = nissy_comparemoves(m1.c_str(), m2.c_str()); 256 if (cmp < 0) 257 return error{cmp}; 258 else 259 return compare_result{cmp}; 260 } 261 262 void set_logger(void (*log)(const char *, void *), void *data) 263 { 264 nissy_setlogger(log, data); 265 } 266 }