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