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 (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 }