commit 5e291466fbbc45aed74f67a1b2e555d1f0c44d8f
parent d4fadc24ee1993104bac7fd854ed6ca83f60ee66
Author: Sebastiano Tronto <sebastiano@tronto.net>
Date: Thu, 10 Oct 2024 19:49:48 +0200
Improved error messages and add some comments in nissy.h
Diffstat:
9 files changed, 228 insertions(+), 119 deletions(-)
diff --git a/shell.c b/shell.c
@@ -56,9 +56,6 @@ typedef struct {
int64_t maxsolutions;
} args_t;
-static void print_cube_result(int64_t, char [static 22]);
-static void print_str_result(int64_t, char *);
-
static int64_t compose_exec(args_t *);
static int64_t inverse_exec(args_t *);
static int64_t applymoves_exec(args_t *);
@@ -240,36 +237,6 @@ rand64(void)
return ret;
}
-static void
-print_cube_result(int64_t ret, char result[static 22])
-{
- switch (ret) {
- case 0:
- break;
- case 1:
- fprintf(stderr, "Warning: resulting cube not solvable\n");
- break;
- case 2: /* Fallthrough */
- default:
- fprintf(stderr, "Unknown error (result is inconsistent)\n");
- }
-
- printf("%s\n", result);
-}
-
-static void
-print_str_result(int64_t ret, char *result)
-{
- switch (ret) {
- case 0:
- break;
- default:
- fprintf(stderr, "Unknown error\n");
- }
-
- printf("%s\n", result);
-}
-
static int64_t
compose_exec(args_t *args)
{
@@ -277,7 +244,8 @@ compose_exec(args_t *args)
int64_t ret;
ret = nissy_compose(args->cube, args->cube_perm, result);
- print_cube_result(ret, result);
+ if (ret == 0)
+ printf("%s\n", result);
return ret;
}
@@ -289,7 +257,8 @@ inverse_exec(args_t *args)
int64_t ret;
ret = nissy_inverse(args->cube, result);
- print_cube_result(ret, result);
+ if (ret == 0)
+ printf("%s\n", result);
return ret;
}
@@ -301,7 +270,8 @@ applymoves_exec(args_t *args)
int64_t ret;
ret = nissy_applymoves(args->cube, args->str_moves, result);
- print_cube_result(ret, result);
+ if (ret == 0)
+ printf("%s\n", result);
return ret;
}
@@ -313,7 +283,8 @@ applytrans_exec(args_t *args)
int64_t ret;
ret = nissy_applytrans(args->cube, args->str_trans, result);
- print_cube_result(ret, result);
+ if (ret == 0)
+ printf("%s\n", result);
return ret;
}
@@ -325,7 +296,8 @@ frommoves_exec(args_t *args)
int64_t ret;
ret = nissy_frommoves(args->str_moves, result);
- print_cube_result(ret, result);
+ if (ret == 0)
+ printf("%s\n", result);
return ret;
}
@@ -338,7 +310,8 @@ convert_exec(args_t *args)
ret = nissy_convert(
args->str_format_in, args->str_format_out, args->str_cube, result);
- print_str_result(ret, result);
+ if (ret == 0)
+ printf("%s\n", result);
return ret;
}
@@ -354,7 +327,8 @@ randomcube_exec(args_t *args)
cp = rand64();
co = rand64();
ret = nissy_getcube(ep, eo, cp, co, "fix", result);
- print_str_result(ret, result);
+ if (ret == 0)
+ printf("%s\n", result);
return ret;
}
@@ -526,7 +500,7 @@ help_exec(args_t *args)
printf("Available commands and usage:\n\n");
for (i = 0; commands[i].name != NULL; i++)
printf("%-15s%s\n", commands[i].name, commands[i].syn);
- printf("\nUse 'help COMMAND' for more information.\n");
+ printf("\nUse 'help -command COMMAND' for more information.\n");
} else {
for (i = 0; commands[i].name != NULL; i++)
if (!strcmp(args->str_command, commands[i].name))
diff --git a/src/core/cube.h b/src/core/cube.h
@@ -66,16 +66,10 @@ isconsistent(cube_t cube)
return true;
inconsistent_ep:
- LOG("Inconsistent EP\n");
- return false;
inconsistent_cp:
- LOG("Inconsistent CP\n");
- return false;
inconsistent_eo:
- LOG("Inconsistent EO\n");
- return false;
inconsistent_co:
- LOG("Inconsistent CO\n");
+ /* We used to do more logging here, hence the 4 different labels */
return false;
}
@@ -115,13 +109,9 @@ issolvable(cube_t cube)
return true;
issolvable_parity:
- LOG("EP and CP parities are different\n");
- return false;
issolvable_eo:
- LOG("Odd number of flipped edges\n");
- return false;
issolvable_co:
- LOG("Sum of corner orientation is not multiple of 3\n");
+ /* We used to do more logging here, hence the 3 different labels */
return false;
}
diff --git a/src/core/io_cube.h b/src/core/io_cube.h
@@ -1,3 +1,6 @@
+STATIC cube_t readcube(const char *, const char *);
+STATIC int writecube(const char *, cube_t, char *);
+STATIC void log_available_formats(void);
STATIC uint8_t readco(const char *);
STATIC uint8_t readcp(const char *);
STATIC uint8_t readeo(const char *);
@@ -29,7 +32,7 @@ STATIC struct {
{ .name = "NONE", .read = NULL, .write = NULL },
};
-cube_t
+STATIC cube_t
readcube(const char *format, const char *buf)
{
int i;
@@ -38,11 +41,12 @@ readcube(const char *format, const char *buf)
if (!strcmp(format, ioformat[i].name))
return ioformat[i].read(buf);
- LOG("Cannot read cube in the given format\n");
+ LOG("Cannot read cube: unknown format '%s'\n", format);
+ log_available_formats();
return ZERO_CUBE;
}
-void
+STATIC int
writecube(const char *format, cube_t cube, char *buf)
{
char *errormsg;
@@ -58,18 +62,30 @@ writecube(const char *format, cube_t cube, char *buf)
for (i = 0; ioformat[i].write != NULL; i++) {
if (!strcmp(format, ioformat[i].name)) {
ioformat[i].write(cube, buf);
- return;
+ return 0;
}
}
+ LOG("Cannot write cube: unknown format '%s'\n", format);
+ log_available_formats();
errormsg = "ERROR: format";
writecube_error:
- LOG("writecube error, see stdout for details\n");
len = strlen(errormsg);
memcpy(buf, errormsg, len);
- buf[len] = '\n';
- buf[len+1] = '\0';
+ buf[len] = '\0';
+ return 1;
+}
+
+STATIC void
+log_available_formats(void)
+{
+ int i;
+
+ LOG("Available formats: ");
+ for (i = 0; ioformat[i].read != NULL; i++)
+ LOG("'%s' ", ioformat[i].name);
+ LOG("\n");
}
STATIC uint8_t
@@ -133,14 +149,34 @@ readcube_B32(const char *buf)
for (i = 0; i < 8; i++) {
c[i] = b32tocorner(buf[i]);
- DBG_ASSERT(c[i] < 255, ZERO_CUBE,
- "Error reading B32 corner %d (char %d)\n", i, i);
+ if (c[i] == UINT8_ERROR) {
+ LOG("Error reading B32 corner %d ", i);
+ if (buf[i] == 0) {
+ LOG("(string terminated early)\n");
+ } else {
+ LOG("(char '%c')\n", buf[i]);
+ }
+ return ZERO_CUBE;
+ }
+ }
+
+ if (buf[8] != '=') {
+ LOG("Error reading B32 separator: a single '=' "
+ "must be used to separate edges and corners\n");
+ return ZERO_CUBE;
}
for (i = 0; i < 12; i++) {
e[i] = b32toedge(buf[i+9]);
- DBG_ASSERT(e[i] < 255, ZERO_CUBE,
- "Error reading B32 edge %d (char %d)\n", i, i+9);
+ if (e[i] == UINT8_ERROR) {
+ LOG("Error reading B32 edge %d ", i);
+ if (buf[i+9] == 0) {
+ LOG("(string terminated early)\n");
+ } else {
+ LOG("(char '%c')\n", buf[i+9]);
+ }
+ return ZERO_CUBE;
+ }
}
return cubefromarray(c, e);
@@ -314,7 +350,7 @@ STATIC uint8_t
b32toedge(char c)
{
if (!((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'f')))
- return 255;
+ return UINT8_ERROR;
return c <= 'Z' ? (uint8_t)(c - 'A') : (uint8_t)(c - 'a') + 26;
}
@@ -324,7 +360,7 @@ b32tocorner(char c) {
uint8_t val;
if (!((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'f')))
- return 255;
+ return UINT8_ERROR;
val = c <= 'Z' ? (uint8_t)(c - 'A') : (uint8_t)(c - 'a') + 26;
diff --git a/src/core/io_trans.h b/src/core/io_trans.h
@@ -10,7 +10,6 @@ readtrans(const char *buf)
if (!strncmp(buf, transstr[t], 11))
return t;
- LOG("readtrans error\n");
return UINT8_ERROR;
}
diff --git a/src/core/moves.h b/src/core/moves.h
@@ -18,7 +18,7 @@ STATIC cube_t applymoves(cube_t, const char *);
STATIC cube_t frommoves(const char *);
#define FOREACH_READMOVE(ARG_BUF, ARG_MOVE, ARG_C, ARG_MAX, \
- LABEL_ERROR, ARG_ACTION) \
+ RET_ERROR, ARG_ACTION) \
const char *VAR_B; \
uint8_t VAR_MOVE_NOMOD, VAR_MOD; \
for (VAR_B = ARG_BUF, ARG_C = 0; *VAR_B != '\0'; VAR_B++, ARG_C++) { \
@@ -26,8 +26,10 @@ STATIC cube_t frommoves(const char *);
VAR_B++; \
if (*VAR_B == '\0' || ARG_C == ARG_MAX) \
break; \
- if ((VAR_MOVE_NOMOD = readmove(*VAR_B)) == UINT8_ERROR) \
- goto LABEL_ERROR; \
+ if ((VAR_MOVE_NOMOD = readmove(*VAR_B)) == UINT8_ERROR) { \
+ LOG("Error: unknown move '%c'\n", *VAR_B); \
+ return RET_ERROR; \
+ } \
if ((VAR_MOD = readmodifier(*(VAR_B+1))) != 0) \
VAR_B++; \
ARG_MOVE = VAR_MOVE_NOMOD + VAR_MOD; \
@@ -124,7 +126,7 @@ move(cube_t c, uint8_t m)
case MOVE_B3:
return MOVE(B3, c);
default:
- LOG("move error, unknown move\n");
+ LOG("move error: unknown move %" PRIu8 "\n", m);
return ZERO_CUBE;
}
}
@@ -171,7 +173,7 @@ premove(cube_t c, uint8_t m)
case MOVE_B3:
return PREMOVE(B, c);
default:
- LOG("move error, unknown move\n");
+ LOG("premove error: unknown move %" PRIu8 "\n", m);
return ZERO_CUBE;
}
}
@@ -222,15 +224,11 @@ readmoves(const char *buf, int max, uint8_t *ret)
uint8_t m;
int c;
- FOREACH_READMOVE(buf, m, c, max, readmoves_error,
+ FOREACH_READMOVE(buf, m, c, max, -1,
ret[c] = m;
)
return c;
-
-readmoves_error:
- LOG("readmoves error\n");
- return -1;
}
STATIC cube_t
@@ -242,15 +240,11 @@ applymoves(cube_t cube, const char *buf)
DBG_ASSERT(isconsistent(cube), ZERO_CUBE,
"move error: inconsistent cube\n");
- FOREACH_READMOVE(buf, m, c, -1, applymoves_error,
+ FOREACH_READMOVE(buf, m, c, -1, ZERO_CUBE,
cube = move(cube, m);
)
return cube;
-
-applymoves_error:
- LOG("applymoves error\n");
- return ZERO_CUBE;
}
STATIC cube_t
diff --git a/src/core/transform.h b/src/core/transform.h
@@ -229,7 +229,7 @@ transform_corners(cube_t c, uint8_t t)
case TRANS_BLm:
return TRANS_CORNERS_MIRRORED(BLm, c);
default:
- LOG("transform error, unknown transformation %" PRIu8 "\n", t);
+ LOG("transform error: unknown transformation %" PRIu8 "\n", t);
return ZERO_CUBE;
}
}
@@ -335,7 +335,6 @@ transform(cube_t c, uint8_t t)
case TRANS_BLm:
return TRANS_MIRRORED(BLm, c);
default:
- LOG("transform error, unknown transformation %" PRIu8 "\n", t);
return ZERO_CUBE;
}
}
@@ -350,5 +349,8 @@ applytrans(cube_t cube, const char *buf)
t = readtrans(buf);
+ if (t == UINT8_ERROR)
+ LOG("Unknown transformation '%s'\n", buf);
+
return transform(cube, t);
}
diff --git a/src/nissy.c b/src/nissy.c
@@ -110,13 +110,19 @@ 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 2;
+ return 8;
}
writecube("B32", cube, result);
- return issolvable(cube) ? 0 : 1;
+ if (!issolvable(cube)) {
+ LOG("Warning: resulting cube is not solvable\n");
+ return 9;
+ }
+
+ return 0;
}
int64_t
@@ -129,7 +135,19 @@ nissy_compose(
cube_t c, p, res;
c = readcube("B32", cube);
+
+ if (!isconsistent(c)) {
+ LOG("Error in nissy_compose: given cube is invalid\n");
+ return 1;
+ }
+
p = readcube("B32", permutation);
+
+ if (!isconsistent(p)) {
+ LOG("Error in nissy_compose: given permutation is invalid\n");
+ return 2;
+ }
+
res = compose(c, p);
return write_result(res, result);
@@ -144,6 +162,12 @@ nissy_inverse(
cube_t c, res;
c = readcube("B32", cube);
+
+ if (iserror(c)) {
+ LOG("Error in nissy_inverse: given cube is invalid\n");
+ return 1;
+ }
+
res = inverse(c);
return write_result(res, result);
@@ -159,6 +183,12 @@ nissy_applymoves(
cube_t c, res;
c = readcube("B32", cube);
+
+ if (!isconsistent(c)) {
+ LOG("Error in nissy_applymoves: given cube is invalid\n");
+ return 1;
+ }
+
res = applymoves(c, moves);
return write_result(res, result);
@@ -174,6 +204,12 @@ nissy_applytrans(
cube_t c, res;
c = readcube("B32", cube);
+
+ if (!isconsistent(c)) {
+ LOG("Error in nissy_applytrans: given cube is invalid\n");
+ return 1;
+ }
+
res = applytrans(c, transformation);
return write_result(res, result);
@@ -189,6 +225,11 @@ nissy_frommoves(
res = applymoves(SOLVED_CUBE, moves);
+ if (!isconsistent(res)) {
+ /* Moves must be invalid */
+ return 1;
+ }
+
return write_result(res, result);
}
@@ -200,12 +241,20 @@ nissy_convert(
char *result
)
{
+ int ret;
cube_t c;
c = readcube(format_in, cube_string);
- writecube(format_out, c, result);
- return isconsistent(c) ? 0 : 2;
+ if (iserror(c))
+ return 1;
+
+ ret = writecube(format_out, c, result);
+
+ if (ret != 0)
+ return 2;
+
+ return isconsistent(c) ? 0 : 3;
}
int64_t
@@ -387,8 +436,10 @@ nissy_solve(
return -1;
} else {
return THREADS > 1 ?
- solve_h48_multithread(c, minmoves, maxmoves, maxsolutions, data, solutions) :
- solve_h48(c, minmoves, maxmoves, maxsolutions, data, solutions);
+ solve_h48_multithread(c, minmoves,
+ maxmoves, maxsolutions, data, solutions) :
+ solve_h48(c, minmoves,
+ maxmoves, maxsolutions, data, solutions);
}
} else if (!strcmp(solver, "simple")) {
return solve_simple(
diff --git a/src/nissy.h b/src/nissy.h
@@ -1,10 +1,17 @@
/*
-If you include this file, you should also include the following:
+This is libnissy (temporarily also known as h48), a Rubik's cube library.
-inttypes, stdarg, stdbool, string
+If you include this file, you should also use the following includes:
-All the functions below return 0 in case of success and a positive
-number in case of error, unless otherwise specified.
+#include <inttypes>
+#include <stdarg>
+#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.
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
@@ -18,40 +25,85 @@ A transformation must be given in the format
for example 'rotation UF' or 'mirrored BL'.
*/
-/* Apply the secod argument as a permutation on the first argument */
+/*
+Apply the secod argument as a permutation on the first argument.
+
+Return values:
+ 0 Valid result
+ 1 The given cube is invalid
+ 2 The given permutation is invalid
+ 9 The resulting cube is not solvable
+*/
int64_t nissy_compose(
const char cube[static 22],
const char permutation[static 22],
char result[static 22]
);
-/* Compute the inverse of the given cube */
+/*
+Compute the inverse of the given cube.
+
+Return values:
+ 0 Valid result
+ 1 The given cube is invalid
+ 9 The resulting cube is not solvable
+*/
int64_t nissy_inverse(
const char cube[static 22],
char result[static 22]
);
-/* Apply the given sequence of moves on the given cube */
+/*
+Apply the given sequence of moves on the given cube.
+
+Return values:
+ 0 Valid result
+ 1 The given cube is invalid
+ 8 The given moves are invalid
+ 9 The resulting cube is not solvable
+*/
int64_t nissy_applymoves(
const char cube[static 22],
const char *moves,
char result[static 22]
);
-/* Apply the single given transformation to the given cube */
+/*
+Apply the single given transformation to the given cube.
+
+Return values:
+ 0 Valid result
+ 1 The given cube is invalid
+ 8 The given transformation is invalid
+ 9 The resulting cube is not solvable
+*/
int64_t nissy_applytrans(
const char cube[static 22],
const char *transformation,
char result[static 22]
);
-/* Return the cube obtained by applying the given moves to the solved cube */
+/*
+Apply the given moves to the solved cube.
+
+Return values:
+ 0 Valid result
+ 1 The given moves are invalid
+*/
int64_t nissy_frommoves(
const char *moves,
char result[static 22]
);
-/* Convert the given cube between the two given formats */
+/*
+Convert the given cube between the two given formats.
+
+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
+*/
int64_t nissy_convert(
const char *format_in,
const char *format_out,
@@ -70,40 +122,48 @@ int64_t nissy_getcube(
);
/*
-Returns the size of the data generated by nissy_gendata, when called with
-the same parameters, or -1 in case of error. The returned value can be
-slightly larger than the actual table size.
+Compute the size of the data generated by nissy_gendata, when called with
+the same parameters, or -1 in case of error.
+
+Return values:
+ -1 Error
+ >=0 The size of the table, in bytes
*/
int64_t nissy_datasize(
const char *solver
);
-/* Returns the number of bytes written, or -1 in case of error */
+/*
+Compute the data for the given solver and store it in generated_data.
+
+Return values:
+ -1 Error
+ >=0 The size of the table, in bytes
+*/
int64_t nissy_gendata(
const char *solver,
void *generated_data
);
-/* Temporarily added to test h48 intermediate tables */
-int64_t nissy_derivedata(
- const char *options,
- const void *fulltable,
- void *generated_data
-);
-
-/* Returns 0 on positive check, 1 on error */
-int64_t nissy_checkdata(
- const char *solver,
- const void *data
-);
+/*
+Print information on a data table via the provided callback writer.
-/* Print information on a data table via the provided callback writer */
+Return values:
+ 0 No error
+ 1 The given data could not be read correctly
+*/
int64_t nissy_datainfo(
const void *table,
void (*write)(const char *, ...)
);
-/* Returns the number of solutions found, or -1 in case of error */
+/*
+Solve the given cube using the given solver and options
+
+Return values:
+ -1 Error
+ >=0 The number of solutions found
+*/
int64_t nissy_solve(
const char cube[static 22],
const char *solver,
@@ -116,5 +176,7 @@ int64_t nissy_solve(
char *solutions
);
-/* Set a global logger function used by this library. */
+/*
+Set a global logger function used by this library.
+*/
void nissy_setlogger(void (*logger_function)(const char *, ...));
diff --git a/tools/nissy_extra.h b/tools/nissy_extra.h
@@ -10,3 +10,4 @@ for testing purposes only.
size_t gendata_h48_derive(uint8_t, const void *, void *);
int parse_h48_solver(const char *, uint8_t [static 1], uint8_t [static 1]);
+int64_t nissy_derivedata(const char *, const void *, void *);