h48

A prototype for an optimal Rubik's cube solver, work in progress.
git clone https://git.tronto.net/h48
Download | Log | Files | Refs | README | LICENSE

nissy.cpp (6077B)


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