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 (5523B)


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