nissy-core

The "engine" of nissy, including the H48 optimal solver.
git clone https://git.tronto.net/nissy-core
Download | Log | Files | Refs | README | LICENSE

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 }