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