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


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