h48

A prototype for an optimal Rubik's cube solver, work in progress.
git clone https://git.tronto.net/h48
Download | Log | Files | Refs | README | LICENSE

commit 79c9c600f7a620e3e804ff7783511ad7da7d8f93
parent 5e291466fbbc45aed74f67a1b2e555d1f0c44d8f
Author: Sebastiano Tronto <sebastiano@tronto.net>
Date:   Fri, 11 Oct 2024 12:04:02 +0200

Error codes, documentation, change nisstype from string to flags

Diffstat:
Mshell.c | 25++++++++++++++-----------
Msrc/nissy.c | 300+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------
Msrc/nissy.h | 229+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------
3 files changed, 460 insertions(+), 94 deletions(-)

diff --git a/shell.c b/shell.c @@ -49,7 +49,7 @@ typedef struct { char *str_moves; char *str_trans; char *str_solver; - char *str_nisstype; /* TODO: remove, use flags */ + char *str_nisstype; int8_t minmoves; int8_t maxmoves; int8_t optimal; @@ -108,7 +108,7 @@ struct { OPTION(FLAG_MOVES, 1, set_str_moves), OPTION(FLAG_TRANS, 1, set_str_trans), OPTION(FLAG_SOLVER, 1, set_str_solver), - OPTION(FLAG_NISSTYPE, 1, set_str_nisstype), /* TODO: remove, use flags */ + OPTION(FLAG_NISSTYPE, 1, set_str_nisstype), /* TODO: more args ? */ OPTION(FLAG_MINMOVES, 1, set_minmoves), OPTION(FLAG_MAXMOVES, 1, set_maxmoves), OPTION(FLAG_OPTIMAL, 1, set_optimal), @@ -244,7 +244,7 @@ compose_exec(args_t *args) int64_t ret; ret = nissy_compose(args->cube, args->cube_perm, result); - if (ret == 0) + if (ret == NISSY_OK || ret == NISSY_WARNING_UNSOLVABLE) printf("%s\n", result); return ret; @@ -257,7 +257,7 @@ inverse_exec(args_t *args) int64_t ret; ret = nissy_inverse(args->cube, result); - if (ret == 0) + if (ret == NISSY_OK || ret == NISSY_WARNING_UNSOLVABLE) printf("%s\n", result); return ret; @@ -270,7 +270,7 @@ applymoves_exec(args_t *args) int64_t ret; ret = nissy_applymoves(args->cube, args->str_moves, result); - if (ret == 0) + if (ret == NISSY_OK || ret == NISSY_WARNING_UNSOLVABLE) printf("%s\n", result); return ret; @@ -283,7 +283,7 @@ applytrans_exec(args_t *args) int64_t ret; ret = nissy_applytrans(args->cube, args->str_trans, result); - if (ret == 0) + if (ret == NISSY_OK || ret == NISSY_WARNING_UNSOLVABLE) printf("%s\n", result); return ret; @@ -296,7 +296,7 @@ frommoves_exec(args_t *args) int64_t ret; ret = nissy_frommoves(args->str_moves, result); - if (ret == 0) + if (ret == NISSY_OK || ret == NISSY_WARNING_UNSOLVABLE) printf("%s\n", result); return ret; @@ -310,7 +310,7 @@ convert_exec(args_t *args) ret = nissy_convert( args->str_format_in, args->str_format_out, args->str_cube, result); - if (ret == 0) + if (ret == NISSY_OK || ret == NISSY_WARNING_UNSOLVABLE) printf("%s\n", result); return ret; @@ -327,7 +327,7 @@ randomcube_exec(args_t *args) cp = rand64(); co = rand64(); ret = nissy_getcube(ep, eo, cp, co, "fix", result); - if (ret == 0) + if (ret == NISSY_OK || ret == NISSY_WARNING_UNSOLVABLE) printf("%s\n", result); return ret; @@ -418,11 +418,14 @@ static int64_t solve_exec(args_t *args) { int i; + uint8_t nissflag; FILE *file; char *buf, solutions[SOLUTIONS_BUFFER_SIZE], path[MAX_PATH_LENGTH]; int64_t ret, gendata_ret, size; size_t read; + nissflag = NISSY_NISSFLAG_NORMAL; /* TODO: parse str_nisstype */ + for (i = 0; tablepaths[i] != NULL; i++) { strcpy(path, tablepaths[i]); strcat(path, args->str_solver); @@ -469,12 +472,12 @@ solve_exec(args_t *args) } ret = nissy_solve( - args->cube, args->str_solver, args->str_nisstype, args->minmoves, + args->cube, args->str_solver, nissflag, args->minmoves, args->maxmoves, args->maxsolutions, args->optimal, buf, solutions); free(buf); - if (ret == 0) + if (ret == NISSY_OK || ret == NISSY_WARNING_UNSOLVABLE) fprintf(stderr, "No solutions found\n"); else printf("%s", solutions); diff --git a/src/nissy.c b/src/nissy.c @@ -109,20 +109,14 @@ distribution_equal( STATIC int64_t write_result(cube_t cube, char result[static 22]) { - if (!isconsistent(cube)) { - LOG("Error: resulting cube is invalid\n"); - writecube("B32", ZERO_CUBE, result); - return 8; - } - writecube("B32", cube, result); if (!issolvable(cube)) { LOG("Warning: resulting cube is not solvable\n"); - return 9; + return NISSY_WARNING_UNSOLVABLE; } - return 0; + return NISSY_OK; } int64_t @@ -133,24 +127,37 @@ nissy_compose( ) { cube_t c, p, res; + int64_t err; c = readcube("B32", cube); if (!isconsistent(c)) { LOG("Error in nissy_compose: given cube is invalid\n"); - return 1; + err = NISSY_ERROR_INVALID_CUBE; + goto nissy_compose_error; } p = readcube("B32", permutation); if (!isconsistent(p)) { LOG("Error in nissy_compose: given permutation is invalid\n"); - return 2; + err = NISSY_ERROR_INVALID_CUBE; + goto nissy_compose_error; } res = compose(c, p); + if (!isconsistent(res)) { + LOG("Unknown error: resulting cube is invalid\n"); + err = NISSY_ERROR_UNKNOWN; + goto nissy_compose_error; + } + return write_result(res, result); + +nissy_compose_error: + writecube("B32", ZERO_CUBE, result); + return err; } int64_t @@ -160,17 +167,29 @@ nissy_inverse( ) { cube_t c, res; + int64_t err; c = readcube("B32", cube); if (iserror(c)) { LOG("Error in nissy_inverse: given cube is invalid\n"); - return 1; + err = NISSY_ERROR_INVALID_CUBE; + goto nissy_inverse_error; } res = inverse(c); + if (!isconsistent(res)) { + LOG("Unknown error: inverted cube is invalid\n"); + err = NISSY_ERROR_UNKNOWN; + goto nissy_inverse_error; + } + return write_result(res, result); + +nissy_inverse_error: + writecube("B32", ZERO_CUBE, result); + return err; } int64_t @@ -181,17 +200,29 @@ nissy_applymoves( ) { cube_t c, res; + int64_t err; c = readcube("B32", cube); if (!isconsistent(c)) { LOG("Error in nissy_applymoves: given cube is invalid\n"); - return 1; + err = NISSY_ERROR_INVALID_CUBE; + goto nissy_applymoves_error; } res = applymoves(c, moves); + if (!isconsistent(res)) { + /* Assume we got a reasonable error message from applymoves */ + err = NISSY_ERROR_INVALID_MOVES; + goto nissy_applymoves_error; + } + return write_result(res, result); + +nissy_applymoves_error: + writecube("B32", ZERO_CUBE, result); + return err; } int64_t @@ -202,17 +233,29 @@ nissy_applytrans( ) { cube_t c, res; + int64_t err; c = readcube("B32", cube); if (!isconsistent(c)) { LOG("Error in nissy_applytrans: given cube is invalid\n"); - return 1; + err = NISSY_ERROR_INVALID_CUBE; + goto nissy_applytrans_error; } res = applytrans(c, transformation); + if (!isconsistent(res)) { + /* Assume we got a reasonable error message from applytrans */ + err = NISSY_ERROR_INVALID_TRANS; + goto nissy_applytrans_error; + } + return write_result(res, result); + +nissy_applytrans_error: + writecube("B32", ZERO_CUBE, result); + return err; } int64_t @@ -222,15 +265,21 @@ nissy_frommoves( ) { cube_t res; + int64_t err; res = applymoves(SOLVED_CUBE, moves); if (!isconsistent(res)) { - /* Moves must be invalid */ - return 1; + /* Assume we got a reasonable error message from applymoves */ + err = NISSY_ERROR_INVALID_MOVES; + goto nissy_frommoves_error; } return write_result(res, result); + +nissy_frommoves_error: + writecube("B32", ZERO_CUBE, result); + return err; } int64_t @@ -241,20 +290,35 @@ nissy_convert( char *result ) { - int ret; cube_t c; + int ret; + int64_t err; c = readcube(format_in, cube_string); - if (iserror(c)) - return 1; + if (iserror(c)) { + err = NISSY_ERROR_INVALID_CUBE; + goto nissy_convert_error; + } ret = writecube(format_out, c, result); - if (ret != 0) - return 2; + if (ret != 0) { + /* Assume the format was invalid */ + err = NISSY_ERROR_INVALID_FORMAT; + goto nissy_convert_error; + } + + if (!isconsistent(c)) { + err = NISSY_ERROR_UNKNOWN; + goto nissy_convert_error; + } - return isconsistent(c) ? 0 : 3; + return NISSY_OK; + +nissy_convert_error: + /* We don't write anything to result, we don't know the format */ + return err; } int64_t @@ -276,6 +340,13 @@ nissy_getcube( c = getcube(ep, eo, cp, co); + if (!isconsistent(c)) { + LOG("Error: could not get cube with ep=%" PRId64 ", eo=%" + PRId64 ", cp=%" PRId64 ", co=%" PRId64 ".\n", + ep, eo, cp, co); + return NISSY_ERROR_OPTIONS; + } + return write_result(c, result); } @@ -290,14 +361,14 @@ nissy_datasize( int64_t nissy_datainfo( - const void *table, + const void *data, void (*write)(const char *, ...) ) { uint8_t i; tableinfo_t info; - readtableinfo(table, &info); + readtableinfo(data, &info); write("\n---------\n\n"); write("Table information for '%s'\n", info.solver); @@ -321,16 +392,15 @@ nissy_datainfo( break; default: LOG("datainfo: unknown table type\n"); - return 1; + return NISSY_ERROR_DATA; } - if (info.next != 0) { - return nissy_datainfo((char *)table + info.next, write); - } + if (info.next != 0) + return nissy_datainfo((char *)data + info.next, write); write("\n---------\n"); - return 0; + return NISSY_OK; } int64_t @@ -340,20 +410,19 @@ nissy_gendata( ) { int p; - int64_t ret; gendata_h48_arg_t arg; arg.buf = data; if (!strncmp(solver, "h48", 3)) { p = parse_h48_solver(solver, &arg.h, &arg.k); arg.maxdepth = 20; - ret = p == 0 ? (int64_t)gendata_h48(&arg) : -1; + if (p != 0) + return NISSY_ERROR_UNKNOWN; + return (int64_t)gendata_h48(&arg); } else { LOG("gendata: unknown solver %s\n", solver); - ret = -1; + return NISSY_ERROR_INVALID_SOLVER; } - - return ret; } int64_t @@ -369,20 +438,20 @@ nissy_checkdata( if (!checkdata(buf, &info)) { LOG("Error: data for %s is inconsistent with info!\n", info.solver); - return 1; + return NISSY_ERROR_DATA; } if (info.next == 0) break; } - return 0; + return NISSY_OK; } int64_t nissy_solve( const char cube[static 22], const char *solver, - const char *nisstype, + uint8_t nissflag, int8_t minmoves, int8_t maxmoves, int64_t maxsolutions, @@ -397,9 +466,14 @@ nissy_solve( c = readcube_B32(cube); + if (!isconsistent(c)) { + LOG("solve: cube is invalid\n"); + return NISSY_ERROR_INVALID_CUBE; + } + if (!issolvable(c)) { LOG("solve: cube is not solvable\n"); - return -1; + return NISSY_ERROR_UNSOLVABLE_CUBE; } if (minmoves < 0) { @@ -414,7 +488,7 @@ nissy_solve( if (maxsolutions < 0) { LOG("solve: 'maxsols' is negative, stopping\n"); - return -1; + return NISSY_ERROR_OPTIONS; } if (maxsolutions == 0) { @@ -424,7 +498,7 @@ nissy_solve( if (solutions == NULL) { LOG("solve: return parameter 'solutions' is NULL, stopping\n"); - return -1; + return NISSY_ERROR_NULL_POINTER; } if (!strncmp(solver, "h48", 3)) { @@ -433,7 +507,8 @@ nissy_solve( p = parse_h48_solver(solver, &h, &k); if (p != 0) { - return -1; + LOG("solve: unknown solver %s\n", solver); + return NISSY_ERROR_INVALID_SOLVER; } else { return THREADS > 1 ? solve_h48_multithread(c, minmoves, @@ -446,12 +521,151 @@ nissy_solve( c, minmoves, maxmoves, maxsolutions, optimal, solutions); } else { LOG("solve: unknown solver '%s'\n", solver); - return -1; + return NISSY_ERROR_INVALID_SOLVER; } } -void -nissy_setlogger(void (*log)(const char *, ...)) +int64_t +nissy_setlogger( + void (*log)(const char *, ...) +) { nissy_log = log; + + if (log == NULL) + return NISSY_WARNING_NULL_CALLBACK; + + return NISSY_OK; +} + +int64_t +nissy_explainerror( + int64_t error_code, + void (*write)(const char *, ...) +) +{ + if (write == NULL) + return NISSY_WARNING_NULL_CALLBACK; + + switch (error_code) { + case NISSY_OK: + write( + "The value %" PRId64 " denotes a success.\n" + "If returned by solve, it means that no solutions has " + "been found.\n", NISSY_OK + ); + return NISSY_OK; + case NISSY_WARNING_UNSOLVABLE: + write( + "The value %" PRId64 " is a warning. It means that the " + "operation was completed succesfully, but the resulting " + "cube is in an unsolvable state. This could be intended, " + "for example if the user has provided an unsolvable cube " + "as input.\n", NISSY_WARNING_UNSOLVABLE + ); + return NISSY_OK; + case NISSY_WARNING_NULL_CALLBACK: + write( + "The value %" PRId64 " is a warning. It means that the " + "provided pointer to a writer function is NULL.\n" + "If returned by nissy_setlogger, it means that any future " + "log messages will not be printed.\n", + NISSY_WARNING_NULL_CALLBACK + ); + return NISSY_OK; + case NISSY_ERROR_INVALID_CUBE: + write( + "The value %" PRId64 " means that the provided cube is " + "invalid. It could be written in an unknown format, or " + "in a format different from what specified, or simply " + "ill-formed.\n", NISSY_ERROR_INVALID_CUBE + ); + return NISSY_OK; + case NISSY_ERROR_UNSOLVABLE_CUBE: + write( + "The value %" PRId64 " means that the provided cube is " + "in an unsolvable state.\n", NISSY_ERROR_INVALID_CUBE + ); + return NISSY_OK; + case NISSY_ERROR_INVALID_MOVES: + write( + "The value %" PRId64 " means that the given moves are " + "invalid.\n", NISSY_ERROR_INVALID_MOVES + ); + return NISSY_OK; + case NISSY_ERROR_INVALID_TRANS: + write( + "The value %" PRId64 " means that the given transformation " + "is invalid.\n", NISSY_ERROR_INVALID_TRANS + ); + return NISSY_OK; + case NISSY_ERROR_INVALID_FORMAT: + write( + "The value %" PRId64 " means that the given format is not " + "known.\n", NISSY_ERROR_INVALID_FORMAT + ); + return NISSY_OK; + case NISSY_ERROR_INVALID_SOLVER: + write( + "The value %" PRId64 " means that the given solver is not " + "known.\n", NISSY_ERROR_INVALID_SOLVER + ); + return NISSY_OK; + case NISSY_ERROR_NULL_POINTER: + write( + "The value %" PRId64 " means that one of the provided " + "pointer arguments is NULL. For example, it may be " + "returned by solve when called with a solver that " + "requires some pre-computed data, but the provided data " + "is NULL.\n", NISSY_ERROR_NULL_POINTER + ); + return NISSY_OK; + case NISSY_ERROR_DATA: + write( + "The value %" PRId64 " means that the provided data is " + "invalid. For example, it may be returned by solve when " + "called with incompatible solver and data arguments.\n", + NISSY_ERROR_DATA + ); + return NISSY_OK; + case NISSY_ERROR_OPTIONS: + write( + "The value %" PRId64 " means that one or more of the " + "given options are invalid. For example, it may be " + "returned by solve when called with a negative maximum " + "number of solutions.\n", NISSY_ERROR_OPTIONS + ); + return NISSY_OK; + case NISSY_ERROR_INVALID_CODE: + write( + "The value %" PRId64 " means that the given error code " + "is not known. It may be returned by explainerror.\n", + NISSY_ERROR_INVALID_CODE + ); + return NISSY_OK; + case NISSY_ERROR_UNKNOWN: + write( + "The value %" PRId64 " denotes an unexpected error. It " + "probably means that there some bug in this library.\n" + "If you can, report any error of this kind to " + "sebastiano@tronto.net. Thanks!\n", NISSY_ERROR_UNKNOWN + ); + return NISSY_OK; + default: + break; + } + + if (error_code > 0) { + write( + "A positive return values does not denote an error\n" + "If returned by gendata or datasize, it denotes the size " + "of the data, in bytes\n" + "If returned by solve, it denotes the number of solutions " + "found.\n" + ); + return NISSY_OK; + } else { + write("Unknown error code %" PRId64 "\n", error_code); + return NISSY_ERROR_INVALID_CODE; + } } diff --git a/src/nissy.h b/src/nissy.h @@ -8,10 +8,9 @@ If you include this file, you should also use the following includes: #include <stdbool> #include <string> -All the functions below return 0 in case of success and a positive number -in case of error, unless otherwise specified. Errors are checked in code -order: for example if error code 1 is returned then it could that also -an error with code 2 or higher occurred. +All the functions return 0 or a positive integer in case of success and +a negative integer in case of error, unless otherwise specified. +You can see the list of error codes below, or use nissy_explainerror(). Arguments of type char [static 22] denote a cube in B32 format. Other available formats are H48 and SRC. See README.md for more info on @@ -25,14 +24,48 @@ A transformation must be given in the format for example 'rotation UF' or 'mirrored BL'. */ +/* Error codes */ +#define NISSY_OK INT64_C(0) +#define NISSY_WARNING_UNSOLVABLE INT64_C(-1) +#define NISSY_WARNING_NULL_CALLBACK INT64_C(-2) +#define NISSY_ERROR_INVALID_CUBE INT64_C(-10) +#define NISSY_ERROR_UNSOLVABLE_CUBE INT64_C(-11) +#define NISSY_ERROR_INVALID_MOVES INT64_C(-20) +#define NISSY_ERROR_INVALID_TRANS INT64_C(-30) +#define NISSY_ERROR_INVALID_FORMAT INT64_C(-40) +#define NISSY_ERROR_INVALID_SOLVER INT64_C(-50) +#define NISSY_ERROR_NULL_POINTER INT64_C(-60) +#define NISSY_ERROR_DATA INT64_C(-70) +#define NISSY_ERROR_OPTIONS INT64_C(-80) +#define NISSY_ERROR_INVALID_CODE INT64_C(-90) +#define NISSY_ERROR_UNKNOWN INT64_C(-999) + +/* Flags for NISS options */ +#define NISSY_NISSFLAG_NORMAL UINT8_C(1) +#define NISSY_NISSFLAG_INVERSE UINT8_C(2) +#define NISSY_NISSFLAG_MIXED UINT8_C(4) +#define NISSY_NISSFLAG_LINEAR \ + (NISSY_NISSFLAG_NORMAL | NISSY_NISSFLAG_INVERSE) +#define NISSY_NISSFLAG_ALL \ + (NISSY_NISSFLAG_NORMAL | NISSY_NISSFLAG_INVERSE | NISSY_NISSFLAG_MIXED) + /* Apply the secod argument as a permutation on the first argument. +Parameters: + cube - The first cube, in B32 format. + permutation - The second cube, in B32 format. This cube is treated as a + permutation and "applied" to the first cube. + result - The return parameter for the resulting cube, in B32 format. + Return values: - 0 Valid result - 1 The given cube is invalid - 2 The given permutation is invalid - 9 The resulting cube is not solvable + NISSY_OK - The cubes were composed succesfully. + NISSY_WARNING_UNSOLVABLE - The resulting cube is not solvable. This is + either because at least on of the given cubes + was not solvable, or due to an unknown internal + error. + NISSY_ERROR_INVALID_CUBE - At least one of the given cubes is invalid. + NISSY_ERROR_UNKNOWN - An unknown error occurred. */ int64_t nissy_compose( const char cube[static 22], @@ -43,10 +76,17 @@ int64_t nissy_compose( /* Compute the inverse of the given cube. +Parameters: + cube - The cube to be inverted, in B32 format. + result - The return parameter for the resulting cube, in B32 format. + Return values: - 0 Valid result - 1 The given cube is invalid - 9 The resulting cube is not solvable + NISSY_OK - The cube was inverted succesfully. + NISSY_WARNING_UNSOLVABLE - The resulting cube is not solvable. This is + either because the given cube was not solvable, + or due to an unknown internal error. + NISSY_ERROR_INVALID_CUBE - The given cube is invalid. + NISSY_ERROR_UNKNOWN - An unknown error occurred. */ int64_t nissy_inverse( const char cube[static 22], @@ -56,11 +96,18 @@ int64_t nissy_inverse( /* Apply the given sequence of moves on the given cube. +Parameters: + cube - The cube to move, in B32 format. + moves - The moves to apply to the cube. + result - The return parameter for the resulting cube, in B32 format. + Return values: - 0 Valid result - 1 The given cube is invalid - 8 The given moves are invalid - 9 The resulting cube is not solvable + NISSY_OK - The moves were applied succesfully. + NISSY_WARNING_UNSOLVABLE - The resulting cube is not solvable. This is + either because the given cube was not solvable, + or due to an unknown internal error. + NISSY_ERROR_INVALID_CUBE - The given cube is invalid. + NISSY_ERROR_INVALID_MOVES - The given moves are invalid. */ int64_t nissy_applymoves( const char cube[static 22], @@ -71,11 +118,17 @@ int64_t nissy_applymoves( /* Apply the single given transformation to the given cube. +Parameters: + cube - The cube to be transformed, in B32 format. + transformation - The transformation in (rotation|mirrored) xy format. + result - The return parameter for the resulting cube, in B32 format. + Return values: - 0 Valid result - 1 The given cube is invalid - 8 The given transformation is invalid - 9 The resulting cube is not solvable + NISSY_OK - The transformation was performed succesfully. + NISSY_WARNING_UNSOLVABLE - The resulting cube is not solvable. This is + probably due to an unknown internal error. + NISSY_ERROR_INVALID_CUBE - The given cube is invalid. + NISSY_ERROR_INVALID_TRANS - The given transformation is invalid. */ int64_t nissy_applytrans( const char cube[static 22], @@ -86,9 +139,15 @@ int64_t nissy_applytrans( /* Apply the given moves to the solved cube. +Parameters: + moves - The moves to be applied to the solved cube. + result - Return parameter for the resulting cube, in B32 format. + Return values: - 0 Valid result - 1 The given moves are invalid + NISSY_OK - The moves were performed succesfully. + NISSY_WARNING_UNSOLVABLE - The resulting cube is not solvable. This is + probably due to an unknown internal error. + NISSY_ERROR_INVALID_MOVES - The given moves are invalid. */ int64_t nissy_frommoves( const char *moves, @@ -98,20 +157,45 @@ int64_t nissy_frommoves( /* Convert the given cube between the two given formats. +Parameters: + format_in - The input format. + format_out - The output format. + string - The cube, in format_in format. + result - Return parameter for the cube in format_out format. Must be + large enough to contains the cube in this format. + Return values: - 0 Valid result - 1 The given cube or format_in is invalid - 2 The resulting cube or format_out is invalid - 3 The resulting cube is inconsistent + NISSY_OK - The conversion was performed succesfully. + NISSY_ERROR_INVALID_CUBE - The given cube is invalid. + NISSY_ERROR_INVALID_FORMAT - At least one of the given formats is invalid. + NISSY_ERROR_UNKNOWN - An unknown error occurred. */ int64_t nissy_convert( const char *format_in, const char *format_out, - const char *cube_string, + const char *cube, char *result ); -/* Get the cube with the given ep, eo, cp and co values. */ +/* +Get the cube with the given ep, eo, cp and co values. The values must be in the +ranges specified below, but if the option "fix" is given any values outside its +range will be adjusted before using it. The option "fix" also fixes parity and +orientation issues, resulting always in a solvable cube. + +Parameters: + ep - The edge permutation, 0 <= ep <= 479001600 (12!) + eo - The edge orientation, 0 <= eo <= 2047 (2^11) + cp - The corner permutation, 0 <= cp <= 40320 (8!) + co - The corner orientation, 0 <= co <= 2187 (3^7) + options - Other options. + result - The return parameter for the resulting cube, in B32 format. + +Return values: + NISSY_OK - The cube was generated succesfully. + NISSY_WARNING_UNSOLVABLE - The resulting cube is unsolvable. + NISSY_ERROR_OPTIONS - One or more of the given parameters is invalid. +*/ int64_t nissy_getcube( int64_t ep, int64_t eo, @@ -125,9 +209,13 @@ int64_t nissy_getcube( Compute the size of the data generated by nissy_gendata, when called with the same parameters, or -1 in case of error. +Parameters: + solver - The name of the solver. + Return values: - -1 Error - >=0 The size of the table, in bytes + NISSY_ERROR_INVALID_SOLVER - The given solver is not known. + NISSY_ERROR_UNKNOWN - An unknown error occurred. + Any value >= 0 - The size of the data, in bytes. */ int64_t nissy_datasize( const char *solver @@ -136,38 +224,71 @@ int64_t nissy_datasize( /* Compute the data for the given solver and store it in generated_data. +Parameters: + solver - The name of the solver. + data - The return parameter for the generated data. Must be large enoguh + to contain the whole data. It is advised to use nissy_datasize to + check how much memory is needed. + Return values: - -1 Error - >=0 The size of the table, in bytes + NISSY_ERROR_INVALID_SOLVER - The given solver is not known. + NISSY_ERROR_UNKNOWN - An error occurred while generating the data. + Any value >= 0 - The size of the data, in bytes. */ int64_t nissy_gendata( const char *solver, - void *generated_data + void *data ); /* Print information on a data table via the provided callback writer. +Parameters: + data - The data + write - A callback writer with the same signature as printf(3). + Return values: - 0 No error - 1 The given data could not be read correctly + NISSY_OK - The data is correct. + NISSY_ERROR_DATA - The data contains errors. */ int64_t nissy_datainfo( - const void *table, + const void *data, void (*write)(const char *, ...) ); /* -Solve the given cube using the given solver and options +Solve the given cube using the given solver and options. + +Parameters: + cube - The cube to solver, in B32 format. + solver - The name of the solver. + nissflag - The flags for NISS (linear, inverse, mixed, or combinations). + minmoves - The minimum number of moves for a solution. + maxmoves - The maximum number of moves for a solution. + maxsolutions - The maximum number of solutions. + optimal - If set to a non-negative value, the maximum number of moves + above the optimal solution length. + data - The data for the solver. Can be computed with gendata. + solutions - The return parameter for the solutions. Must be large enough + to store all found solutions. The solutions are separated by + a '\n' (newline) and a '\0' (NULL character) terminates the + list. + TODO: replace with callback writer. Return values: - -1 Error - >=0 The number of solutions found + NISSY_OK - Cube solved succesfully. + NISSY_ERROR_INVALID_CUBE - The given cube is invalid. + NISSY_ERROR_UNSOLVABLE_CUBE - The given cube is valid, but not solvable with + the given solver. + NISSY_ERROR_OPTIONS - One or more of the given options are invalid. + NISSY_ERROR_NULL_POINTER - One of the provided pointers is null. + NISSY_ERROR_INVALID_SOLVER - The given solver is not known. + Any value >= 0 - The number of solutions found. */ int64_t nissy_solve( const char cube[static 22], const char *solver, - const char *nisstype, /* TODO: remove, use flags */ + uint8_t nissflag, int8_t minmoves, int8_t maxmoves, int64_t maxsolutions, @@ -178,5 +299,33 @@ int64_t nissy_solve( /* Set a global logger function used by this library. + +Parameters: + write - A callback writer with the same signature as printf(3). + +Return values: + NISSY_OK - Logger set succesfully. + NISSY_WARNING_NULL_CALLBACK - The provided callback writer is NULL. */ -void nissy_setlogger(void (*logger_function)(const char *, ...)); +int64_t nissy_setlogger( + void (*logger_function)(const char *, ...) +); + +/* +Print an explanation of the given error code via the provided callback writer. + +Parameters: + error_code - The error code to be explained. It can be any value returned + by a function in this library, not necessarily an error. + write - A callback writer with the same signature as printf(3). + Must be non-NULL. + +Return values: + NISSY_OK - The error code is known. + NISSY_WARNING_NULL_CALLBACK - The provided callback writer is NULL. + NISSY_ERROR_INVALID_CODE - The error code is unknown. +*/ +int64_t nissy_explainerror( + int64_t error_code, + void (*write)(const char *, ...) +);