aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to '')
l---------.dockerignore1
-rw-r--r--cpp/examples/variations.cpp15
-rw-r--r--cpp/nissy.cpp34
-rw-r--r--cpp/nissy.h16
-rw-r--r--python/examples/variations.py12
-rw-r--r--python/nissy_module.c74
-rw-r--r--shell/shell.c38
-rw-r--r--src/core/constants.h66
-rw-r--r--src/core/core_types.h6
-rw-r--r--src/core/moves.h222
-rw-r--r--src/nissy.c26
-rw-r--r--src/nissy.h41
-rw-r--r--src/solvers/solutions.h4
-rw-r--r--src/solvers/solutions_types_macros.h6
-rw-r--r--test/150_variations/00_unniss.in2
-rw-r--r--test/150_variations/00_unniss.out2
-rw-r--r--test/150_variations/01_lastqt_simple.in2
-rw-r--r--test/150_variations/01_lastqt_simple.out3
-rw-r--r--test/150_variations/02_lastqt_niss.in2
-rw-r--r--test/150_variations/02_lastqt_niss.out5
-rw-r--r--test/150_variations/03_lastqt_parallel.in2
-rw-r--r--test/150_variations/03_lastqt_parallel.out5
-rw-r--r--test/150_variations/04_lastqt_parallel_niss.in2
-rw-r--r--test/150_variations/04_lastqt_parallel_niss.out17
-rw-r--r--test/150_variations/variations.c19
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
6int 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
4from sys import path
5path.append("./")
6import nissy_python_module as nissy
7
8moves = "R U' Bw2 M D' x' F B(E2 F D B' Lw2 U2 U' S2 B)"
9
10print("Changing the last quarter turns of {} gives:".format(moves))
11for 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
46static PyObject * 46static PyObject *
47stringlist_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
69static PyObject *
47string_result_free(long long err, char *result) 70string_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
325PyDoc_STRVAR(countmoves_doc, 333PyDoc_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
393PyDoc_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);
404PyObject *
405variations(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
384static PyMethodDef nissy_methods[] = { 419static 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 *);
62static int64_t solve_scramble_exec(args_t *); 64static int64_t solve_scramble_exec(args_t *);
63static int64_t countmoves_exec(args_t *); 65static int64_t countmoves_exec(args_t *);
64static int64_t comparemoves_exec(args_t *); 66static int64_t comparemoves_exec(args_t *);
67static int64_t variation_exec(args_t *);
65static int64_t help_exec(args_t *); 68static int64_t help_exec(args_t *);
66 69
67static int parse_args(int, char **, args_t *); 70static int parse_args(int, char **, args_t *);
@@ -75,6 +78,7 @@ static bool set_str_moves(int, char **, args_t *);
75static bool set_str_moves2(int, char **, args_t *); 78static bool set_str_moves2(int, char **, args_t *);
76static bool set_str_trans(int, char **, args_t *); 79static bool set_str_trans(int, char **, args_t *);
77static bool set_str_solver(int, char **, args_t *); 80static bool set_str_solver(int, char **, args_t *);
81static bool set_str_variation(int, char **, args_t *);
78static bool set_str_nisstype(int, char **, args_t *); 82static bool set_str_nisstype(int, char **, args_t *);
79static bool set_minmoves(int, char **, args_t *); 83static bool set_minmoves(int, char **, args_t *);
80static bool set_maxmoves(int, char **, args_t *); 84static 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
513static int64_t 524static int64_t
525variation_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
540static int64_t
514help_exec(args_t *args) 541help_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
694static bool 722static bool
723set_str_variation(int argc, char **argv, args_t *args)
724{
725 args->str_variation = argv[0];
726
727 return true;
728}
729
730static bool
695set_str_nisstype(int argc, char **argv, args_t *args) 731set_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
849STATIC 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
861STATIC 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
882STATIC 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
894STATIC 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
3typedef struct { 1typedef struct {
4 cube_t cube; 2 cube_t cube;
5 uint8_t orientation; 3 uint8_t orientation;
@@ -8,6 +6,6 @@ typedef struct {
8typedef struct { 6typedef 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(
11STATIC long long comparemoves(const char *, const char *); 11STATIC long long comparemoves(const char *, const char *);
12STATIC uint8_t readmodifier(char); 12STATIC uint8_t readmodifier(char);
13STATIC int64_t writemoves(size_t, const uint8_t *, size_t, char *); 13STATIC int64_t writemoves(size_t, const uint8_t *, size_t, char *);
14STATIC int64_t writemoves_struct(
15 const moves_struct_t [static 1], size_t, char *);
14 16
15STATIC_INLINE bool allowednextmove(uint8_t, uint8_t); 17STATIC_INLINE bool allowednextmove(uint8_t, uint8_t);
16STATIC bool allowedmoves(size_t, const uint8_t *); 18STATIC bool allowedmoves(size_t, const uint8_t *);
@@ -23,6 +25,7 @@ STATIC_INLINE uint8_t moveopposite(uint8_t);
23STATIC_INLINE uint8_t reorient_move(uint8_t, uint8_t); 25STATIC_INLINE uint8_t reorient_move(uint8_t, uint8_t);
24STATIC_INLINE uint8_t inverse_reorient_move(uint8_t, uint8_t); 26STATIC_INLINE uint8_t inverse_reorient_move(uint8_t, uint8_t);
25STATIC_INLINE uint8_t movefollow(uint8_t); 27STATIC_INLINE uint8_t movefollow(uint8_t);
28STATIC uint8_t transform_move_basic(uint8_t, uint8_t);
26STATIC uint8_t transform_move(uint8_t, uint8_t); 29STATIC uint8_t transform_move(uint8_t, uint8_t);
27 30
28STATIC cube_t move(cube_t, uint8_t); 31STATIC cube_t move(cube_t, uint8_t);
@@ -31,6 +34,12 @@ STATIC uint8_t inverse_move(uint8_t);
31STATIC void sortparallel_moves(size_t, uint8_t*); 34STATIC void sortparallel_moves(size_t, uint8_t*);
32STATIC bool are_lastmoves_singlecw(size_t, const uint8_t*); 35STATIC bool are_lastmoves_singlecw(size_t, const uint8_t*);
33 36
37STATIC int64_t move_variations(const char *, const char *, size_t, char *);
38STATIC int64_t move_variations_lastqt(
39 const moves_struct_t [static 1], size_t, char *);
40STATIC 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(
160STATIC int64_t 169STATIC int64_t
161readmoves_struct(const char *moves, moves_struct_t ret[static 1]) 170readmoves_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
282STATIC int64_t
283writemoves_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
322writemoves_struct_error:
323 buf[w] = '\0';
324 return NISSY_ERROR_BUFFER_SIZE;
325}
326
273STATIC_INLINE bool 327STATIC_INLINE bool
274allowednextmove(uint8_t m1, uint8_t m2) 328allowednextmove(uint8_t m1, uint8_t m2)
275{ 329{
@@ -408,14 +462,12 @@ move(cube_t c, uint8_t m)
408} 462}
409 463
410STATIC uint8_t 464STATIC uint8_t
411transform_move(uint8_t m, uint8_t t) 465transform_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
486STATIC uint8_t
487transform_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 */
435STATIC cube_t 508STATIC cube_t
436premove(cube_t c, uint8_t m) 509premove(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
586STATIC int64_t
587move_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
613STATIC int64_t
614move_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
682lastqt_error:
683 LOG("[variations] Error writing result.\n");
684 return NISSY_ERROR_BUFFER_SIZE;
685}
686
687STATIC int64_t
688move_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
718unniss_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
151long long 151long long
152nissy_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
177long long
152nissy_getcube( 178nissy_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/*
103The value NISSY_ERROR_INVALID_VARIATION means that the given method of
104finding variations for a solution is not known.
105*/
106#define NISSY_ERROR_INVALID_VARIATION -51LL
107
108/*
102The value NISSY_ERROR_NULL_POINTER means that one of the provided pointer 109The value NISSY_ERROR_NULL_POINTER means that one of the provided pointer
103arguments is NULL. For example, it may be returned by solve when called 110arguments is NULL. For example, it may be returned by solve when called
104with a solver that requires some pre-computed data, but the provided 111with a solver that requires some pre-computed data, but the provided
@@ -205,6 +212,36 @@ nissy_applytrans(
205); 212);
206 213
207/* 214/*
215Find variations of a given move sequence, for example by changing
216the direction of the last quarter turn(s), or linearizing a NISS move
217sequence. The result consists of one or more move sequences, one per line,
218and it always ends in a newline character.
219
220Parameters:
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
227Return 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*/
236long long
237nissy_variations(
238 const char *moves,
239 const char *variation,
240 unsigned long long result_size,
241 char *result
242);
243
244/*
208Get the cube with the given ep, eo, cp and co values. The values must be in the 245Get the cube with the given ep, eo, cp and co values. The values must be in the
209ranges specified below, but if the option "fix" is given any values outside its 246ranges specified below, but if the option "fix" is given any values outside its
210range will be adjusted before using it. The option "fix" also fixes parity and 247range 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/*
405Count the given moves.
406
368Parameters: 407Parameters:
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/*
421Compare the two moves sequences. Both must be at most NISSY_SIZE_MOVES long.
422
382Parameters: 423Parameters:
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
3typedef struct { 3typedef 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
10typedef struct { 10typedef 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 @@
1unniss
2Uw2 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 @@
11
2Uw2 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 @@
1lastqt
2U2 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 @@
12
2U2 D L' F
3U2 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 @@
1lastqt
2U 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 @@
14
2U B2 L (F R)
3U B2 L (F R')
4U B2 L' (F R)
5U 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 @@
1lastqt
2U 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 @@
14
2U F B
3U F B'
4U F' B
5U 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 @@
1lastqt
2L2 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 @@
116
2L2 R U D (U D)
3L2 R U D (U D')
4L2 R U D (U' D)
5L2 R U D (U' D')
6L2 R U D' (U D)
7L2 R U D' (U D')
8L2 R U D' (U' D)
9L2 R U D' (U' D')
10L2 R U' D (U D)
11L2 R U' D (U D')
12L2 R U' D (U' D)
13L2 R U' D (U' D')
14L2 R U' D' (U D)
15L2 R U' D' (U D')
16L2 R U' D' (U' D)
17L2 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
3long long nissy_variations(
4 const char *, const char *, long long unsigned, char *);
5
6void 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}

Generated with cgit - Back to sebastiano.tronto.net