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

commit 992de12cc081e7dde16c3c231f83bfa77c67825a
parent e2b154c40acaac4e7a7b3e379ada0404519c3750
Author: Sebastiano Tronto <sebastiano@tronto.net>
Date:   Thu, 31 Jul 2025 09:47:57 +0200

Added move sequence comparison function

Diffstat:
Mbuild | 3++-
Mcpp/nissy.cpp | 14++++++++++++++
Mcpp/nissy.h | 10++++++++++
Mpython/nissy_module.c | 37+++++++++++++++++++++++++++++++++++++
Mshell/shell.c | 44++++++++++++++++++++++++++++++++++++++++++++
Msrc/core/core_types.h | 9+++++++++
Msrc/core/moves.h | 69++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
Msrc/nissy.c | 12++++++++++++
Msrc/nissy.h | 22++++++++++++++++++++++
Mtest/033_inverse_move/inverse_move_tests.c | 4++--
Mtest/062_transform_move/transform_move_tests.c | 4++--
Mtest/140_appendsolution/appendsolution_tests.c | 4++--
12 files changed, 222 insertions(+), 10 deletions(-)

diff --git a/build b/build @@ -282,7 +282,8 @@ build_cpp() { fi build_nissy || exit 1 - run $CXX $(odflags) -std=c++20 -o runcpp cpp/nissy.cpp nissy.o $@ + run $CXX $(odflags) -std=c++20 -o runcpp cpp/nissy.cpp nissy.o $@ \ + || exit 1 run ./runcpp } diff --git a/cpp/nissy.cpp b/cpp/nissy.cpp @@ -24,6 +24,7 @@ extern "C" { const unsigned char *, unsigned, char *, long long *, int (*)(void *), void *); long long nissy_countmoves(const char *); + long long nissy_comparemoves(const char *, const char *); long long nissy_setlogger(void (*)(const char *, void *), void *); } @@ -53,6 +54,9 @@ namespace nissy { const status status::STOP{1}; const status status::PAUSE{2}; + const compare_result compare_result::EQUAL{0}; + const compare_result compare_result::DIFFERENT{99}; + namespace size { constexpr size_t CUBE = 24; constexpr size_t TRANSFORMATION = 12; @@ -210,6 +214,16 @@ namespace nissy { return error{err}; } + std::variant<error, compare_result> + compare_moves(const std::string& m1, const std::string& m2) + { + auto cmp = nissy_comparemoves(m1.c_str(), m2.c_str()); + if (cmp < 0) + return error{cmp}; + else + return compare_result{cmp}; + } + void set_logger(void (*log)(const char *, void *), void *data) { nissy_setlogger(log, data); diff --git a/cpp/nissy.h b/cpp/nissy.h @@ -55,6 +55,14 @@ namespace nissy { static const status PAUSE; }; + class compare_result { + public: + long long value; + + static const compare_result EQUAL; + static const compare_result DIFFERENT; + }; + class cube { public: cube(); @@ -103,6 +111,8 @@ namespace nissy { }; error count_moves(const std::string&); + std::variant<error, compare_result> compare_moves( + const std::string&, const std::string&); void set_logger(void (*)(const char *, void *), void *); } diff --git a/python/nissy_module.c b/python/nissy_module.c @@ -345,6 +345,42 @@ countmoves(PyObject *self, PyObject *args) return long_result(count); } +PyDoc_STRVAR(comparemoves_doc, +"comparemoves(moves1, moves2)\n" +"--\n\n" +"Compare the two move sequences\n" +"\n" +"Parameters:\n" +" - moves1: the first sequence of moves\n" +" - moves2: the second sequence of moves\n" +"\n" +"Returns: a string describing how the two moves sequences compare. " +"This can be one of:\n" +"\"EQUAL\" - The two sequences are equal up to swapping parallel moves\n" +"\"DIFFERENT\" - The two sequences are different\n" +); +PyObject * +comparemoves(PyObject *self, PyObject *args) +{ + long long cmp; + const char *m1, *m2; + + if (!PyArg_ParseTuple(args, "ss", &m1, &m2)) + return NULL; + + if ((cmp = nissy_comparemoves(m1, m2)) < 0) + return long_result(cmp); + + switch (cmp) { + case NISSY_COMPARE_MOVES_EQUAL: + return string_result(cmp, "EQUAL"); + case NISSY_COMPARE_MOVES_DIFFERENT: + return string_result(cmp, "DIFFERENT"); + default: + return long_result(cmp); + } +} + static PyMethodDef nissy_methods[] = { { "inverse", inverse, METH_VARARGS, inverse_doc }, { "applymoves", applymoves, METH_VARARGS, applymoves_doc }, @@ -355,6 +391,7 @@ static PyMethodDef nissy_methods[] = { { "checkdata", checkdata, METH_VARARGS, checkdata_doc }, { "solve", solve, METH_VARARGS, solve_doc }, { "countmoves", countmoves, METH_VARARGS, countmoves_doc }, + { "comparemoves", comparemoves, METH_VARARGS, comparemoves_doc }, { NULL, NULL, 0, NULL } }; diff --git a/shell/shell.c b/shell/shell.c @@ -18,6 +18,7 @@ #define FLAG_COMMAND "-command" #define FLAG_STR_CUBE "-cubestr" #define FLAG_MOVES "-moves" +#define FLAG_MOVES2 "-moves2" #define FLAG_TRANS "-trans" #define FLAG_SOLVER "-solver" #define FLAG_NISSTYPE "-nisstype" @@ -39,6 +40,7 @@ typedef struct { char *str_command; char *str_cube; char *str_moves; + char *str_moves2; char *str_trans; char *str_solver; char *str_nisstype; @@ -59,6 +61,7 @@ static int64_t gendata_exec(args_t *); static int64_t solve_exec(args_t *); static int64_t solve_scramble_exec(args_t *); static int64_t countmoves_exec(args_t *); +static int64_t comparemoves_exec(args_t *); static int64_t help_exec(args_t *); static int parse_args(int, char **, args_t *); @@ -69,6 +72,7 @@ static bool set_cube(int, char **, args_t *); static bool set_str_command(int, char **, args_t *); static bool set_str_cube(int, char **, args_t *); static bool set_str_moves(int, char **, args_t *); +static bool set_str_moves2(int, char **, args_t *); static bool set_str_trans(int, char **, args_t *); static bool set_str_solver(int, char **, args_t *); static bool set_str_nisstype(int, char **, args_t *); @@ -91,6 +95,7 @@ struct { OPTION(FLAG_COMMAND, 1, set_str_command), OPTION(FLAG_STR_CUBE, 1, set_str_cube), OPTION(FLAG_MOVES, 1, set_str_moves), + OPTION(FLAG_MOVES2, 1, set_str_moves2), OPTION(FLAG_TRANS, 1, set_str_trans), OPTION(FLAG_SOLVER, 1, set_str_solver), OPTION(FLAG_NISSTYPE, 1, set_str_nisstype), @@ -185,6 +190,13 @@ struct { countmoves_exec ), COMMAND( + "compare", + "compare " FLAG_MOVES " MOVES " FLAG_MOVES2 " MOVES2", + "Compare the two move sequences." + INFO_MOVESFORMAT, + comparemoves_exec + ), + COMMAND( "help", "help [" FLAG_COMMAND " COMMAND]", "If no COMMAND is specified, prints some generic information " @@ -476,6 +488,29 @@ countmoves_exec(args_t *args) } static int64_t +comparemoves_exec(args_t *args) +{ + long long cmp; + + if ((cmp = nissy_comparemoves(args->str_moves, args->str_moves2)) < 0) + return cmp; + + switch (cmp) { + case NISSY_COMPARE_MOVES_EQUAL: + printf("The two move sequences are equal\n"); + break; + case NISSY_COMPARE_MOVES_DIFFERENT: + printf("The two move sequences are different\n"); + break; + default: + printf("Error: unknown case\n"); + return -1; + } + + return 0; +} + +static int64_t help_exec(args_t *args) { int i; @@ -512,6 +547,7 @@ parse_args(int argc, char **argv, args_t *args) .cube = "", .str_cube = "", .str_moves = "", + .str_moves2 = "", .str_trans = "", .str_solver = "", .str_nisstype = "", @@ -632,6 +668,14 @@ set_str_moves(int argc, char **argv, args_t *args) } static bool +set_str_moves2(int argc, char **argv, args_t *args) +{ + args->str_moves2 = argv[0]; + + return true; +} + +static bool set_str_trans(int argc, char **argv, args_t *args) { args->str_trans = argv[0]; diff --git a/src/core/core_types.h b/src/core/core_types.h @@ -1,4 +1,13 @@ +#define MOVES_STRUCT_MAXLEN 1000 + typedef struct { cube_t cube; uint8_t orientation; } oriented_cube_t; + +typedef struct { + size_t nnormal; + size_t ninverse; + uint8_t normal[MOVES_STRUCT_MAXLEN]; + uint8_t inverse[MOVES_STRUCT_MAXLEN]; +} moves_struct_t; diff --git a/src/core/moves.h b/src/core/moves.h @@ -3,8 +3,12 @@ STATIC uint8_t readmove(char); STATIC int64_t readmoves(const char *, - size_t, size_t, uint64_t *, uint64_t *, uint8_t *, uint8_t *); + size_t, size_t, size_t *, size_t *, uint8_t *, uint8_t *); +STATIC int64_t readmoves_struct(const char *, moves_struct_t [static 1]); STATIC int64_t countmoves(const char *); +STATIC bool moves_struct_equal( + const moves_struct_t [static 1], const moves_struct_t [static 1]); +STATIC long long comparemoves(const char *, const char *); STATIC uint8_t readmodifier(char); STATIC int64_t writemoves(size_t, const uint8_t *, size_t, char *); @@ -124,8 +128,8 @@ readmoves( const char *buf, size_t nsize, size_t invsize, - uint64_t *n, - uint64_t *i, + size_t *n, + size_t *i, uint8_t *normal, uint8_t *inverse ) @@ -154,6 +158,13 @@ readmoves( } STATIC int64_t +readmoves_struct(const char *moves, moves_struct_t ret[static 1]) +{ + return readmoves(moves, MOVES_STRUCT_MAXLEN, MOVES_STRUCT_MAXLEN, + &ret->nnormal, &ret->ninverse, ret->normal, ret->inverse); +} + +STATIC int64_t countmoves(const char *buf) { uint8_t m; @@ -168,6 +179,58 @@ countmoves(const char *buf) return count; } +STATIC bool +moves_struct_equal( + const moves_struct_t ms1[static 1], + const moves_struct_t ms2[static 1] +) +{ + size_t i; + + if (ms1->nnormal != ms2->nnormal || ms1->ninverse != ms2->ninverse) + return false; + + for (i = 0; i < ms1->nnormal; i++) + if (ms1->normal[i] != ms2->normal[i]) + return false; + + for (i = 0; i < ms1->ninverse; i++) + if (ms1->inverse[i] != ms2->inverse[i]) + return false; + + return true; +} + +STATIC long long +comparemoves(const char *moves1, const char *moves2) +{ + int64_t err; + moves_struct_t ms1, ms2; + + if ((err = readmoves_struct(moves1, &ms1)) < 0) + return err; + sortparallel_moves(ms1.nnormal, ms1.normal); + sortparallel_moves(ms1.ninverse, ms1.inverse); + + if ((err = readmoves_struct(moves2, &ms2)) < 0) + return err; + sortparallel_moves(ms2.nnormal, ms2.normal); + sortparallel_moves(ms2.ninverse, ms2.inverse); + + if (moves_struct_equal(&ms1, &ms2)) + return NISSY_COMPARE_MOVES_EQUAL; + + /* + TODO: more types of move comparison + - up to moving rotations around + - up to rotation + - up transformation (including mirror or not including it) + - ... + */ + + return NISSY_COMPARE_MOVES_DIFFERENT; +} + STATIC int64_t writemoves( size_t nmoves, diff --git a/src/nissy.c b/src/nissy.c @@ -354,6 +354,18 @@ nissy_countmoves( } long long +nissy_comparemoves( + const char *moves1, + const char *moves2 +) +{ + if (moves1 == NULL || moves2 == NULL) + return NISSY_ERROR_NULL_POINTER; + + return comparemoves(moves1, moves2); +} + +long long nissy_setlogger( void (*log)(const char *, void *), void *user_data diff --git a/src/nissy.h b/src/nissy.h @@ -42,6 +42,10 @@ for example 'rotation UF' or 'mirrored BL'. #define NISSY_STATUS_STOP 1 #define NISSY_STATUS_PAUSE 2 +/* Possible results of move sequence comparison */ +#define NISSY_COMPARE_MOVES_EQUAL 0 +#define NISSY_COMPARE_MOVES_DIFFERENT 99 + /* The solved cube */ #define NISSY_SOLVED_CUBE "ABCDEFGH=ABCDEFGHIJKL=A" @@ -375,6 +379,24 @@ nissy_countmoves( ); /* +Parameters: + moves1 - The first sequence of moves to compare. + moves2 - The second sequence of moves to compare. + +Return values: + NISSY_ERROR_INVALID_MOVES - One of the given moves sequences is invalid. + NISSY_ERROR_NULL_POINTER - One of the arguments is NULL. + NISSY_COMPARE_MOVES_EQUAL - The two moves sequences are indentical, up + to swapping parallel moves. + NISSY_COMPARE_MOVES_DIFFERENT - The two moves sequences are different. +*/ +long long +nissy_comparemoves( + const char *moves1, + const char *moves2 +); + +/* Set a global logger function used by this library. Setting the logger to NULL disables logging. diff --git a/test/033_inverse_move/inverse_move_tests.c b/test/033_inverse_move/inverse_move_tests.c @@ -3,11 +3,11 @@ extern char *movestr[]; int64_t readmoves(const char *, size_t n, size_t m, - uint64_t *, uint64_t *, uint8_t [n], uint8_t [m]); + size_t *, size_t *, uint8_t [n], uint8_t [m]); uint8_t inverse_move(uint8_t); void run(void) { - uint64_t inv, nor; + size_t inv, nor; int64_t tot; uint8_t moves[2]; diff --git a/test/062_transform_move/transform_move_tests.c b/test/062_transform_move/transform_move_tests.c @@ -5,7 +5,7 @@ cube_t applytrans(cube_t, const char *); uint8_t transform_move(uint8_t, uint8_t); int64_t readmoves(const char *, size_t n, size_t m, - uint64_t *, uint64_t *, uint8_t [n], uint8_t [m]); + size_t *, size_t *, uint8_t [n], uint8_t [m]); oriented_cube_t move_extended(oriented_cube_t, uint8_t); oriented_cube_t applymoves(oriented_cube_t, const char *); uint8_t readtrans(const char[static NISSY_SIZE_TRANSFORMATION]); @@ -13,7 +13,7 @@ uint8_t readtrans(const char[static NISSY_SIZE_TRANSFORMATION]); void run(void) { char movestr[STRLENMAX], transtr[STRLENMAX], cubestr[STRLENMAX]; uint8_t t, moves[MAXMOVES]; - uint64_t i, n, ninv; + size_t i, n, ninv; int64_t tot; oriented_cube_t cube; diff --git a/test/140_appendsolution/appendsolution_tests.c b/test/140_appendsolution/appendsolution_tests.c @@ -14,7 +14,7 @@ See below for the output format. uint8_t readtrans(const char [NISSY_SIZE_TRANSFORMATION]); int64_t readmoves(const char *, size_t n, size_t m, - uint64_t *, uint64_t *, uint8_t [n], uint8_t [m]); + size_t *, size_t *, uint8_t [n], uint8_t [m]); void solution_moves_reset(solution_moves_t [static 1]); bool solution_list_init(solution_list_t [static 1], size_t n, char [n]); int64_t appendsolution(const solution_moves_t [static 1], @@ -23,7 +23,7 @@ int64_t appendsolution(const solution_moves_t [static 1], void run(void) { int i, ntrans; int64_t tot; - uint64_t nm, np; + size_t nm, np; char str[STRLENMAX], buf[STRLENMAX]; solution_moves_t moves; solution_settings_t settings;