diff options
| author | Sebastiano Tronto <sebastiano@tronto.net> | 2025-08-07 15:09:46 +0200 |
|---|---|---|
| committer | Sebastiano Tronto <sebastiano@tronto.net> | 2025-08-07 15:28:01 +0200 |
| commit | 5355de2921126e2b75e24abd57e17556e22a6ed0 (patch) | |
| tree | 0df679e152ffb2798248982ac58ff123c6859114 | |
| parent | 57a7520545134ab95f7bb0397dcbe991c906a3e9 (diff) | |
| download | nissy-core-5355de2921126e2b75e24abd57e17556e22a6ed0.tar.gz nissy-core-5355de2921126e2b75e24abd57e17556e22a6ed0.zip | |
Added API function for solution variations
25 files changed, 586 insertions, 36 deletions
diff --git a/.dockerignore b/.dockerignore deleted file mode 120000 index 3e4e48b..0000000 --- a/.dockerignore +++ /dev/null | |||
| @@ -1 +0,0 @@ | |||
| 1 | .gitignore \ No newline at end of file | ||
diff --git a/cpp/examples/variations.cpp b/cpp/examples/variations.cpp new file mode 100644 index 0000000..3c6421d --- /dev/null +++ b/cpp/examples/variations.cpp | |||
| @@ -0,0 +1,15 @@ | |||
| 1 | /* A simple example showing how to move a cube and print it in H48 format. */ | ||
| 2 | |||
| 3 | #include "../nissy.h" | ||
| 4 | #include <iostream> | ||
| 5 | |||
| 6 | int main() { | ||
| 7 | std::string moves = "R U' Bw2 M D' x' F B(E2 F D B' Lw2 U2 U' S2 B)"; | ||
| 8 | auto v = std::get<nissy::variation>(nissy::variation::get("lastqt")); | ||
| 9 | auto variations = v.find_variations(moves).solutions; | ||
| 10 | |||
| 11 | std::cout << "Changing the last quarter turn of " << moves << " gives:" | ||
| 12 | << std::endl << variations; | ||
| 13 | |||
| 14 | return 0; | ||
| 15 | } | ||
diff --git a/cpp/nissy.cpp b/cpp/nissy.cpp index 90fcf20..6ca4884 100644 --- a/cpp/nissy.cpp +++ b/cpp/nissy.cpp | |||
| @@ -12,6 +12,7 @@ extern "C" { | |||
| 12 | long long nissy_inverse(const char *, char *); | 12 | long long nissy_inverse(const char *, char *); |
| 13 | long long nissy_applymoves(const char *, const char *, char *); | 13 | long long nissy_applymoves(const char *, const char *, char *); |
| 14 | long long nissy_applytrans(const char *, const char *, char *); | 14 | long long nissy_applytrans(const char *, const char *, char *); |
| 15 | long long nissy_variations(const char *, const char *, size_t, char*); | ||
| 15 | long long nissy_getcube(long long, long long, long long, long long, | 16 | long long nissy_getcube(long long, long long, long long, long long, |
| 16 | long long, const char *, char *); | 17 | long long, const char *, char *); |
| 17 | long long nissy_solverinfo(const char *, char *); | 18 | long long nissy_solverinfo(const char *, char *); |
| @@ -44,6 +45,7 @@ namespace nissy { | |||
| 44 | const error error::INVALID_MOVES{-20}; | 45 | const error error::INVALID_MOVES{-20}; |
| 45 | const error error::INVALID_TRANS{-30}; | 46 | const error error::INVALID_TRANS{-30}; |
| 46 | const error error::INVALID_SOLVER{-50}; | 47 | const error error::INVALID_SOLVER{-50}; |
| 48 | const error error::INVALID_VARIATION{-51}; | ||
| 47 | const error error::NULL_POINTER{-60}; | 49 | const error error::NULL_POINTER{-60}; |
| 48 | const error error::BUFFER_SIZE{-61}; | 50 | const error error::BUFFER_SIZE{-61}; |
| 49 | const error error::DATA{-70}; | 51 | const error error::DATA{-70}; |
| @@ -62,10 +64,42 @@ namespace nissy { | |||
| 62 | constexpr size_t TRANSFORMATION = 12; | 64 | constexpr size_t TRANSFORMATION = 12; |
| 63 | constexpr size_t SOLVE_STATS = 10; | 65 | constexpr size_t SOLVE_STATS = 10; |
| 64 | constexpr size_t DATAID = 255; | 66 | constexpr size_t DATAID = 255; |
| 67 | constexpr size_t MOVES = 1000; | ||
| 65 | } | 68 | } |
| 66 | 69 | ||
| 67 | bool error::ok() const { return value >= 0; } | 70 | bool error::ok() const { return value >= 0; } |
| 68 | 71 | ||
| 72 | variation::variation(const std::string& str) : name{str} {} | ||
| 73 | |||
| 74 | variation::variations_result | ||
| 75 | variation::find_variations(const std::string& moves) | ||
| 76 | { | ||
| 77 | variation::variations_result result; | ||
| 78 | |||
| 79 | const size_t len = 3 * size::MOVES * 16; | ||
| 80 | result.solutions.resize(len); | ||
| 81 | |||
| 82 | auto err = nissy_variations(moves.c_str(), name.c_str(), len, | ||
| 83 | result.solutions.data()); | ||
| 84 | |||
| 85 | int size = result.solutions.find_first_of('\0'); | ||
| 86 | result.solutions.resize(size); | ||
| 87 | result.err = error{err}; | ||
| 88 | |||
| 89 | return result; | ||
| 90 | } | ||
| 91 | |||
| 92 | std::variant<variation, error> | ||
| 93 | variation::get(const std::string& name) { | ||
| 94 | char result[10]; | ||
| 95 | variation s(name); | ||
| 96 | |||
| 97 | if (nissy_variations("", name.c_str(), 10, result) < 0) | ||
| 98 | return error::INVALID_VARIATION; | ||
| 99 | else | ||
| 100 | return s; | ||
| 101 | } | ||
| 102 | |||
| 69 | cube::cube() {} | 103 | cube::cube() {} |
| 70 | 104 | ||
| 71 | error cube::move(const std::string& moves) | 105 | error cube::move(const std::string& moves) |
diff --git a/cpp/nissy.h b/cpp/nissy.h index 199af10..74bbd32 100644 --- a/cpp/nissy.h +++ b/cpp/nissy.h | |||
| @@ -39,6 +39,7 @@ namespace nissy { | |||
| 39 | static const error INVALID_MOVES; | 39 | static const error INVALID_MOVES; |
| 40 | static const error INVALID_TRANS; | 40 | static const error INVALID_TRANS; |
| 41 | static const error INVALID_SOLVER; | 41 | static const error INVALID_SOLVER; |
| 42 | static const error INVALID_VARIATION; | ||
| 42 | static const error NULL_POINTER; | 43 | static const error NULL_POINTER; |
| 43 | static const error BUFFER_SIZE; | 44 | static const error BUFFER_SIZE; |
| 44 | static const error DATA; | 45 | static const error DATA; |
| @@ -63,6 +64,21 @@ namespace nissy { | |||
| 63 | static const compare_result DIFFERENT; | 64 | static const compare_result DIFFERENT; |
| 64 | }; | 65 | }; |
| 65 | 66 | ||
| 67 | class variation { | ||
| 68 | public: | ||
| 69 | struct variations_result { | ||
| 70 | error err; | ||
| 71 | std::string solutions; | ||
| 72 | }; | ||
| 73 | |||
| 74 | const std::string name; | ||
| 75 | |||
| 76 | variations_result find_variations(const std::string&); | ||
| 77 | static std::variant<variation, error> get(const std::string&); | ||
| 78 | private: | ||
| 79 | variation(const std::string&); | ||
| 80 | }; | ||
| 81 | |||
| 66 | class cube { | 82 | class cube { |
| 67 | public: | 83 | public: |
| 68 | cube(); | 84 | cube(); |
diff --git a/python/examples/variations.py b/python/examples/variations.py new file mode 100644 index 0000000..1b85d32 --- /dev/null +++ b/python/examples/variations.py | |||
| @@ -0,0 +1,12 @@ | |||
| 1 | # Small example of nissy_python_module usage | ||
| 2 | # See the solve.py example for more details on how this works | ||
| 3 | |||
| 4 | from sys import path | ||
| 5 | path.append("./") | ||
| 6 | import nissy_python_module as nissy | ||
| 7 | |||
| 8 | moves = "R U' Bw2 M D' x' F B(E2 F D B' Lw2 U2 U' S2 B)" | ||
| 9 | |||
| 10 | print("Changing the last quarter turns of {} gives:".format(moves)) | ||
| 11 | for s in nissy.variations(moves, "lastqt"): | ||
| 12 | print(s) | ||
diff --git a/python/nissy_module.c b/python/nissy_module.c index a86b23f..88109d3 100644 --- a/python/nissy_module.c +++ b/python/nissy_module.c | |||
| @@ -44,6 +44,29 @@ string_result(long long err, const char *result) | |||
| 44 | } | 44 | } |
| 45 | 45 | ||
| 46 | static PyObject * | 46 | static PyObject * |
| 47 | stringlist_result(long long err, char *result) | ||
| 48 | { | ||
| 49 | int i, j, k; | ||
| 50 | PyObject *list, *item; | ||
| 51 | |||
| 52 | if(!check_error(err)) { | ||
| 53 | return NULL; | ||
| 54 | } else { | ||
| 55 | list = PyList_New(err); | ||
| 56 | for (i = 0, j = 0, k = 0; result[i] != 0; i++) { | ||
| 57 | if (result[i] != '\n') | ||
| 58 | continue; | ||
| 59 | result[i] = 0; | ||
| 60 | item = PyUnicode_FromString(&result[k]); | ||
| 61 | PyList_SetItem(list, j, item); | ||
| 62 | j++; | ||
| 63 | k = i+1; | ||
| 64 | } | ||
| 65 | return list; | ||
| 66 | } | ||
| 67 | } | ||
| 68 | |||
| 69 | static PyObject * | ||
| 47 | string_result_free(long long err, char *result) | 70 | string_result_free(long long err, char *result) |
| 48 | { | 71 | { |
| 49 | PyObject *ret; | 72 | PyObject *ret; |
| @@ -287,12 +310,11 @@ solve(PyObject *self, PyObject *args) | |||
| 287 | { | 310 | { |
| 288 | long long result; | 311 | long long result; |
| 289 | unsigned nissflag, minmoves, maxmoves, maxsolutions; | 312 | unsigned nissflag, minmoves, maxmoves, maxsolutions; |
| 290 | int optimal, i, j, k, threads; | 313 | int optimal, threads; |
| 291 | const char *cube, *solver; | 314 | const char *cube, *solver; |
| 292 | char solutions[MAX_SOLUTIONS_SIZE]; | 315 | char solutions[MAX_SOLUTIONS_SIZE]; |
| 293 | long long stats[NISSY_SIZE_SOLVE_STATS]; | 316 | long long stats[NISSY_SIZE_SOLVE_STATS]; |
| 294 | PyByteArrayObject *data; | 317 | PyByteArrayObject *data; |
| 295 | PyObject *list, *item; | ||
| 296 | 318 | ||
| 297 | if (!PyArg_ParseTuple(args, "ssIIIIIIY", &cube, &solver, &nissflag, | 319 | if (!PyArg_ParseTuple(args, "ssIIIIIIY", &cube, &solver, &nissflag, |
| 298 | &minmoves, &maxmoves, &maxsolutions, &optimal, &threads, &data)) | 320 | &minmoves, &maxmoves, &maxsolutions, &optimal, &threads, &data)) |
| @@ -305,21 +327,7 @@ solve(PyObject *self, PyObject *args) | |||
| 305 | stats, NULL, NULL); | 327 | stats, NULL, NULL); |
| 306 | Py_END_ALLOW_THREADS | 328 | Py_END_ALLOW_THREADS |
| 307 | 329 | ||
| 308 | if(!check_error(result)) { | 330 | return stringlist_result(result, solutions); |
| 309 | return NULL; | ||
| 310 | } else { | ||
| 311 | list = PyList_New(result); | ||
| 312 | for (i = 0, j = 0, k = 0; solutions[i] != 0; i++) { | ||
| 313 | if (solutions[i] != '\n') | ||
| 314 | continue; | ||
| 315 | solutions[i] = 0; | ||
| 316 | item = PyUnicode_FromString(&solutions[k]); | ||
| 317 | PyList_SetItem(list, j, item); | ||
| 318 | j++; | ||
| 319 | k = i+1; | ||
| 320 | } | ||
| 321 | return list; | ||
| 322 | } | ||
| 323 | } | 331 | } |
| 324 | 332 | ||
| 325 | PyDoc_STRVAR(countmoves_doc, | 333 | PyDoc_STRVAR(countmoves_doc, |
| @@ -368,8 +376,9 @@ comparemoves(PyObject *self, PyObject *args) | |||
| 368 | if (!PyArg_ParseTuple(args, "ss", &m1, &m2)) | 376 | if (!PyArg_ParseTuple(args, "ss", &m1, &m2)) |
| 369 | return NULL; | 377 | return NULL; |
| 370 | 378 | ||
| 371 | if ((cmp = nissy_comparemoves(m1, m2)) < 0) | 379 | cmp = nissy_comparemoves(m1, m2); |
| 372 | return long_result(cmp); | 380 | if (!check_error(cmp)) |
| 381 | return NULL; | ||
| 373 | 382 | ||
| 374 | switch (cmp) { | 383 | switch (cmp) { |
| 375 | case NISSY_COMPARE_MOVES_EQUAL: | 384 | case NISSY_COMPARE_MOVES_EQUAL: |
| @@ -381,6 +390,32 @@ comparemoves(PyObject *self, PyObject *args) | |||
| 381 | } | 390 | } |
| 382 | } | 391 | } |
| 383 | 392 | ||
| 393 | PyDoc_STRVAR(variations_doc, | ||
| 394 | "variations(moves, variation)\n" | ||
| 395 | "--\n\n" | ||
| 396 | "Find variations of a given move sequence\n" | ||
| 397 | "\n" | ||
| 398 | "Parameters:\n" | ||
| 399 | " - moves: the moves\n" | ||
| 400 | " - variation: the variation to apply, such as 'unniss' or 'lastqt'\n" | ||
| 401 | "\n" | ||
| 402 | "Returns: a list of move sequences, the variation of the given moves.\n" | ||
| 403 | ); | ||
| 404 | PyObject * | ||
| 405 | variations(PyObject *self, PyObject *args) | ||
| 406 | { | ||
| 407 | long long err; | ||
| 408 | const char *m, *v; | ||
| 409 | char result[MAX_SOLUTIONS_SIZE]; | ||
| 410 | |||
| 411 | if (!PyArg_ParseTuple(args, "ss", &m, &v)) | ||
| 412 | return NULL; | ||
| 413 | |||
| 414 | err = nissy_variations(m, v, MAX_SOLUTIONS_SIZE, result); | ||
| 415 | |||
| 416 | return stringlist_result(err, result); | ||
| 417 | } | ||
| 418 | |||
| 384 | static PyMethodDef nissy_methods[] = { | 419 | static PyMethodDef nissy_methods[] = { |
| 385 | { "inverse", inverse, METH_VARARGS, inverse_doc }, | 420 | { "inverse", inverse, METH_VARARGS, inverse_doc }, |
| 386 | { "applymoves", applymoves, METH_VARARGS, applymoves_doc }, | 421 | { "applymoves", applymoves, METH_VARARGS, applymoves_doc }, |
| @@ -392,6 +427,7 @@ static PyMethodDef nissy_methods[] = { | |||
| 392 | { "solve", solve, METH_VARARGS, solve_doc }, | 427 | { "solve", solve, METH_VARARGS, solve_doc }, |
| 393 | { "countmoves", countmoves, METH_VARARGS, countmoves_doc }, | 428 | { "countmoves", countmoves, METH_VARARGS, countmoves_doc }, |
| 394 | { "comparemoves", comparemoves, METH_VARARGS, comparemoves_doc }, | 429 | { "comparemoves", comparemoves, METH_VARARGS, comparemoves_doc }, |
| 430 | { "variations", variations, METH_VARARGS, variations_doc }, | ||
| 395 | { NULL, NULL, 0, NULL } | 431 | { NULL, NULL, 0, NULL } |
| 396 | }; | 432 | }; |
| 397 | 433 | ||
diff --git a/shell/shell.c b/shell/shell.c index 8800094..0e624c9 100644 --- a/shell/shell.c +++ b/shell/shell.c | |||
| @@ -21,6 +21,7 @@ | |||
| 21 | #define FLAG_MOVES2 "-moves2" | 21 | #define FLAG_MOVES2 "-moves2" |
| 22 | #define FLAG_TRANS "-trans" | 22 | #define FLAG_TRANS "-trans" |
| 23 | #define FLAG_SOLVER "-solver" | 23 | #define FLAG_SOLVER "-solver" |
| 24 | #define FLAG_VARIATION "-variation" | ||
| 24 | #define FLAG_NISSTYPE "-nisstype" | 25 | #define FLAG_NISSTYPE "-nisstype" |
| 25 | #define FLAG_MINMOVES "-m" | 26 | #define FLAG_MINMOVES "-m" |
| 26 | #define FLAG_MAXMOVES "-M" | 27 | #define FLAG_MAXMOVES "-M" |
| @@ -43,6 +44,7 @@ typedef struct { | |||
| 43 | char *str_moves2; | 44 | char *str_moves2; |
| 44 | char *str_trans; | 45 | char *str_trans; |
| 45 | char *str_solver; | 46 | char *str_solver; |
| 47 | char *str_variation; | ||
| 46 | char *str_nisstype; | 48 | char *str_nisstype; |
| 47 | unsigned minmoves; | 49 | unsigned minmoves; |
| 48 | unsigned maxmoves; | 50 | unsigned maxmoves; |
| @@ -62,6 +64,7 @@ static int64_t solve_exec(args_t *); | |||
| 62 | static int64_t solve_scramble_exec(args_t *); | 64 | static int64_t solve_scramble_exec(args_t *); |
| 63 | static int64_t countmoves_exec(args_t *); | 65 | static int64_t countmoves_exec(args_t *); |
| 64 | static int64_t comparemoves_exec(args_t *); | 66 | static int64_t comparemoves_exec(args_t *); |
| 67 | static int64_t variation_exec(args_t *); | ||
| 65 | static int64_t help_exec(args_t *); | 68 | static int64_t help_exec(args_t *); |
| 66 | 69 | ||
| 67 | static int parse_args(int, char **, args_t *); | 70 | static int parse_args(int, char **, args_t *); |
| @@ -75,6 +78,7 @@ static bool set_str_moves(int, char **, args_t *); | |||
| 75 | static bool set_str_moves2(int, char **, args_t *); | 78 | static bool set_str_moves2(int, char **, args_t *); |
| 76 | static bool set_str_trans(int, char **, args_t *); | 79 | static bool set_str_trans(int, char **, args_t *); |
| 77 | static bool set_str_solver(int, char **, args_t *); | 80 | static bool set_str_solver(int, char **, args_t *); |
| 81 | static bool set_str_variation(int, char **, args_t *); | ||
| 78 | static bool set_str_nisstype(int, char **, args_t *); | 82 | static bool set_str_nisstype(int, char **, args_t *); |
| 79 | static bool set_minmoves(int, char **, args_t *); | 83 | static bool set_minmoves(int, char **, args_t *); |
| 80 | static bool set_maxmoves(int, char **, args_t *); | 84 | static bool set_maxmoves(int, char **, args_t *); |
| @@ -98,6 +102,7 @@ struct { | |||
| 98 | OPTION(FLAG_MOVES2, 1, set_str_moves2), | 102 | OPTION(FLAG_MOVES2, 1, set_str_moves2), |
| 99 | OPTION(FLAG_TRANS, 1, set_str_trans), | 103 | OPTION(FLAG_TRANS, 1, set_str_trans), |
| 100 | OPTION(FLAG_SOLVER, 1, set_str_solver), | 104 | OPTION(FLAG_SOLVER, 1, set_str_solver), |
| 105 | OPTION(FLAG_VARIATION, 1, set_str_variation), | ||
| 101 | OPTION(FLAG_NISSTYPE, 1, set_str_nisstype), | 106 | OPTION(FLAG_NISSTYPE, 1, set_str_nisstype), |
| 102 | OPTION(FLAG_MINMOVES, 1, set_minmoves), | 107 | OPTION(FLAG_MINMOVES, 1, set_minmoves), |
| 103 | OPTION(FLAG_MAXMOVES, 1, set_maxmoves), | 108 | OPTION(FLAG_MAXMOVES, 1, set_maxmoves), |
| @@ -114,7 +119,6 @@ struct { | |||
| 114 | char *desc; | 119 | char *desc; |
| 115 | int64_t (*exec)(args_t *); | 120 | int64_t (*exec)(args_t *); |
| 116 | } commands[] = { | 121 | } commands[] = { |
| 117 | /* TODO: add synopsis and description here */ | ||
| 118 | COMMAND( | 122 | COMMAND( |
| 119 | "inverse", | 123 | "inverse", |
| 120 | "inverse " FLAG_CUBE " CUBE ", | 124 | "inverse " FLAG_CUBE " CUBE ", |
| @@ -197,6 +201,13 @@ struct { | |||
| 197 | comparemoves_exec | 201 | comparemoves_exec |
| 198 | ), | 202 | ), |
| 199 | COMMAND( | 203 | COMMAND( |
| 204 | "variations", | ||
| 205 | "variations " FLAG_MOVES " MOVES " FLAG_VARIATION " VARIATION", | ||
| 206 | "Find variations of a move sequence." | ||
| 207 | INFO_MOVESFORMAT, | ||
| 208 | variation_exec | ||
| 209 | ), | ||
| 210 | COMMAND( | ||
| 200 | "help", | 211 | "help", |
| 201 | "help [" FLAG_COMMAND " COMMAND]", | 212 | "help [" FLAG_COMMAND " COMMAND]", |
| 202 | "If no COMMAND is specified, prints some generic information " | 213 | "If no COMMAND is specified, prints some generic information " |
| @@ -511,6 +522,22 @@ comparemoves_exec(args_t *args) | |||
| 511 | } | 522 | } |
| 512 | 523 | ||
| 513 | static int64_t | 524 | static int64_t |
| 525 | variation_exec(args_t *args) | ||
| 526 | { | ||
| 527 | long long err; | ||
| 528 | char result[SOLUTIONS_BUFFER_SIZE]; | ||
| 529 | |||
| 530 | err = nissy_variations(args->str_moves, args->str_variation, | ||
| 531 | SOLUTIONS_BUFFER_SIZE, result); | ||
| 532 | |||
| 533 | if (err < 0) | ||
| 534 | return err; | ||
| 535 | printf("%s", result); | ||
| 536 | |||
| 537 | return 0; | ||
| 538 | } | ||
| 539 | |||
| 540 | static int64_t | ||
| 514 | help_exec(args_t *args) | 541 | help_exec(args_t *args) |
| 515 | { | 542 | { |
| 516 | int i; | 543 | int i; |
| @@ -550,6 +577,7 @@ parse_args(int argc, char **argv, args_t *args) | |||
| 550 | .str_moves2 = "", | 577 | .str_moves2 = "", |
| 551 | .str_trans = "", | 578 | .str_trans = "", |
| 552 | .str_solver = "", | 579 | .str_solver = "", |
| 580 | .str_variation = "", | ||
| 553 | .str_nisstype = "", | 581 | .str_nisstype = "", |
| 554 | .minmoves = 0, | 582 | .minmoves = 0, |
| 555 | .maxmoves = 20, | 583 | .maxmoves = 20, |
| @@ -692,6 +720,14 @@ set_str_solver(int argc, char **argv, args_t *args) | |||
| 692 | } | 720 | } |
| 693 | 721 | ||
| 694 | static bool | 722 | static bool |
| 723 | set_str_variation(int argc, char **argv, args_t *args) | ||
| 724 | { | ||
| 725 | args->str_variation = argv[0]; | ||
| 726 | |||
| 727 | return true; | ||
| 728 | } | ||
| 729 | |||
| 730 | static bool | ||
| 695 | set_str_nisstype(int argc, char **argv, args_t *args) | 731 | set_str_nisstype(int argc, char **argv, args_t *args) |
| 696 | { | 732 | { |
| 697 | args->str_nisstype = argv[0]; | 733 | args->str_nisstype = argv[0]; |
diff --git a/src/core/constants.h b/src/core/constants.h index 26f6916..d8f2471 100644 --- a/src/core/constants.h +++ b/src/core/constants.h | |||
| @@ -845,3 +845,69 @@ STATIC equivalent_moves_t equivalent_moves_table[] = { | |||
| 845 | [MOVE_z2] = {{UINT8_MAX}, {2, 2, UINT8_MAX}}, | 845 | [MOVE_z2] = {{UINT8_MAX}, {2, 2, UINT8_MAX}}, |
| 846 | [MOVE_z3] = {{UINT8_MAX}, {2, 2, 2, UINT8_MAX}}, | 846 | [MOVE_z3] = {{UINT8_MAX}, {2, 2, 2, UINT8_MAX}}, |
| 847 | }; | 847 | }; |
| 848 | |||
| 849 | STATIC uint8_t slice_to_basic[] = { | ||
| 850 | [MOVE_M] = MOVE_L, | ||
| 851 | [MOVE_M2] = MOVE_L2, | ||
| 852 | [MOVE_M3] = MOVE_L3, | ||
| 853 | [MOVE_S] = MOVE_F, | ||
| 854 | [MOVE_S2] = MOVE_F2, | ||
| 855 | [MOVE_S3] = MOVE_F3, | ||
| 856 | [MOVE_E] = MOVE_D, | ||
| 857 | [MOVE_E2] = MOVE_D2, | ||
| 858 | [MOVE_E3] = MOVE_D3, | ||
| 859 | }; | ||
| 860 | |||
| 861 | STATIC uint8_t basic_to_slice[] = { | ||
| 862 | [MOVE_U] = MOVE_E3, | ||
| 863 | [MOVE_U2] = MOVE_E2, | ||
| 864 | [MOVE_U3] = MOVE_E, | ||
| 865 | [MOVE_D] = MOVE_E, | ||
| 866 | [MOVE_D2] = MOVE_E2, | ||
| 867 | [MOVE_D3] = MOVE_E3, | ||
| 868 | [MOVE_R] = MOVE_M3, | ||
| 869 | [MOVE_R2] = MOVE_M2, | ||
| 870 | [MOVE_R3] = MOVE_M, | ||
| 871 | [MOVE_L] = MOVE_M, | ||
| 872 | [MOVE_L2] = MOVE_M2, | ||
| 873 | [MOVE_L3] = MOVE_M3, | ||
| 874 | [MOVE_F] = MOVE_S, | ||
| 875 | [MOVE_F2] = MOVE_S2, | ||
| 876 | [MOVE_F3] = MOVE_S3, | ||
| 877 | [MOVE_B] = MOVE_S3, | ||
| 878 | [MOVE_B2] = MOVE_S2, | ||
| 879 | [MOVE_B3] = MOVE_S, | ||
| 880 | }; | ||
| 881 | |||
| 882 | STATIC uint8_t rotation_to_basic[] = { | ||
| 883 | [MOVE_x] = MOVE_R, | ||
| 884 | [MOVE_x2] = MOVE_R2, | ||
| 885 | [MOVE_x3] = MOVE_R3, | ||
| 886 | [MOVE_y] = MOVE_U, | ||
| 887 | [MOVE_y2] = MOVE_U2, | ||
| 888 | [MOVE_y3] = MOVE_U3, | ||
| 889 | [MOVE_z] = MOVE_F, | ||
| 890 | [MOVE_z2] = MOVE_F2, | ||
| 891 | [MOVE_z3] = MOVE_F3, | ||
| 892 | }; | ||
| 893 | |||
| 894 | STATIC uint8_t basic_to_rotation[] = { | ||
| 895 | [MOVE_U] = MOVE_y, | ||
| 896 | [MOVE_U2] = MOVE_y2, | ||
| 897 | [MOVE_U3] = MOVE_y3, | ||
| 898 | [MOVE_D] = MOVE_y3, | ||
| 899 | [MOVE_D2] = MOVE_y2, | ||
| 900 | [MOVE_D3] = MOVE_y, | ||
| 901 | [MOVE_R] = MOVE_x, | ||
| 902 | [MOVE_R2] = MOVE_x2, | ||
| 903 | [MOVE_R3] = MOVE_x3, | ||
| 904 | [MOVE_L] = MOVE_x3, | ||
| 905 | [MOVE_L2] = MOVE_x2, | ||
| 906 | [MOVE_L3] = MOVE_x, | ||
| 907 | [MOVE_F] = MOVE_z, | ||
| 908 | [MOVE_F2] = MOVE_z2, | ||
| 909 | [MOVE_F3] = MOVE_z3, | ||
| 910 | [MOVE_B] = MOVE_z3, | ||
| 911 | [MOVE_B2] = MOVE_z2, | ||
| 912 | [MOVE_B3] = MOVE_z, | ||
| 913 | }; | ||
diff --git a/src/core/core_types.h b/src/core/core_types.h index 19a9f42..53cc95e 100644 --- a/src/core/core_types.h +++ b/src/core/core_types.h | |||
| @@ -1,5 +1,3 @@ | |||
| 1 | #define MOVES_STRUCT_MAXLEN 1000 | ||
| 2 | |||
| 3 | typedef struct { | 1 | typedef struct { |
| 4 | cube_t cube; | 2 | cube_t cube; |
| 5 | uint8_t orientation; | 3 | uint8_t orientation; |
| @@ -8,6 +6,6 @@ typedef struct { | |||
| 8 | typedef struct { | 6 | typedef struct { |
| 9 | size_t nnormal; | 7 | size_t nnormal; |
| 10 | size_t ninverse; | 8 | size_t ninverse; |
| 11 | uint8_t normal[MOVES_STRUCT_MAXLEN]; | 9 | uint8_t normal[NISSY_SIZE_MOVES]; |
| 12 | uint8_t inverse[MOVES_STRUCT_MAXLEN]; | 10 | uint8_t inverse[NISSY_SIZE_MOVES]; |
| 13 | } moves_struct_t; | 11 | } moves_struct_t; |
diff --git a/src/core/moves.h b/src/core/moves.h index 9c8cc90..6169c6e 100644 --- a/src/core/moves.h +++ b/src/core/moves.h | |||
| @@ -11,6 +11,8 @@ STATIC bool moves_struct_equal( | |||
| 11 | STATIC long long comparemoves(const char *, const char *); | 11 | STATIC long long comparemoves(const char *, const char *); |
| 12 | STATIC uint8_t readmodifier(char); | 12 | STATIC uint8_t readmodifier(char); |
| 13 | STATIC int64_t writemoves(size_t, const uint8_t *, size_t, char *); | 13 | STATIC int64_t writemoves(size_t, const uint8_t *, size_t, char *); |
| 14 | STATIC int64_t writemoves_struct( | ||
| 15 | const moves_struct_t [static 1], size_t, char *); | ||
| 14 | 16 | ||
| 15 | STATIC_INLINE bool allowednextmove(uint8_t, uint8_t); | 17 | STATIC_INLINE bool allowednextmove(uint8_t, uint8_t); |
| 16 | STATIC bool allowedmoves(size_t, const uint8_t *); | 18 | STATIC bool allowedmoves(size_t, const uint8_t *); |
| @@ -23,6 +25,7 @@ STATIC_INLINE uint8_t moveopposite(uint8_t); | |||
| 23 | STATIC_INLINE uint8_t reorient_move(uint8_t, uint8_t); | 25 | STATIC_INLINE uint8_t reorient_move(uint8_t, uint8_t); |
| 24 | STATIC_INLINE uint8_t inverse_reorient_move(uint8_t, uint8_t); | 26 | STATIC_INLINE uint8_t inverse_reorient_move(uint8_t, uint8_t); |
| 25 | STATIC_INLINE uint8_t movefollow(uint8_t); | 27 | STATIC_INLINE uint8_t movefollow(uint8_t); |
| 28 | STATIC uint8_t transform_move_basic(uint8_t, uint8_t); | ||
| 26 | STATIC uint8_t transform_move(uint8_t, uint8_t); | 29 | STATIC uint8_t transform_move(uint8_t, uint8_t); |
| 27 | 30 | ||
| 28 | STATIC cube_t move(cube_t, uint8_t); | 31 | STATIC cube_t move(cube_t, uint8_t); |
| @@ -31,6 +34,12 @@ STATIC uint8_t inverse_move(uint8_t); | |||
| 31 | STATIC void sortparallel_moves(size_t, uint8_t*); | 34 | STATIC void sortparallel_moves(size_t, uint8_t*); |
| 32 | STATIC bool are_lastmoves_singlecw(size_t, const uint8_t*); | 35 | STATIC bool are_lastmoves_singlecw(size_t, const uint8_t*); |
| 33 | 36 | ||
| 37 | STATIC int64_t move_variations(const char *, const char *, size_t, char *); | ||
| 38 | STATIC int64_t move_variations_lastqt( | ||
| 39 | const moves_struct_t [static 1], size_t, char *); | ||
| 40 | STATIC int64_t move_variations_unniss( | ||
| 41 | const moves_struct_t [static 1], size_t, char *); | ||
| 42 | |||
| 34 | #define FOREACH_READMOVE(ARG_BUF, ARG_MOVE, ARG_C, ARG_MAX, \ | 43 | #define FOREACH_READMOVE(ARG_BUF, ARG_MOVE, ARG_C, ARG_MAX, \ |
| 35 | RET_ERROR, ARG_ACTION) \ | 44 | RET_ERROR, ARG_ACTION) \ |
| 36 | const char *VAR_B; \ | 45 | const char *VAR_B; \ |
| @@ -160,7 +169,7 @@ readmoves( | |||
| 160 | STATIC int64_t | 169 | STATIC int64_t |
| 161 | readmoves_struct(const char *moves, moves_struct_t ret[static 1]) | 170 | readmoves_struct(const char *moves, moves_struct_t ret[static 1]) |
| 162 | { | 171 | { |
| 163 | return readmoves(moves, MOVES_STRUCT_MAXLEN, MOVES_STRUCT_MAXLEN, | 172 | return readmoves(moves, NISSY_SIZE_MOVES, NISSY_SIZE_MOVES, |
| 164 | &ret->nnormal, &ret->ninverse, ret->normal, ret->inverse); | 173 | &ret->nnormal, &ret->ninverse, ret->normal, ret->inverse); |
| 165 | } | 174 | } |
| 166 | 175 | ||
| @@ -270,6 +279,51 @@ writemoves_error: | |||
| 270 | return NISSY_ERROR_BUFFER_SIZE; | 279 | return NISSY_ERROR_BUFFER_SIZE; |
| 271 | } | 280 | } |
| 272 | 281 | ||
| 282 | STATIC int64_t | ||
| 283 | writemoves_struct( | ||
| 284 | const moves_struct_t moves[static 1], | ||
| 285 | size_t buf_size, | ||
| 286 | char *buf | ||
| 287 | ) | ||
| 288 | { | ||
| 289 | int64_t w, u; | ||
| 290 | |||
| 291 | w = 0; | ||
| 292 | if (moves->nnormal > 0) { | ||
| 293 | w = writemoves(moves->nnormal, moves->normal, buf_size, buf); | ||
| 294 | if (w < 0) | ||
| 295 | goto writemoves_struct_error; | ||
| 296 | } | ||
| 297 | |||
| 298 | u = 0; | ||
| 299 | if (moves->ninverse > 0) { | ||
| 300 | if (moves->nnormal > 0) { | ||
| 301 | if ((size_t)w >= buf_size) | ||
| 302 | goto writemoves_struct_error; | ||
| 303 | buf[w++] = ' '; | ||
| 304 | } | ||
| 305 | if ((size_t)w >= buf_size) | ||
| 306 | goto writemoves_struct_error; | ||
| 307 | buf[w++] = '('; | ||
| 308 | |||
| 309 | u = writemoves(moves->ninverse, moves->inverse, | ||
| 310 | buf_size-w, buf+w); | ||
| 311 | if (u < 0) | ||
| 312 | goto writemoves_struct_error; | ||
| 313 | |||
| 314 | if ((size_t)w >= buf_size) | ||
| 315 | goto writemoves_struct_error; | ||
| 316 | buf[w + (u++)] = ')'; | ||
| 317 | } | ||
| 318 | |||
| 319 | buf[u+w] = '\0'; | ||
| 320 | return u+w; | ||
| 321 | |||
| 322 | writemoves_struct_error: | ||
| 323 | buf[w] = '\0'; | ||
| 324 | return NISSY_ERROR_BUFFER_SIZE; | ||
| 325 | } | ||
| 326 | |||
| 273 | STATIC_INLINE bool | 327 | STATIC_INLINE bool |
| 274 | allowednextmove(uint8_t m1, uint8_t m2) | 328 | allowednextmove(uint8_t m1, uint8_t m2) |
| 275 | { | 329 | { |
| @@ -408,14 +462,12 @@ move(cube_t c, uint8_t m) | |||
| 408 | } | 462 | } |
| 409 | 463 | ||
| 410 | STATIC uint8_t | 464 | STATIC uint8_t |
| 411 | transform_move(uint8_t m, uint8_t t) | 465 | transform_move_basic(uint8_t m, uint8_t t) |
| 412 | { | 466 | { |
| 413 | uint8_t a, base, modifier; | 467 | uint8_t a, base, modifier; |
| 414 | 468 | ||
| 415 | if (m > MOVE_B3) { | 469 | if (t > 47) { |
| 416 | LOG("transform_move: attempting to transform %s, but " | 470 | LOG("transform_move: invalid trans %" PRIu8 "\n", t); |
| 417 | "transofrmations are only supported for basic moves\n", | ||
| 418 | movestr[m]); | ||
| 419 | return UINT8_ERROR; | 471 | return UINT8_ERROR; |
| 420 | } | 472 | } |
| 421 | 473 | ||
| @@ -431,6 +483,27 @@ transform_move(uint8_t m, uint8_t t) | |||
| 431 | return base + modifier; | 483 | return base + modifier; |
| 432 | } | 484 | } |
| 433 | 485 | ||
| 486 | STATIC uint8_t | ||
| 487 | transform_move(uint8_t m, uint8_t t) | ||
| 488 | { | ||
| 489 | if (m <= MOVE_B3) | ||
| 490 | return transform_move_basic(m, t); | ||
| 491 | |||
| 492 | if (m >= MOVE_Uw && m <= MOVE_Bw3) | ||
| 493 | return 18+transform_move_basic(m-18, t); | ||
| 494 | |||
| 495 | if (m >= MOVE_M && m <= MOVE_E3) | ||
| 496 | return basic_to_slice[ | ||
| 497 | transform_move_basic(slice_to_basic[m], t)]; | ||
| 498 | |||
| 499 | if (m >= MOVE_x && m <= MOVE_z3) | ||
| 500 | return basic_to_rotation[ | ||
| 501 | transform_move_basic(rotation_to_basic[m], t)]; | ||
| 502 | |||
| 503 | LOG("transform_move: invalid move %" PRIu8 "\n", m); | ||
| 504 | return UINT8_ERROR; | ||
| 505 | } | ||
| 506 | |||
| 434 | /* Applies the INVERSE of m BEFORE the scramble corresponding to c */ | 507 | /* Applies the INVERSE of m BEFORE the scramble corresponding to c */ |
| 435 | STATIC cube_t | 508 | STATIC cube_t |
| 436 | premove(cube_t c, uint8_t m) | 509 | premove(cube_t c, uint8_t m) |
| @@ -509,3 +582,140 @@ are_lastmoves_singlecw(size_t n, const uint8_t *moves) | |||
| 509 | 582 | ||
| 510 | return isbase(moves[n-1]) && (!two || isbase(moves[n-2])); | 583 | return isbase(moves[n-1]) && (!two || isbase(moves[n-2])); |
| 511 | } | 584 | } |
| 585 | |||
| 586 | STATIC int64_t | ||
| 587 | move_variations( | ||
| 588 | const char *moves, | ||
| 589 | const char *variation, | ||
| 590 | size_t result_size, | ||
| 591 | char *result | ||
| 592 | ) | ||
| 593 | { | ||
| 594 | moves_struct_t m; | ||
| 595 | int64_t err; | ||
| 596 | |||
| 597 | err = readmoves_struct(moves, &m); | ||
| 598 | if (err < 0) { | ||
| 599 | LOG("[variations] Error reading moves.\n"); | ||
| 600 | return err; | ||
| 601 | } | ||
| 602 | |||
| 603 | if (!strcmp(variation, "lastqt")) { | ||
| 604 | return move_variations_lastqt(&m, result_size, result); | ||
| 605 | } else if (!strcmp(variation, "unniss")) { | ||
| 606 | return move_variations_unniss(&m, result_size, result); | ||
| 607 | } else { | ||
| 608 | LOG("[variations] Error: unknown variation '%s'\n", variation); | ||
| 609 | return NISSY_ERROR_INVALID_VARIATION; | ||
| 610 | } | ||
| 611 | } | ||
| 612 | |||
| 613 | STATIC int64_t | ||
| 614 | move_variations_lastqt( | ||
| 615 | const moves_struct_t s[static 1], | ||
| 616 | size_t result_size, | ||
| 617 | char *result | ||
| 618 | ) | ||
| 619 | { | ||
| 620 | uint8_t n1, n2, i1, i2, swapn1, swapn2, swapi1, swapi2, i, j, k, l; | ||
| 621 | int8_t in1, in2, ii1, ii2; | ||
| 622 | int64_t err, count; | ||
| 623 | size_t u; | ||
| 624 | moves_struct_t ss; | ||
| 625 | |||
| 626 | in1 = s->nnormal-1; | ||
| 627 | in2 = s->nnormal-2; | ||
| 628 | ii1 = s->ninverse-1; | ||
| 629 | ii2 = s->ninverse-2; | ||
| 630 | |||
| 631 | n1 = in1 >= 0 ? s->normal[in1] : UINT8_ERROR; | ||
| 632 | n2 = in2 >= 0 ? s->normal[in2] : UINT8_ERROR; | ||
| 633 | i1 = ii1 >= 0 ? s->inverse[ii1] : UINT8_ERROR; | ||
| 634 | i2 = ii2 >= 0 ? s->inverse[ii2] : UINT8_ERROR; | ||
| 635 | |||
| 636 | swapn1 = in1 >= 0 && n1 % 3 != 1 ? 1 : 0; | ||
| 637 | swapn2 = swapn1 && in2 >= 0 && n2 % 3 != 1 && parallel(n1, n2) ? 1 : 0; | ||
| 638 | swapi1 = ii1 >= 0 && i1 % 3 != 1 ? 1 : 0; | ||
| 639 | swapi2 = swapi1 && ii2 >= 0 && i2 % 3 != 1 && parallel(i1, i2) ? 1 : 0; | ||
| 640 | |||
| 641 | /* Reset ending qt to base so that they are sorted */ | ||
| 642 | ss = *s; | ||
| 643 | if (swapn1 == 1) ss.normal[in1] = 3*movebase(n1); | ||
| 644 | if (swapn2 == 1) ss.normal[in2] = 3*movebase(n2); | ||
| 645 | if (swapi1 == 1) ss.inverse[ii1] = 3*movebase(i1); | ||
| 646 | if (swapi2 == 1) ss.inverse[ii2] = 3*movebase(i2); | ||
| 647 | |||
| 648 | u = 0; | ||
| 649 | count = 0; | ||
| 650 | for (i = 0; i <= swapn2; i++) { | ||
| 651 | if (i == 1) ss.normal[in2] += 2; | ||
| 652 | for (j = 0; j <= swapn1; j++) { | ||
| 653 | if (j == 1) ss.normal[in1] += 2; | ||
| 654 | for (k = 0; k <= swapi2; k++) { | ||
| 655 | if (k == 1) ss.inverse[ii2] += 2; | ||
| 656 | for (l = 0; l <= swapi1; l++) { | ||
| 657 | if (l == 1) ss.inverse[ii1] += 2; | ||
| 658 | |||
| 659 | err = writemoves_struct( | ||
| 660 | &ss, result_size-u, result+u); | ||
| 661 | if (err < 0) | ||
| 662 | goto lastqt_error; | ||
| 663 | u += err; | ||
| 664 | count++; | ||
| 665 | |||
| 666 | if (u >= result_size) | ||
| 667 | goto lastqt_error; | ||
| 668 | result[u++] = '\n'; | ||
| 669 | result[u] = '\0'; | ||
| 670 | |||
| 671 | if (l == 1) ss.inverse[ii1] -= 2; | ||
| 672 | } | ||
| 673 | if (k == 1) ss.inverse[ii2] -= 2; | ||
| 674 | } | ||
| 675 | if (j == 1) ss.normal[in1] -= 2; | ||
| 676 | } | ||
| 677 | if (i == 1) ss.normal[in2] -= 2; | ||
| 678 | } | ||
| 679 | |||
| 680 | return count; | ||
| 681 | |||
| 682 | lastqt_error: | ||
| 683 | LOG("[variations] Error writing result.\n"); | ||
| 684 | return NISSY_ERROR_BUFFER_SIZE; | ||
| 685 | } | ||
| 686 | |||
| 687 | STATIC int64_t | ||
| 688 | move_variations_unniss( | ||
| 689 | const moves_struct_t s[static 1], | ||
| 690 | size_t result_size, | ||
| 691 | char *result | ||
| 692 | ) | ||
| 693 | { | ||
| 694 | size_t i, tot; | ||
| 695 | uint8_t res[NISSY_SIZE_MOVES]; | ||
| 696 | int64_t err; | ||
| 697 | |||
| 698 | tot = s->nnormal + s->ninverse; | ||
| 699 | if (tot > NISSY_SIZE_MOVES) { | ||
| 700 | LOG("[variations] Error: %zu total moves, more than maximum " | ||
| 701 | "allowed %zu", tot, NISSY_SIZE_MOVES); | ||
| 702 | return NISSY_ERROR_BUFFER_SIZE; | ||
| 703 | } | ||
| 704 | |||
| 705 | for (i = 0; i < s->nnormal; i++) | ||
| 706 | res[i] = s->normal[i]; | ||
| 707 | for (i = 0; i < s->ninverse; i++) | ||
| 708 | res[i+s->nnormal] = inverse_move(s->inverse[s->ninverse-i-1]); | ||
| 709 | |||
| 710 | err = writemoves(tot, res, result_size, result); | ||
| 711 | if (err < 0 || (size_t)err > result_size) | ||
| 712 | goto unniss_error; | ||
| 713 | |||
| 714 | result[err++] = '\n'; | ||
| 715 | result[err] = '\0'; | ||
| 716 | return 1; | ||
| 717 | |||
| 718 | unniss_error: | ||
| 719 | LOG("[variations] Error writing result.\n"); | ||
| 720 | return NISSY_ERROR_BUFFER_SIZE; | ||
| 721 | } | ||
diff --git a/src/nissy.c b/src/nissy.c index 4b5d476..17ef960 100644 --- a/src/nissy.c +++ b/src/nissy.c | |||
| @@ -149,6 +149,32 @@ nissy_applytrans_error: | |||
| 149 | } | 149 | } |
| 150 | 150 | ||
| 151 | long long | 151 | long long |
| 152 | nissy_variations( | ||
| 153 | const char *moves, | ||
| 154 | const char *variation, | ||
| 155 | unsigned long long result_size, | ||
| 156 | char *result | ||
| 157 | ) | ||
| 158 | { | ||
| 159 | if (moves == NULL) { | ||
| 160 | LOG("[variations] Error: 'moves' argument is NULL\n"); | ||
| 161 | return NISSY_ERROR_NULL_POINTER; | ||
| 162 | } | ||
| 163 | |||
| 164 | if (variation == NULL) { | ||
| 165 | LOG("[variations] Error: 'variation' argument is NULL\n"); | ||
| 166 | return NISSY_ERROR_NULL_POINTER; | ||
| 167 | } | ||
| 168 | |||
| 169 | if (result == NULL) { | ||
| 170 | LOG("[variations] Error: 'result' argument is NULL\n"); | ||
| 171 | return NISSY_ERROR_NULL_POINTER; | ||
| 172 | } | ||
| 173 | |||
| 174 | return move_variations(moves, variation, result_size, result); | ||
| 175 | } | ||
| 176 | |||
| 177 | long long | ||
| 152 | nissy_getcube( | 178 | nissy_getcube( |
| 153 | long long ep, | 179 | long long ep, |
| 154 | long long eo, | 180 | long long eo, |
diff --git a/src/nissy.h b/src/nissy.h index 38fe656..959b2d8 100644 --- a/src/nissy.h +++ b/src/nissy.h | |||
| @@ -27,6 +27,7 @@ for example 'rotation UF' or 'mirrored BL'. | |||
| 27 | #define NISSY_SIZE_TRANSFORMATION 12U | 27 | #define NISSY_SIZE_TRANSFORMATION 12U |
| 28 | #define NISSY_SIZE_SOLVE_STATS 10U | 28 | #define NISSY_SIZE_SOLVE_STATS 10U |
| 29 | #define NISSY_SIZE_DATAID 255U | 29 | #define NISSY_SIZE_DATAID 255U |
| 30 | #define NISSY_SIZE_MOVES 1000U | ||
| 30 | 31 | ||
| 31 | /* Flags for NISS options */ | 32 | /* Flags for NISS options */ |
| 32 | #define NISSY_NISSFLAG_NORMAL 1U | 33 | #define NISSY_NISSFLAG_NORMAL 1U |
| @@ -99,6 +100,12 @@ not known. | |||
| 99 | #define NISSY_ERROR_INVALID_SOLVER -50LL | 100 | #define NISSY_ERROR_INVALID_SOLVER -50LL |
| 100 | 101 | ||
| 101 | /* | 102 | /* |
| 103 | The value NISSY_ERROR_INVALID_VARIATION means that the given method of | ||
| 104 | finding variations for a solution is not known. | ||
| 105 | */ | ||
| 106 | #define NISSY_ERROR_INVALID_VARIATION -51LL | ||
| 107 | |||
| 108 | /* | ||
| 102 | The value NISSY_ERROR_NULL_POINTER means that one of the provided pointer | 109 | The value NISSY_ERROR_NULL_POINTER means that one of the provided pointer |
| 103 | arguments is NULL. For example, it may be returned by solve when called | 110 | arguments is NULL. For example, it may be returned by solve when called |
| 104 | with a solver that requires some pre-computed data, but the provided | 111 | with a solver that requires some pre-computed data, but the provided |
| @@ -205,6 +212,36 @@ nissy_applytrans( | |||
| 205 | ); | 212 | ); |
| 206 | 213 | ||
| 207 | /* | 214 | /* |
| 215 | Find variations of a given move sequence, for example by changing | ||
| 216 | the direction of the last quarter turn(s), or linearizing a NISS move | ||
| 217 | sequence. The result consists of one or more move sequences, one per line, | ||
| 218 | and it always ends in a newline character. | ||
| 219 | |||
| 220 | Parameters: | ||
| 221 | moves - The moves of which to find the variation. Must be at most | ||
| 222 | NISSY_SIZE_MOVES long. | ||
| 223 | variations - Specify which kind of variations to find, e.g. "lastqt". | ||
| 224 | result_size - The size of the result buffer. | ||
| 225 | result - The result buffer. | ||
| 226 | |||
| 227 | Return values: | ||
| 228 | NISSY_ERROR_NULL_POINTER - One of the provided pointers is NULL. | ||
| 229 | NISSY_ERROR_INVALID_MOVES - The given moves are invalid. | ||
| 230 | NISSY_ERROR_INVALID_VARIATION - The given transformer is not known. | ||
| 231 | NISSY_ERROR_BUFFER_SIZE - Either the result buffer is too small or the | ||
| 232 | given move sequence is longer than | ||
| 233 | NISSY_SIZE_MOVES. | ||
| 234 | Any value >= 0 - The number of variations found. | ||
| 235 | */ | ||
| 236 | long long | ||
| 237 | nissy_variations( | ||
| 238 | const char *moves, | ||
| 239 | const char *variation, | ||
| 240 | unsigned long long result_size, | ||
| 241 | char *result | ||
| 242 | ); | ||
| 243 | |||
| 244 | /* | ||
| 208 | Get the cube with the given ep, eo, cp and co values. The values must be in the | 245 | Get the cube with the given ep, eo, cp and co values. The values must be in the |
| 209 | ranges specified below, but if the option "fix" is given any values outside its | 246 | ranges specified below, but if the option "fix" is given any values outside its |
| 210 | range will be adjusted before using it. The option "fix" also fixes parity and | 247 | range will be adjusted before using it. The option "fix" also fixes parity and |
| @@ -365,6 +402,8 @@ nissy_solve( | |||
| 365 | ); | 402 | ); |
| 366 | 403 | ||
| 367 | /* | 404 | /* |
| 405 | Count the given moves. | ||
| 406 | |||
| 368 | Parameters: | 407 | Parameters: |
| 369 | moves - The moves to be counted. | 408 | moves - The moves to be counted. |
| 370 | 409 | ||
| @@ -379,6 +418,8 @@ nissy_countmoves( | |||
| 379 | ); | 418 | ); |
| 380 | 419 | ||
| 381 | /* | 420 | /* |
| 421 | Compare the two moves sequences. Both must be at most NISSY_SIZE_MOVES long. | ||
| 422 | |||
| 382 | Parameters: | 423 | Parameters: |
| 383 | moves1 - The first sequence of moves to compare. | 424 | moves1 - The first sequence of moves to compare. |
| 384 | moves2 - The second sequence of moves to compare. | 425 | moves2 - The second sequence of moves to compare. |
diff --git a/src/solvers/solutions.h b/src/solvers/solutions.h index 00ed84c..9f209d1 100644 --- a/src/solvers/solutions.h +++ b/src/solvers/solutions.h | |||
| @@ -55,7 +55,7 @@ solution_list_init(solution_list_t sols[static 1], size_t n, char *buf) | |||
| 55 | return false; | 55 | return false; |
| 56 | 56 | ||
| 57 | sols->nsols = 0; | 57 | sols->nsols = 0; |
| 58 | sols->shortest_sol = MAXLEN + 1; | 58 | sols->shortest_sol = SOLUTION_MAXLEN + 1; |
| 59 | sols->size = n; | 59 | sols->size = n; |
| 60 | sols->used = 0; | 60 | sols->used = 0; |
| 61 | sols->buf = buf; | 61 | sols->buf = buf; |
| @@ -162,7 +162,7 @@ appendsolution( | |||
| 162 | uint8_t t; | 162 | uint8_t t; |
| 163 | solution_moves_t tsol[NTRANS]; | 163 | solution_moves_t tsol[NTRANS]; |
| 164 | 164 | ||
| 165 | if (moves->nmoves + moves->npremoves > MAXLEN) | 165 | if (moves->nmoves + moves->npremoves > SOLUTION_MAXLEN) |
| 166 | goto appendsolution_error_solution_length; | 166 | goto appendsolution_error_solution_length; |
| 167 | 167 | ||
| 168 | for ( | 168 | for ( |
diff --git a/src/solvers/solutions_types_macros.h b/src/solvers/solutions_types_macros.h index f1cb517..e57e039 100644 --- a/src/solvers/solutions_types_macros.h +++ b/src/solvers/solutions_types_macros.h | |||
| @@ -1,10 +1,10 @@ | |||
| 1 | #define MAXLEN 20 | 1 | #define SOLUTION_MAXLEN 20 |
| 2 | 2 | ||
| 3 | typedef struct { | 3 | typedef struct { |
| 4 | uint8_t nmoves; | 4 | uint8_t nmoves; |
| 5 | uint8_t moves[MAXLEN]; | 5 | uint8_t moves[SOLUTION_MAXLEN]; |
| 6 | uint8_t npremoves; | 6 | uint8_t npremoves; |
| 7 | uint8_t premoves[MAXLEN]; | 7 | uint8_t premoves[SOLUTION_MAXLEN]; |
| 8 | } solution_moves_t; | 8 | } solution_moves_t; |
| 9 | 9 | ||
| 10 | typedef struct { | 10 | typedef struct { |
diff --git a/test/150_variations/00_unniss.in b/test/150_variations/00_unniss.in new file mode 100644 index 0000000..84c3c3d --- /dev/null +++ b/test/150_variations/00_unniss.in | |||
| @@ -0,0 +1,2 @@ | |||
| 1 | unniss | ||
| 2 | Uw2 F B' L x M R D' (D' R2 F' L2 B D') | ||
diff --git a/test/150_variations/00_unniss.out b/test/150_variations/00_unniss.out new file mode 100644 index 0000000..f38061b --- /dev/null +++ b/test/150_variations/00_unniss.out | |||
| @@ -0,0 +1,2 @@ | |||
| 1 | 1 | ||
| 2 | Uw2 F B' L x M R D' D B' L2 F R2 D | ||
diff --git a/test/150_variations/01_lastqt_simple.in b/test/150_variations/01_lastqt_simple.in new file mode 100644 index 0000000..f7ecc50 --- /dev/null +++ b/test/150_variations/01_lastqt_simple.in | |||
| @@ -0,0 +1,2 @@ | |||
| 1 | lastqt | ||
| 2 | U2 D L' F | ||
diff --git a/test/150_variations/01_lastqt_simple.out b/test/150_variations/01_lastqt_simple.out new file mode 100644 index 0000000..53fbdcc --- /dev/null +++ b/test/150_variations/01_lastqt_simple.out | |||
| @@ -0,0 +1,3 @@ | |||
| 1 | 2 | ||
| 2 | U2 D L' F | ||
| 3 | U2 D L' F' | ||
diff --git a/test/150_variations/02_lastqt_niss.in b/test/150_variations/02_lastqt_niss.in new file mode 100644 index 0000000..fc72321 --- /dev/null +++ b/test/150_variations/02_lastqt_niss.in | |||
| @@ -0,0 +1,2 @@ | |||
| 1 | lastqt | ||
| 2 | U B2 L (F R') | ||
diff --git a/test/150_variations/02_lastqt_niss.out b/test/150_variations/02_lastqt_niss.out new file mode 100644 index 0000000..52c0db0 --- /dev/null +++ b/test/150_variations/02_lastqt_niss.out | |||
| @@ -0,0 +1,5 @@ | |||
| 1 | 4 | ||
| 2 | U B2 L (F R) | ||
| 3 | U B2 L (F R') | ||
| 4 | U B2 L' (F R) | ||
| 5 | U B2 L' (F R') | ||
diff --git a/test/150_variations/03_lastqt_parallel.in b/test/150_variations/03_lastqt_parallel.in new file mode 100644 index 0000000..8a650fb --- /dev/null +++ b/test/150_variations/03_lastqt_parallel.in | |||
| @@ -0,0 +1,2 @@ | |||
| 1 | lastqt | ||
| 2 | U F B' | ||
diff --git a/test/150_variations/03_lastqt_parallel.out b/test/150_variations/03_lastqt_parallel.out new file mode 100644 index 0000000..611b3df --- /dev/null +++ b/test/150_variations/03_lastqt_parallel.out | |||
| @@ -0,0 +1,5 @@ | |||
| 1 | 4 | ||
| 2 | U F B | ||
| 3 | U F B' | ||
| 4 | U F' B | ||
| 5 | U F' B' | ||
diff --git a/test/150_variations/04_lastqt_parallel_niss.in b/test/150_variations/04_lastqt_parallel_niss.in new file mode 100644 index 0000000..8f186f5 --- /dev/null +++ b/test/150_variations/04_lastqt_parallel_niss.in | |||
| @@ -0,0 +1,2 @@ | |||
| 1 | lastqt | ||
| 2 | L2 R U' D (U' D') | ||
diff --git a/test/150_variations/04_lastqt_parallel_niss.out b/test/150_variations/04_lastqt_parallel_niss.out new file mode 100644 index 0000000..5600d88 --- /dev/null +++ b/test/150_variations/04_lastqt_parallel_niss.out | |||
| @@ -0,0 +1,17 @@ | |||
| 1 | 16 | ||
| 2 | L2 R U D (U D) | ||
| 3 | L2 R U D (U D') | ||
| 4 | L2 R U D (U' D) | ||
| 5 | L2 R U D (U' D') | ||
| 6 | L2 R U D' (U D) | ||
| 7 | L2 R U D' (U D') | ||
| 8 | L2 R U D' (U' D) | ||
| 9 | L2 R U D' (U' D') | ||
| 10 | L2 R U' D (U D) | ||
| 11 | L2 R U' D (U D') | ||
| 12 | L2 R U' D (U' D) | ||
| 13 | L2 R U' D (U' D') | ||
| 14 | L2 R U' D' (U D) | ||
| 15 | L2 R U' D' (U D') | ||
| 16 | L2 R U' D' (U' D) | ||
| 17 | L2 R U' D' (U' D') | ||
diff --git a/test/150_variations/variations.c b/test/150_variations/variations.c new file mode 100644 index 0000000..2c08607 --- /dev/null +++ b/test/150_variations/variations.c | |||
| @@ -0,0 +1,19 @@ | |||
| 1 | #include "../test.h" | ||
| 2 | |||
| 3 | long long nissy_variations( | ||
| 4 | const char *, const char *, long long unsigned, char *); | ||
| 5 | |||
| 6 | void run(void) { | ||
| 7 | long long err; | ||
| 8 | char variation[STRLENMAX], moves[STRLENMAX], result[STRLENMAX]; | ||
| 9 | |||
| 10 | fgets(variation, STRLENMAX, stdin); | ||
| 11 | variation[strlen(variation)-1] = '\0'; /* Remove newline */ | ||
| 12 | fgets(moves, STRLENMAX, stdin); | ||
| 13 | |||
| 14 | err = nissy_variations(moves, variation, STRLENMAX, result); | ||
| 15 | if (err < 0) | ||
| 16 | printf("Error %lld\n", err); | ||
| 17 | else | ||
| 18 | printf("%lld\n%s", err, result); | ||
| 19 | } | ||
